串(String)是由零个或多个字符组成的有限序列,又名叫字符串。
一般记为 s =“a1a2a3……an”(n>=0)
字符串的存储结构
字符串一般用i=0来保存字符串的长度,从i=1开始保存字符串,末尾处没有’\0’。
字符串的存储结构与线性表相同,也分顺序存储结构和链式存储结构。
字符串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。
按照预定义的大小,为每个定义的字符串变量分配一个固定长度的存储区,一般用定长数组来定义。
与线性表相似,既然是固定长度的存储区,就存在一个空间分配不灵活的问题,那么会考虑用链式存储结构。
字符串通常还是会直接定义一个足够长度的存储区来存储的。
字符串就是一种更加特殊的线性结构。它表现在:1.使用char类型的数组来存储。2.面向字符串的操作与一般的顺序表不同,比如元素的插入、删除、确定位置等,一般的顺序表定义的操作都是1次处理一个元素,而字符串的操作往往是处理若干个字符。
因为字符串操作的这些特殊性,所以C语言中专门在string.h头文件中定义了许多关于字符串的操作,其中比较重要的是:字符串输出函数puts、字符串输入函数gets、字符串连接函数strcat、字符串拷贝函数strcpy、字符串比较函数strcmp、测字符串长度函数strlen等。
定义一个字符串,不是通过定义一个很长的数组来实现,而是通过动态分配内存的方法来实现,这样的话,需要一个变量记录动态数组的长度,有了这个长度,我们就不需要像C语言那样通过在结尾加添'\0'来判断字符串是否结束了。
<span style="font-size:18px;">//字符串 typedef struct String { char* data; int size; }String; //分配字符串 bool assignStr(String *pT,char *chars) { int i = 0; //求字符串的长度 while(chars[i] != '\0') ++i; //如果是空串 if(0 == i) { pT->data = NULL; pT->size = 0; } else { pT->size = i; pT->data = (char*)malloc(sizeof(char) * pT->size); if(NULL ==pT->data ) return false; else { for(int j = 0; j < i;++j) pT->data[j] = chars[j]; } } return true; } //销毁字符串 void clearStr(String *pS) { free(pS->data); pS->data = NULL; pS->size = 0; } //求字符串长度 int strLength(String *pS) { return pS->size; } //字符串拷贝;将pS拷贝到pT bool strCpy(String *pT,String *pS) { if(strLength(pT)<strLength(pS)) { pT->data=(char*)realloc(pT->data,sizeof(char)*pS->size); pT->size=pS->size; } if(NULL==pT->data) return false; else { for(int i=0;i<strLength(pT);i++) { pT->data[i]=pS->data[i]; } pT->size=pS->size; return true; } } //判断是否为空 bool is_empty(String *pS) { if(NULL == pS->data && 0 == pS->size) { printf("empty"); return true; } else return false; } //字符串比较,前>后:1;前=后:0;前<后:-1 int strCmp(String *pT,String *pS) { int i=strLength(pT); int j=strLength(pS); int k; i<j?k=i:k=j; //当i=j时,k=j for(int n=0;n<k;n++) { if(pT->data[n]>pS->data[n]) return 1; else if(pT->data[n]<pS->data[n]) { return -1; } } //如果程序能完整执行完for循环,说明两个字符串的前k个字符相等 //剩下只要比较它俩谁长就可以了 if(i<j) { return -1; } else if(i>j) { return 1; } else return 0; } //将第二个字符串连接到第一个后面 void strCat(String *pT,String *pS) { int i = strLength(pT); int j = strLength(pS); pT->data = (char*)realloc(pT->data,sizeof(char) * (i+j)); for(int m = i,n = 0 ; m < (i+j); ++m,++n) pT->data[m] = pS->data[n]; pT->size = i + j; } //从指定的位置返回指定长度的子串 bool getSubString(String *pS,int pos,int len,String *pSubString) { //判断输入的位置和长度是否合法 if(pos < 0 || len <= 0 || len+pos > strLength(pS)) return false; for(int i = pos,j = 0; i<pos+len;++i,++j) { pSubString->data[j] = pS->data[i]; } pSubString->size = len; return true; } //在指定位置后插入字符串;在pS中插入pT,插入位置为pos bool insertStr(String *pT,String *pS,int pos) { int i = strLength(pT); int j = strLength(pS); if(pos < 0 || pos > j) return false; pS->data = (char*)realloc(pS->data,sizeof(char) * (i+j)); pS->size = i+j; if(NULL == pS->data) return false; //将需要插入的字符串的长度空出来,然后将pS的每个元素依次后移 for(int m = i+j ; m > pos; --m) pS->data[m] = pS->data[m-i]; //将需要插入的字符串的值插入到pS中 for(int n = pos,l = 0; n < i+pos;++n,++l) pS->data[n] = pT->data[l]; return true; } //删除指定位置后面的若干个字符 bool deleteStr(String *pS,int pos,int len) { int j = strLength(pS); if(pos < 0 || pos > j || len + pos > j) return false; for(int i = pos; i < j-len;++i) pS->data[i] = pS->data[i+len]; pS->size -= len; return false; } //检索:源字符串的某个位置以后是否有目标字符串,有则返回位置,无则返回-1 //在pS中是否有pT int index(String *pT,String *pS,int pos) { int m=strlen(pS); int n=strlen(pT); //如果比较位置大于等于源字符串的长度,返回-1 if(pos>=m) return -1; int i=pos,j=0; //当两个字符都没有访问到最后一个元素时,继续 while(i+n<m&&j<n) { //如果从某一个位置起二者相等,继续比较 if(pS->data[i]==pT->data[j]) { i++; j++; } //否则源字符串从第一个字符匹配的下一个位置开始继续 else { i=i-j+1;//i和j是同步增长的 j=0; } //如果目标串已经找完,则找到 if(j==strLength(pT)) { return i-strLength(pT); } } //没有找到,返回-1 return -1; } //替换 void replace(String *pT,String *pS,String *pNew) { //使用已经定义的操作完成:查找、删除、插入 int m = strLength(pT); int n = strLength(pNew); int i = 0; do{ i = index(pT,pS,i); if(i != -1) { deleteStr(pS,i,m); //删除pS中i位置之后的m个字符 insertStr(pNew,pS,i); //在pS中插入pNew,插入位置为i i += n; } } while(i != -1); } //打印字符串,调试时使用 void printStr(String *pT) { printf("word: "); // 不能使用下面这句,因为pT->data之前可能曾经很长 // printf("%s",pT->data); for(int i = 0 ; i < strLength(pT);++i) printf("%c",pT->data[i]); printf("\n"); } </span>