C语言实现动态扩容的string
众所周知,C中的string使用比较方便。关于C中的string源码实现
最近工作中使用C语言,但又苦于没有高效的字符串实现,字符串的拼接和裁剪都比较麻烦,而且每个字符串都需要申请内存,内存的申请和释放也很容易出bug,怎么高效的实现一个不需要处理内存问题并且可以动态扩容进行拼接和裁剪的string呢?
一个好的string应该有以下功能?创建字符串删除字符串尾部追加字符串头部插入字符串从尾部删除N个字符从头部删除N个字符裁剪字符串获取字符串长度获取完整字符串
下面,我们来看看各个功能的实现。
首先定义一个string的句柄,相当于C中的实例。structcstring;typedefstructcstringcstringt;
在内部string的实现如下:string的初始内存大小staticconstsizetcstringminsize32;
structcstring{charstr;字符串指针sizetalloced;已分配的内存大小sizetlen;字符串的实际长度};
创建字符串:cstringtcstringcreate(void){cstringtcs;
cscalloc(1,sizeof(cs));csstrmalloc(cstringminsize);csstr;初始分配内存大小是32,之后每次以2倍大小扩容csallocedcstringminsize;cslen0;
returncs;}
销毁字符串:voidcstringdestroy(cstringtcs){if(csNULL)return;free(csstr);free(cs);}
内部如何扩容呢:staticvoidcstringensurespace(cstringtcs,sizetaddlen){if(csNULLaddlen0)return;
if(csallocedcslenaddlen1)return;
while(csallocedcslenaddlen1){csalloced1;每次以2倍大小扩容if(csalloced0){左移到最后可能会变为0,由于alloced是无符号型,减一则会变成UINTMAXcsalloced;}}csstrrealloc(csstr,csalloced);}
在尾部追加字符串:voidcstringappendstr(cstringtcs,constcharstr,sizetlen){if(csNULLstrNULLstr)return;
if(len0)lenstrlen(str);
cstringensurespace(cs,len);确保内部有足够的空间存储字符串memmove(csstrcslen,str,len);cslenlen;csstr〔cslen〕;}
在尾部追加字符:voidcstringappendchar(cstringtcs,charc){if(csNULL)return;cstringensurespace(cs,1);csstr〔cslen〕c;cslen;csstr〔cslen〕;}
在尾部追加整数:voidcstringappendint(cstringtcs,intval){charstr〔12〕;
if(csNULL)return;
snprintf(str,sizeof(str),d,val);整数转为字符串cstringappendstr(cs,str,0);}
在头部插入字符串:voidcstringfrontstr(cstringtcs,constcharstr,sizetlen){if(csNULLstrNULLstr)return;
if(len0)lenstrlen(str);
cstringensurespace(cs,len);memmove(csstrlen,csstr,cslen);memmove(csstr,str,len);cslenlen;csstr〔cslen〕;}
在头部插入字符:voidcstringfrontchar(cstringtcs,charc){if(csNULL)return;cstringensurespace(cs,1);memmove(csstr1,csstr,cslen);csstr〔0〕c;cslen;csstr〔cslen〕;}
在头部插入整数:voidcstringfrontint(cstringtcs,intval){charstr〔12〕;
if(csNULL)return;
snprintf(str,sizeof(str),d,val);cstringfrontstr(cs,str,0);}
清空字符串:voidcstringclear(cstringtcs){if(csNULL)return;cstringtruncate(cs,0);}
裁剪字符串:voidcstringtruncate(cstringtcs,sizetlen){if(csNULLlencslen)return;
cslenlen;csstr〔cslen〕;}
删除头部的N个字符:voidcstringdropbegin(cstringtcs,sizetlen){if(csNULLlen0)return;
if(lencslen){cstringclear(cs);return;}
cslenlen;memmove(csstr,csstrlen,cslen1);}
删除尾部的N个字符:voidcstringdropend(cstringtcs,sizetlen){if(csNULLlen0)return;
if(lencslen){cstringclear(cs);return;}cslenlen;csstr〔cslen〕;}
获取字符串的长度:sizetcstringlen(constcstringtcs){if(csNULL)return0;returncslen;}
返回字符串指针,使用的是内部的内存:constcharcstringpeek(constcstringtcs){if(csNULL)returnNULL;returncsstr;}
重新分配一块内存存储字符串返回:charcstringdump(constcstringtcs,sizetlen){charout;
if(csNULL)returnNULL;
if(len!NULL)lencslen;outmalloc(cslen1);memcpy(out,csstr,cslen1);returnout;}
测试代码如下:intmain(){cstringtcscstringcreate();cstringappendstr(cs,123,0);cstringappendchar(cs,4);cstringappendint(cs,5);printf(s,cstringpeek(cs));cstringfrontstr(cs,789,0);printf(s,cstringpeek(cs));cstringdropbegin(cs,2);printf(s,cstringpeek(cs));cstringdropend(cs,2);printf(s,cstringpeek(cs));cstringdestroy(cs);return0;}
输出:
12345hr78912345hr912345hr9123hr完整代码如下:头文件:includestddef。h
structcstring;typedefstructcstringcstringt;
cstringtcstringcreate(void);
voidcstringdestroy(cstringtcs);
voidcstringappendstr(cstringtcs,constcharstr,sizetlen);
voidcstringappendchar(cstringtcs,charc);
voidcstringappendint(cstringtcs,intval);
voidcstringfrontstr(cstringtcs,constcharstr,sizetlen);
voidcstringfrontchar(cstringtcs,charc);
voidcstringfrontint(cstringtcs,intval);
voidcstringclear(cstringtcs);
voidcstringtruncate(cstringtcs,sizetlen);
voidcstringdropbegin(cstringtcs,sizetlen);
voidcstringdropend(cstringtcs,sizetlen);
sizetcstringlen(constcstringtcs);
constcharcstringpeek(constcstringtcs);
charcstringdump(constcstringtcs,sizetlen);
源文件:includectype。hincludestdbool。hincludestdlib。hincludestdio。hincludestring。h
staticconstsizetcstringminsize32;
structcstring{charstr;sizetalloced;sizetlen;};
cstringtcstringcreate(void){cstringtcs;
cscalloc(1,sizeof(cs));csstrmalloc(cstringminsize);csstr;csallocedcstringminsize;cslen0;
returncs;}
voidcstringdestroy(cstringtcs){if(csNULL)return;free(csstr);free(cs);}
staticvoidcstringensurespace(cstringtcs,sizetaddlen){if(csNULLaddlen0)return;
if(csallocedcslenaddlen1)return;
while(csallocedcslenaddlen1){csalloced1;if(csalloced0){csalloced;}}csstrrealloc(csstr,csalloced);}
voidcstringappendstr(cstringtcs,constcharstr,sizetlen){if(csNULLstrNULLstr)return;
if(len0)lenstrlen(str);
cstringensurespace(cs,len);memmove(csstrcslen,str,len);cslenlen;csstr〔cslen〕;}
voidcstringappendchar(cstringtcs,charc){if(csNULL)return;cstringensurespace(cs,1);csstr〔cslen〕c;cslen;csstr〔cslen〕;}
voidcstringappendint(cstringtcs,intval){charstr〔12〕;
if(csNULL)return;
snprintf(str,sizeof(str),d,val);cstringappendstr(cs,str,0);}
voidcstringfrontstr(cstringtcs,constcharstr,sizetlen){if(csNULLstrNULLstr)return;
if(len0)lenstrlen(str);
cstringensurespace(cs,len);memmove(csstrlen,csstr,cslen);memmove(csstr,str,len);cslenlen;csstr〔cslen〕;}
voidcstringfrontchar(cstringtcs,charc){if(csNULL)return;cstringensurespace(cs,1);memmove(csstr1,csstr,cslen);csstr〔0〕c;cslen;csstr〔cslen〕;}
voidcstringfrontint(cstringtcs,intval){charstr〔12〕;
if(csNULL)return;
snprintf(str,sizeof(str),d,val);cstringfrontstr(cs,str,0);}
voidcstringclear(cstringtcs){if(csNULL)return;cstringtruncate(cs,0);}
voidcstringtruncate(cstringtcs,sizetlen){if(csNULLlencslen)return;
cslenlen;csstr〔cslen〕;}
voidcstringdropbegin(cstringtcs,sizetlen){if(csNULLlen0)return;
if(lencslen){cstringclear(cs);return;}
cslenlen;1tomovetheNULL。memmove(csstr,csstrlen,cslen1);}
voidcstringdropend(cstringtcs,sizetlen){if(csNULLlen0)return;
if(lencslen){cstringclear(cs);return;}cslenlen;csstr〔cslen〕;}
sizetcstringlen(constcstringtcs){if(csNULL)return0;returncslen;}
constcharcstringpeek(constcstringtcs){if(csNULL)returnNULL;returncsstr;}
charcstringdump(constcstringtcs,sizetlen){charout;
if(csNULL)returnNULL;
if(len!NULL)lencslen;outmalloc(cslen1);memcpy(out,csstr,cslen1);returnout;}
散文我是不是很伟大文王小鱼一hr喝过酒之后,我想到海子,想到许立志。我还想到一些英雄人物,邱少云,黄继光。我不止一次地想过他们,想过我活在这个世上,应该学习雷锋。记得我学会的第一首歌曲,我……
今天大寒,老话说大寒吃一鲜,一年病不沾,1鲜指什么?今天是二十四节气当中的最后一个节气大寒。大寒节气处在三九、四九时段,所以也是一年当中最寒冷的时候。而且今年大寒节气和春节除夕相近,1月20日是大寒,1月21日是除夕,1月22日……
旅行社大批出境游产品节后上新1月22日,菲律宾马尼拉中国城举行舞龙舞狮表演等活动,庆祝农历新年的到来供图新华社日前,文旅部宣布,自2月6日起,试点恢复全国旅行社及在线旅游企业经营中国公民赴有关国家出……
1胜21负!勇士甩锅22岁水货榜眼,联盟倒数第1出炉,库里躲北京时间4月6日,活塞108比123输给篮网,遭遇11连败。活塞16胜64负已经提前锁定联盟倒数第一的战绩。值得一提的是,活塞引进怀斯曼之后,战绩变得更加糟糕。怀斯曼为活塞打了……
天下泰山丨山村春意质朴绚丽来源:【中华泰山网】泰安日报社中华泰山网讯草长莺飞的时节,泰山樱桃园的樱桃花竞相绽放,密密匝匝开满枝头,随风摇曳生姿。游人漫步树下,赏繁花,话春意,构成了一幅春日特有的绚……
高盛预测年内铜价或创新高!紫金矿业股价或将重估?根据高盛最近预测显示,由于中国在世界上大量的收购铜,使得全世界现货铜库存量降到历史最低水平,如果收购将继续维持下去现货铜的供应将供不应求!铜价在近几个月内或将达到12000美元……
江西婺源广袤田野金色油菜花盛开美丽春景引客来图为婺源县溪头乡江岭景区,不少摄影爱好者在高处平台上拍摄远处的连片金色油菜花田和乡村美景。胡敦煌摄图为婺源县溪头乡江岭景区的金色油菜花盛开,与白墙黛瓦的村落相映成趣,构成……
硅谷扩大裁员!亚马逊将再减员9000人,25万华人精英或被动【阅读此文之前,麻烦您点击下关注,方便与您讨论分享,也能及时观看下一篇精彩文章。非常感谢您的关注!】近年来,许多公司遭遇了大量裁员风波。其中最主要原因是互联网行业的竞争日……
拼团系统开发模式玩法流程介绍拼团系统开发拼团系统是近几年兴起的一种商业模式,它不仅可以让消费者享受到低价商品,还能帮商家完成促销,从而在短时间内积累庞大的客户流量。下面就详细分析一下,拼团系统模式的玩法流……
中国国际时装周舞台上演新自由主义时装作品中国国际时装周舞台上演新自由主义时装作品中国青年报客户端3月26日,多名模特在位于北京前门的北京坊劝业场展示YOUGX的最新时装。刘占崑摄一名模特展示YOUG……
如何晒太阳才健康晒太阳对于人类的健康非常重要。然而,晒太阳并不是一件简单的事情,因为过度晒太阳可能会导致皮肤癌等疾病。那么,东亚人应该如何晒太阳才能健康呢?下面我将详细介绍。控制晒太阳的……
马来西亚国家介绍,有些可能与你知道的不一样!货运全球网,拥有160万外贸发货人,62万国际物流公司,帮助您做外贸!马来西亚是东南亚一个多元文化和多民族的国家,它位于新加坡和泰国之间,面积329,847平方公里。该国……