C/C++提供了众多的字符串处理函数。它们声明在<string.h>中。如下所示:
strlen(s) | 返回s的长度,不包括字符串结束符null |
strcmp(s1,s2) | 比较两个字符串s1和s2是否相同,若s1与s2相等,返回0;若s1大于s2,返回正数;若s1小于s2,则返回负数 |
strcat(s1,s2) | 将字符串s2链接到s1后,并返回s1 |
strcpy(s1,s2) | 将s2复制给s1,并返回s1 |
strncat(s1,s2,n) | 将s2的前n个字符连接到s1后面,并返回s1 |
strncpy(s1, s2, n) | 将s2的前n个字符复制给s1,并返回s1 |
传递给这些标准库函数历程的指针必须具有非零值,并且指向以null结束的字符数组中的第一个元素。其中一些标准库函数会修改传递给它的字符串,这些函数将假定它们所修改的字符串具有足够大的空间接受本函数新生成的字符,程序员必须确保目标字符串必须足够大。
strlen
strlen计算字符数组的字符数,以‘\0'为结束标志,计算不为‘\0'的数组元素个数。
int strlen(const char *str) { assert(str != NULL); int len=0; while ((*str++) != ’\0') len++; return len; }
strcmp
strcmp函数是C/C++中基本的函数,它对两个字符串进行比较,然后返回比较结果,函数形式如下:
intstrcmp(constchar*str1,constchar*str2);
其中str1和str2可以是字符串常量或者字符串变量,返回值为整形。返回结果如下规定:
①str1小于str2,返回负值或者-1(VC返回-1);②str1等于str2,返回0;
③str1大于str2,返回正值或者1(VC返回1);
strcmp函数实际上是对字符的ASCII码进行比较,实现原理如下:首先比较两个串的第一个字符,若不相等,则停止比较并得出两个ASCII码大小比较的结果;如果相等就接着比较第二个字符然后第三个字符等等。无论两个字符串是什么样,strcmp函数最多比较到其中一个字符串遇到结束符'/0'为止,就能得出结果。strcmp算法的可以有多种,不过我觉的可以把这么多算法分为两种,一种是利用减法运算判断结果,另一种是利用比较运算(==)得出结果。代码如下
1 int strcmp(const char *str1, const char *str2) { 2 assert(str1 != NULL && str2 != NULL); 3 int ret = 0; 4 while (!(ret = *(unsigned int*)str1 - *(unsigned int*)str2) && *str1) { 5 str1++; 6 str2++; 7 } 8 9 if (ret < 0) { 10 return -1; 11 } else if (ret > 0) { 12 return 1; 13 } else { 14 return 0; 15 } 16 }
①使用*(unsignedchar*)str1而不是用*str1。这是因为传入的参数为有符号数,有符号字符值的范围是-128~127,无符号字符值的范围是0~255,而字符串的ASCII没有负值,若不转化为无符号数这回在减法实现时出现错误。例如str1的值为1,str2的值为255。
作为无符号数计算时ret=-254,结果为负值,正确作为有符号数计算时ret=2,结果为正值,错误
②While循环中ret=*(unsignedchar*)str1-*(unsignedchar*)str2)&&*str1,最后与上str1也可以换成str2,因为前面已经做了相减,无论哪个先为‘\0’都会退出。因为最后与上str1是为了判断str1是否结束,即是否为‘\0’。
③这个函数没有判断参数为NULL时的情况,所以当传入NULL时程序会崩溃。网上看别人说商业化代码都会在调用strcmp前先判断是否为NULL,所以可以不用判断NULL;我在VC6上测试string.h中的strcmp(NULL,NULL),程序也会崩溃。这里可以根据实际情况来决定。
参考资料: 1. http://wenku.baidu.com/view/bf87f429b4daa58da0114aaf.html
strcat与strcpy
strcat(dst, src)把src所指字符串添加到dest结尾处(覆盖dest结尾处的“\0")并添加'\0'。
strcpy(dest, src)把从src地址开始且含有null结束符的字符串复制到以dest开始的地址空间。
传递给标准库函数strcat与strcpy的第一个实参数组必须有足够大的空间存放新生成的字符串。
自定义函数实现strcat()函数的功能:
char *strcat(char *strDest, const char *strSrc) { assert(strDest != NULL && strSrc != NULL); char *address = strDest; while (*strDest) { strDest++; } while (*strDest++ = *strSrc++); return address }
自定义函数实现strcpy()函数的功能:
1 char* strcpy(char *strDest, const char* strSrc) { 2 assert(strDest != NULL && strSrc != NULL); 3 char* address = strDest; 4 while ((*strDest++ = *strSrc++) != ‘\0'); 5 return address; 6 }
strncat
char* strncat(char *dst, const char* src, size_t n);
把src的前n个字符添加到dst的后面,并在最后添加null。如果src的长度小于n,那么就复制src的内容到null字符,而不用管剩下的不够n部分。
代码如下:
char * strncat(char*dst, const char* src, size_t n){ if (n != 0) { char *d = dst; const char *s = src; while (*d != 0) d++; do { if ((*d = *s++) == 0) break; d++; } while (--n != 0); *d = 0; } return (dst); }
参考资料: 1.http://www.cplusplus.com/reference/cstring/strncat/
2. http://www.opensource.apple.com/source/Libc/Libc-167/gen.subproj/i386.subproj/strncat.c
strncpy
char * strncpy(char *dst, const char *src, size_t n);
把s2的前n个字符串拷贝到dst中。如果src的长度小于n,那么dst中会在拷贝完src正文内容后用'\0'填补直到长度为n。
如果src的长度比n大,那么dst的后面不会用'\0'补齐。所以不应该假设函数执行后的dst是以'\0'结尾的字符串。
代码如下:
char * strncat(char* dst, const char* src, size_t n) {
assert(dst != NULL && src != NULL); char* address = dst; while (n > 0 && *src != '\0') { *dst++ = *src++; --n; } while (n > 0) { *dst++ = 0; --n; } return s; }
参考资料: 1. http://www.opensource.apple.com/source/Libc/Libc-262/ppc/gen/strncpy.c
2. http://www.cplusplus.com/reference/cstring/strncpy/