字符串就是一种更加特殊的线性结构。
它表现在:1.使用char类型的数组来存储。2.面向字符串的操作与一般的顺序表不同,比如元素的插入、删除、确定位置等,一般的顺序表定义的操作都是1次处理一个元素,而字符串的操作往往是处理若干个字符。
因为字符串操作的这些特殊性,所以C语言中专门在string.h头文件中定义了许多关于字符串的操作,其中比较重要的是:字符串输出函数
puts、字符串输入函数gets、字符串连接函数strcat、字符串拷贝函数strcpy、字符串比较函数strcmp、测字符串长度函数strlen等。
定义一个字符串,不是通过定义一个很长的数组来实现,而是通过动态分配内存的方法来实现,这样的话,需要一个变量记录动态数组的长度,有了这个长度,我们就不需要像C语言那样通过在结尾加添‘\0‘来判断字符串是否结束了。
//字符串 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"); }
时间: 2024-10-08 00:49:19