第九章字符串、字符和字节
这一块在初学的时候很容易被大家忽视,但字符串作为一种重要的数据类型,没有在C中显式的说明。这样看起来C++定义了string的数据类型实在是带来了不少福音。
如果想用C玩OJ或者数据结构与算法的话,这一章需要仔细阅读,因为这是你仅有能用到的字符串处理的标准库。
总结:
C的字符串标准库使用需要声明"string.h"。
strlen用于计算一个字符串的长度,它的返回值是一个无符号的整数。后面会说可能存在的问题。
strcpy函数把一个字符串从一个位置赋值到另一个位置。
strcat函数把一个字符串的一份拷贝添加到另一个字符串的后面。
strcmp函数对两个字符串进行词典序的比较。它的返回值提示第一个字符串是大于、小于还是等于。
strncpy/strncat/strncmp对应不受限制的版本,它们可以完美判断是否操作溢出。另外还要加一个长度参数。
strncpy长度指定了多少个字符被写入到目标字符数组中。
strncat长度制定了从源字符串赋值的最大数目,结尾包含‘\0‘。
strcmp长度制定了比较的数目。
关于查找的字符串:
strchr查找一个字符串中的某个字符第一次出现的位置。
strrchr同上,但是返回最后一次出现的位置。
strpbrk在一个字符串查找一个指定字符集中任意字符(不是子串!是任意一个字符!)第一次出现的位置。
strstr是查找子串第一次出现的位置。
在这里我不想涉及到高级查找函数,功能太诡异。
strerror把一个错误代码作为它的参数,返回一个指向字符串的指针,该字符串用于描述这个错误。
关于测试和转换字符的函数:
用它们的意义在于,代码的移植性可以大大提高。
toupper把一个小写字母换成大写字母。
tolower把一个大写字母换成小写字母。
iscntrl检查是不是一个控制字符。
...很多这样的。。。它们会返回一个整型值,表示真或假。
关于内存操作:
memxxx函数提供类似字符串的操作,但是遇到NUL时候不会停止操作。同时会包括一个长度参数。
memmove/memcpy赋值指定长度字节数
memcmp比较
memchr查找一个特定值
memset将一个序列初始化为一个特定的值。
警告:
1、应该使用有符号数的表达式使用strlen函数。
因为strlen在定义的时候返回值为size_t,这是一个无符号数,所以:
if(strlen(x) >= strlen(y))...
if(strlen(x) - strlen(y) >=0)...
这两个是可能不相同的,前者会像预想的那样正常工作,但是后者不能表达一个负数值。
最好将strlen返回值强制转换为int 。
2、在表达式中混有有符号数和无符号数。
同上。
3、使用strcpy函数把一个长字符串赋值到一个较短的数组中,导致溢出。
如果太长,strcpy不会考虑溢出问题,它的操作结果将是覆盖后面的内存空间。
4、使用strcat函数把一个字符串添加到一个数组中,导致数组溢出。
同上。
5、把strcmp函数的返回值1和-1进行比较,或者当做布尔值比较。
这是一种不好的风格,最好的的方法是与0进行比较。
if(strcmp(a,b))这样就是结果很可能a,b是相等的,但是返回一个假。
6、使用并非以NUL字符截尾的字符序列作为以上函数的传递值。
比如strcmp、strlen这些函数都是在找NUL作为终止的条件,如果没有个NUL,返回值将会不确定。
7、使用strncpy函数产生不易NUL字节结尾的字符串。
在使用strncpy函数后,如果复制的长度超过剩余长度,虽然不会溢出,但是它的结果不会以NUL结尾。
8、把strncpy函数和strxxx族函数混用。
呵呵的警告。
编程提示:
1、不要试图自己编写功能相同的函数来取代库函数。
库函数有时候用汇编来写的,从而有最大速度。如果想改进效率,还是看看你的其他代码吧。
2、使用字符分类和转换函数可以提高函数的移植性。