当前位置: 首页 > 科技观察

C语言如何实现字符串的动态扩展

时间:2023-03-13 00:14:17 科技观察

众所周知,C++中的string使用起来更加方便。string在C++中的源码实现可以看我的文章:源码分析C++中string的实现最近工作使用C语言,但是苦于缺乏高效的string实现,字符strings的拼接和切割是比较麻烦,而且每个字符串都需要申请内存,内存的申请和释放也容易出现bug。如何高效实现一个无需处理内存问题,可动态扩展的字符串拼接裁剪毛呢?一个好的字符串应该具备以下功能?创建一个字符串删除字符串的尾部追加字符串的头部插入字符串从尾部删除N个字符从头部删除N个字符裁剪字符串获取字符串的长度获取完整的字符串让我们来看看每个实现功能:首先定义一个字符串句柄,相当于C++中的实例structc_string;typedefstructc_stringc_string_t;内部字符串的实现如下://字符串的初始内存大小staticconstsize_tc_string_min_size=32;structc_string{char*str;//字符串指针size_tallocated;//分配的内存大小size_tlen;//字符串的实际长度};创建字符串: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->allocated=c_string_min_size;cs->len=0;returncs;}销毁字符串:voidc_string_destroy(c_string_t*cs){if(cs==NULL)return;free(cs->str);free(cs);}如何内部扩展:staticvoidc_string_ensure_space(c_string_t*cs,size_tadd_len){if(cs==NULL||add_len==0)return;if(cs->分配>=cs->len+add_len+1)return;while(cs->allocatedlen+add_len+1){cs->allocated<<=1;//每次扩容2倍大小if(cs->allocated==0){//向左移动到最后可能会变成0,因为allocated是无符号类型,减一就会变成UINT_MAXcs->allocated--;}}cs->str=realloc(cs->str,cs->allocated);}在末尾附加一个字符串:voidc_string_append_str(c_string_t*cs,constchar*str,size_tlen){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';}在末尾追加字符:voidc_string_append_char(c_string_t*cs,charc){if(cs==NULL)return;c_string_ensure_space(CS,1);cs->str[cs->len]=c;cs->len++;cs->str[cs->len]='\0';}最后追加一个整数:voidc_string_append_int(c_string_t*cs,intval){charstr[12];if(cs==NULL)return;snprintf(str,sizeof(str),"%d",val);//整数转字符串c_string_append_str(cs,str,0);}在头部插入一个字符串:voidc_string_front_str(c_string_t*cs,constchar*str,size_tlen){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';}在头部插入字符:voidc_string_front_char(c_string_t*cs,charc){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';}在头部插入一个整数:voidc_string_front_int(c_string_t*cs,intval){charstr[12];if(cs==NULL)return;snprintf(str,sizeof(str),"%d",val);c_string_front_str(cs,str,0);}空字符串:voidc_string_clear(c_string_t*cs){if(cs==NULL)return;c_string_truncate(cs,0);}裁剪字符串:voidc_string_truncate(c_string_t*cs,size_tlen){if(cs==NULL||len>=cs->len)return;cs->lenlen=len;cs->str[cs->len]='\0';}删除头N字符:voidc_string_drop_begin(c_string_t*cs,size_tlen){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个字符:voidc_string_drop_end(c_string_t*cs,size_tlen){if(cs==NULL||len==0)return;if(len>=cs->len){c_string_clear(cs);return;}cs->len-=len;cs->str[cs->len]='\0';}获取字符串的长度:size_tc_string_len(constc_string_t*cs){if(cs==NULL)return0;returncs->len;}返回字符串指针,使用内存:constchar*c_string_peek(constc_string_t*cs){if(cs==NULL)returnNULL;returncs->str;}重新分配一块内存存放字符串返回:char*c_string_dump(constc_string_t*cs,size_t*len){char*out;if(cs==NULL)returnNULL;if(len!=NULL)*len=cs->len;out=malloc(cs->len+1);memcpy(out,cs->str,cs->len+1);returnout;}测试代码如下:intmain(){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);return0;}输出:12345789123459123459123完整代码如下:头文件:#includestructc_string;typedefstructc_stringc_string_t;c_string_t*c_string_create(void);voidc_string_string_vodestroy(voidc_string_string_vodestroy)(c_string_t*cs,constchar*str,size_tlen);voidc_string_append_char(c_string_t*cs,charc);voidc_string_append_int(c_string_t*cs,intval);voidc_string_front_str(c_string_t*cs,constchar*str,size_tlen);voidc_string_front_char(c_string_t*cs,charc);voidc_string_front_int(c_string_t*cs,intval);voidc_string_clear(c_string_t*cs);voidc_string_truncate(c_string_t*cs,size_tlen);voidc_string_drop_begin(c_string_t*cs,size_tlen);voidc_string_drop_end(c_string_t*cs,size_tlen);size_tc_string_string_t(concstcs));constchar*c_string_peek(constc_string_t*cs);char*c_string_dump(constc_string_t*cs,size_t*len);源文件:#include#include#include#include#includestaticconstsize_tc_string_min_size=32;structc_string{char*str;size_talloced;size_tlen;};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;returncs;}voidc_string_destroy(c_string_t*cs){if(cs==NULL)return;free(cs->str);free(cs);}staticvoidc_string_ensure_space(c_string_t*cs,size_tadd_len){if(cs==NULL||add_len==0)return;if(cs->alloced>=cs->len+add_len+1)return;while(cs->allocedlen+add_len+1){cs->alloced<<=1;if(cs->alloced==0){cs->alloced--;}}cs->str=realloc(cs->str,cs->alloced);}voidc_string_append_str(c_string_t*cs,constchar*str,size_tlen){if(cs==NULL||str==NULL||*str=='\0')返回;如果(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';}voidc_string_append_char(c_string_t*cs,charc){if(cs==NULL)return;c_string_ensure_space(cs,1);cs->str[cs->len]=c;cs->len++;cs->str[cs->len]='\0';}voidc_string_append_int(c_string_t*cs,intval){charstr[12];if(cs==NULL)return;snprintf(str,sizeof(str),"%d",val);c_string_append_str(cs,str,0);}voidc_string_front_str(c_string_t*cs,constchar*str,size_tlen){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';}voidc_string_front_char(c_string_t*cs,charc){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';}voidc_string_front_int(c_string_t*cs,intval){charstr[12];如果(cs==NULL)返回;snprintf(str,sizeof(str),"%d",val);c_string_front_str(cs,str,0);}voidc_string_clear(c_string_t*cs){if(cs==NULL)返回;c_string_truncate(cs,0);}voidc_string_truncate(c_string_t*cs,size_tlen){if(cs==NULL||len>=cs->len)return;cs->lenlen=len;cs->str[cs->len]='\0';}voidc_string_drop_begin(c_string_t*cs,size_tlen){if(cs==NULL||len==0)return;if(len>=cs->len){c_string_clear(cs);return;}cs->len-=len;/*+1tomovetheNULL.*/memmove(cs->str,cs->str+len,cs->len+1);}voidc_string_drop_end(c_string_t*cs,size_tlen){if(cs==NULL||len==0)return;if(len>=cs->len){c_string_clear(cs);return;}cs->len-=len;cs->str[cs->len]='\0';}size_tc_string_len(constc_string_t*cs){if(cs==NULL)return0;returncs->len;}constchar*c_string_peek(constc_string_t*cs){if(cs==NULL)returnNULL;returncs->str;}char*c_string_dump(constc_string_t*cs,size_t*len){char*out;if(cs==NULL)returnNULL;if(len!=NULL)*len=cs->len;out=malloc(cs->len+1);memcpy(out,cs->str,cs->len+1);returnout;}