C语言如何实现动态扩容的String

本文转载自微信公众号「程序喵大人」,语言何作者程序喵大人 。实现转载本文请联系程序喵大人公众号。动态的

最近工作中使用C语言,扩容但又苦于没有高效的语言何字符串实现,字符串的实现拼接和裁剪都比较麻烦,而且每个字符串都需要申请内存,动态的内存的扩容申请和释放也很容易出bug,怎么高效的云服务器语言何实现一个不需要处理内存问题并且可以动态扩容进行拼接和裁剪的string呢?

一个好的string应该有以下功能? 创建字符串 删除字符串 尾部追加字符串 头部插入字符串 从尾部删除N个字符 从头部删除N个字符 裁剪字符串 获取字符串长度 获取完整字符串

下面来看看各个功能的实现:

首先定义一个string的句柄,相当于C++中的实现实例

struct c_string; typedef struct c_string c_string_t; 

在内部string的实现如下:

// string的初始内存大小 static const size_t c_string_min_size = 32; struct c_string {      char *str; // 字符串指针     size_t alloced; // 已分配的内存大小     size_t len; // 字符串的实际长度 }; 

创建字符串:

c_string_t *c_string_create(void) {      c_string_t *cs;     cs = calloc(1, sizeof(*cs));     cs->str = malloc(c_string_min_size);     *cs->str = \0;     // 初始分配内存大小是32,之后每次以2倍大小扩容     cs->alloced = c_string_min_size;      cs->len = 0;     return cs; } 

销毁字符串:

void c_string_destroy(c_string_t *cs) {      if (cs == NULL) return;     free(cs->str);     free(cs); } 

内部如何扩容呢:

static void c_string_ensure_space(c_string_t *cs,动态的亿华云计算 size_t add_len) {      if (cs == NULL || add_len == 0) return;     if (cs->alloced >= cs->len + add_len + 1) return;     while (cs->alloced < cs->len + add_len + 1) {          cs->alloced <<= 1; // 每次以2倍大小扩容         if (cs->alloced == 0) {              // 左移到最后可能会变为0,由于alloced是扩容无符号型,减一则会变成UINT_MAX             cs->alloced--;         }     }     cs->str = realloc(cs->str,语言何 cs->alloced); } 

在尾部追加字符串:

void c_string_append_str(c_string_t *cs, const char *str, size_t len) {      if (cs == NULL || str == NULL || *str == \0) return;     if (len == 0) len = strlen(str);     c_string_ensure_space(cs, len); // 确保内部有足够的空间存储字符串     memmove(cs->str + cs->len, str, len);     cs->len += len;     cs->str[cs->len] = \0; } 

在尾部追加字符:

void c_string_append_char(c_string_t *cs, char c) {      if (cs == NULL) return;     c_string_ensure_space(cs, 1);     cs->str[cs->len] = c;     cs->len++;     cs->str[cs->len] = \0; } 

在尾部追加整数:

void c_string_append_int(c_string_t *cs, int val) {      char str[12];     if (cs == NULL) return;     snprintf(str, sizeof(str), "%d", val); // 整数转为字符串     c_string_append_str(cs, str, 0); } 

在头部插入字符串:

void c_string_front_str(c_string_t *cs, const char *str, size_t len) {      if (cs == NULL || str == NULL || *str == \0) return;     if (len == 0) len = strlen(str);     c_string_ensure_space(cs, len);     memmove(cs->str + len, cs->str, cs->len);     memmove(cs->str, str, len);     cs->len += len;     cs->str[cs->len] = \0; } 

在头部插入字符:

void c_string_front_char(c_string_t *cs, char c) {      if (cs == NULL) return;     c_string_ensure_space(cs, 1);     memmove(cs->str + 1, cs->str, cs->len);     cs->str[0] = c;     cs->len++;     cs->str[cs->len] = \0; } 

在头部插入整数:

void c_string_front_int(c_string_t *cs, int val) {      char str[12];     if (cs == NULL) return;     snprintf(str, sizeof(str), "%d", val);     c_string_front_str(cs, str, 0); } 

清空字符串:

void c_string_clear(c_string_t *cs) {      if (cs == NULL) return;     c_string_truncate(cs, 0); } 

裁剪字符串:

void c_string_truncate(c_string_t *cs, size_t len) {      if (cs == NULL || len >= cs->len) return;     cs->len = len;     cs->str[cs->len] = \0; } 

删除头部的N个字符:

void c_string_drop_begin(c_string_t *cs, size_t len) {      if (cs == NULL || len == 0) return;     if (len >= cs->len) {          c_string_clear(cs);         return;     }     cs->len -= len;     memmove(cs->str, cs->str + len, cs->len + 1); } 

删除尾部的N个字符:

void c_string_drop_end(c_string_t *cs, size_t len) {      if (cs == NULL || len == 0) return;     if (len >= cs->len) {          c_string_clear(cs);         return;     }     cs->len -= len;     cs->str[cs->len] = \0; } 

获取字符串的长度:

size_t c_string_len(const c_string_t *cs) {      if (cs == NULL) return 0;     return cs->len; } 

返回字符串指针,使用的实现是内部的内存:

const char *c_string_peek(const c_string_t *cs) {      if (cs == NULL) return NULL;     return cs->str; } 

重新分配一块内存存储字符串返回:

char *c_string_dump(const c_string_t *cs, size_t *len) {      char *out;     if (cs == NULL) return NULL;     if (len != NULL) *len = cs->len;     out = malloc(cs->len + 1);     memcpy(out, cs->str, cs->len + 1);     return out; } 

测试代码如下:

int main() {      c_string_t *cs = c_string_create();     c_string_append_str(cs, "123", 0);     c_string_append_char(cs, 4);     c_string_append_int(cs, 5);     printf("%s \n", c_string_peek(cs));     c_string_front_str(cs, "789", 0);     printf("%s \n", c_string_peek(cs));     c_string_drop_begin(cs, 2);     printf("%s \n", c_string_peek(cs));     c_string_drop_end(cs, 2);     printf("%s \n", c_string_peek(cs));     c_string_destroy(cs);     return 0; } 

输出:

12345 78912345 912345 9123 

完整代码如下:头文件:

#include <stddef.h> struct c_string; typedef struct c_string c_string_t; c_string_t *c_string_create(void); void c_string_destroy(c_string_t *cs); void c_string_append_str(c_string_t *cs, const char *str, size_t len); void c_string_append_char(c_string_t *cs, char c); void c_string_append_int(c_string_t *cs, int val); void c_string_front_str(c_string_t *cs, const char *str, size_t len); void c_string_front_char(c_string_t *cs, char c); void c_string_front_int(c_string_t *cs, int val); void c_string_clear(c_string_t *cs); void c_string_truncate(c_string_t *cs, size_t len); void c_string_drop_begin(c_string_t *cs, size_t len); void c_string_drop_end(c_string_t *cs, size_t len); size_t c_string_len(const c_string_t *cs); const char *c_string_peek(const c_string_t *cs); char *c_string_dump(const c_string_t *cs, size_t *len); 

源文件:

#include <ctype.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> static const size_t c_string_min_size = 32; struct c_string {      char *str;     size_t alloced;     size_t len; }; c_string_t *c_string_create(void) {      c_string_t *cs;     cs = calloc(1, sizeof(*cs));     cs->str = malloc(c_string_min_size);     *cs->str = \0;     cs->alloced = c_string_min_size;     cs->len = 0;     return cs; } void c_string_destroy(c_string_t *cs) {      if (cs == NULL) return;     free(cs->str);     free(cs); } static void c_string_ensure_space(c_string_t *cs, size_t add_len) {      if (cs == NULL || add_len == 0) return;     if (cs->alloced >= cs->len + add_len + 1) return;     while (cs->alloced < cs->len + add_len + 1) {          cs->alloced <<= 1;         if (cs->alloced == 0) {              cs->alloced--;         }     }     cs->str = realloc(cs->str, cs->alloced); } void c_string_append_str(c_string_t *cs, const char *str, size_t len) {      if (cs == NULL || str == NULL || *str == \0) return;     if (len == 0) len = strlen(str);     c_string_ensure_space(cs, len);     memmove(cs->str + cs->len, str, len);     cs->len += len;     cs->str[cs->len] = \0; } void c_string_append_char(c_string_t *cs, char c) {      if (cs == NULL) return;     c_string_ensure_space(cs, 1);     cs->str[cs->len] = c;     cs->len++;     cs->str[cs->len] = \0; } void c_string_append_int(c_string_t *cs, int val) {      char str[12];     if (cs == NULL) return;     snprintf(str, sizeof(str), "%d", val);     c_string_append_str(cs, str, 0); } void c_string_front_str(c_string_t *cs, const char *str, size_t len) {      if (cs == NULL || str == NULL || *str == \0) return;     if (len == 0) len = strlen(str);     c_string_ensure_space(cs, len);     memmove(cs->str + len, cs->str, cs->len);     memmove(cs->str, str, len);     cs->len += len;     cs->str[cs->len] = \0; } void c_string_front_char(c_string_t *cs, char c) {      if (cs == NULL) return;     c_string_ensure_space(cs, 1);     memmove(cs->str + 1, cs->str, cs->len);     cs->str[0] = c;     cs->len++;     cs->str[cs->len] = \0; } void c_string_front_int(c_string_t *cs, int val) {      char str[12];     if (cs == NULL) return;     snprintf(str, sizeof(str), "%d", val);     c_string_front_str(cs, str, 0); } void c_string_clear(c_string_t *cs) {      if (cs == NULL) return;     c_string_truncate(cs, 0); } void c_string_truncate(c_string_t *cs, size_t len) {      if (cs == NULL || len >= cs->len) return;     cs->len = len;     cs->str[cs->len] = \0; } void c_string_drop_begin(c_string_t *cs, size_t len) {      if (cs == NULL || len == 0) return;     if (len >= cs->len) {          c_string_clear(cs);         return;     }     cs->len -= len;     /* +1 to move the NULL. */     memmove(cs->str, cs->str + len, cs->len + 1); } void c_string_drop_end(c_string_t *cs, size_t len) {      if (cs == NULL || len == 0) return;     if (len >= cs->len) {          c_string_clear(cs);         return;     }     cs->len -= len;     cs->str[cs->len] = \0; } size_t c_string_len(const c_string_t *cs) {      if (cs == NULL) return 0;     return cs->len; } const char *c_string_peek(const c_string_t *cs) {      if (cs == NULL) return NULL;     return cs->str; } char *c_string_dump(const c_string_t *cs, size_t *len) {      char *out;     if (cs == NULL) return NULL;     if (len != NULL) *len = cs->len;     out = malloc(cs->len + 1);     memcpy(out, cs->str, cs->len + 1);     return out; } 
滇ICP备2023000592号-31