基本概念
1.三字母词
三字母词就是几个字符的序列,合起来表示另一个字符。
1 | ??( [ ??< { ??= # |
1 | printf("Delete file (are you really sure??): " ); |
输出
1 | Delete file (are you really sure ]: |
2. typedef
1 | typedef char *ptr_to_char; |
这个声明把标识符ptr_to_char作为指向字符的指针类型的新名字。你可以像使用任何预定义名字一样在下面的声明中使用这个新名字。例如:
1 | ptr_to_char a; |
好处:
- 使用typedef声明类型可以减少使声明变得又臭又长的危险,尤其是那些复杂的声明 。
- 而且,如果你以后觉得应该修改程序所使用的一些数据的类型时,修改一个typedef声明比修改程序中与这种类型有关的所有变量(和函数)的所有声明要容易得多。
3. goto语句
1 | goto 语句标签; |
例如:
4.零为假,非零为真。
5.间接访问操作符
通过一个指针访问它所指向的地址的过程称为间接访问
这个用于执行间接访问的操作符是单目操作符 * 。
6. NULL指针
NULL指针——表示不指向任何东西。
要使一个指针变量为NULL,你可以给它赋一个零值。
为了测试一个指针变量是否为NULL,你可以将它与零值进行比较。
1 | int *p=0; |
7. stdarg宏
可变参数列表是通过宏来实现的,这些宏定义于stdarg.h头文件,它是标准库的一部分。
这个头文件声明了一个类型va_list和三个宏——va_start、va_arg和va_end。
1 | /* |
char和short类型的实参被转换为int类型,float类型的实参被转换为double类型。所以你在va_arg中使用后面这些类型时应该小心。
8. *ap+6相当于表达式array[2]+6。
9. 2[array]等于*( array + 2 ),array为数组。
1 | int a[3]={1,2,3}; |
这个诡异技巧之所以可行,缘于C实现下标的方法。对编译器来说,这两种形式并无差别。但是,你绝不应该编写2[array],因为它会大大影响程序的可读性。
下标绝不会比指针更有效率,但指针有时会比下标更有效率。
10.字符数组初始化
1 | char message[] = { 'H', 'e', 'l', 'l', 'o', 0 }; |
方式二
1 | char message[] = "Hello";//双引号括起来 |
1 | char message1[] = "Hello";//初始化一个字符数组的元素 |
11.二维数组
1 | int matrix[3][10]; |
1.
1 | matrix + 1 //2 |
2.
1 | int vector[10], *vp = vector;//合法 |
- 原因:mp的初始化是不正确的,因为matrix并不是一个指向整型的指针,而是一个指向整型数组的指针。
12. 字符串的长度并不包括NUL字节。
string.h包含了使用字符串函数所需的原型和声明。
1 | if( strlen( x ) >= strlen( y ) ) ... |
- 上面的两者并不相等!
库函数strlen的原型如下:
1 | size_t strlen( char const *string ); |
1 | /* |
13.复制字符串
用于复制字符串的函数是strcpy,它的原型如下所示:
1 | char *strcpy( char *dst, char const *src ); |
1 | char message[] = "Original message"; |
14.连接字符串
要想把一个字符串添加(连接)到另一个字符串的后面,你可以使用strcat函数。它的原型如下:
1 | char *strcat( char *dst, char const *src ); |
和前面一样,程序员必须保证目标字符数组剩余的空间足以保存整个源字符串。
返回值
strcpy和strcat都返回它们第1个参数的一份拷贝,就是一个指向目标字符数组的指针。由于它们返回这种类型的值,所以你可以嵌套地调用这些函数,如下面的例子所示:
1 | strcat( strcpy( dst, a ), b ); |
15.字符串比较
库函数strcmp用于比较两个字符串,它的原型如下:
1 | int strcmp( char const *s1, char const *s2 ); |
16.长度受限的字符串函数
1.strncpy把源字符串的字符复制到目标数组。然而,它总是正好向dst写入len个字符。如果strlen( src )的值小于len,dst数组就用额外的NUL字节填充到len长度。如果strlen( src )的值大于或等于len,那么只有len个字符被复制到dst中。注意!它的结果将不会以NUL字节结尾 。
使用了一个不是以NUL字节结尾的字符序列,会发生什么情况呢?
strlen函数将无法知道NUL字节是没有的,所以它将继续进行查找,一个字符接一个字符,直到它发现一个NUL字节为止。或许它找了几百个字符才找到,而strlen函数的这个返回值从本质上说是一个随机数。或者,如果函数试图访问系统分配给这个程序以外的内存范围,程序就会崩溃。
这个问题只有当你使用strncpy函数创建字符串,然后或者对它们使用str开头的库函数,或者在printf中使用%s格式码打印它们时才会发生。
例如,考虑下面这个代码段:
如果name的内容可以容纳于buffer中,最后那个赋值语句没有任何效果。但是,如果name太长,这条赋值语句可以保证buffer中的字符串是以NUL结尾的。以后对这个数组使用strlen或其他不受限制的字符串函数将能够正确工作。
2.strncat也是一个长度受限的函数,但它和strncpy存在不同之外。它从src中最多复制len个字符到目标数组的后面。但是,strncat总是在结果字符串后面添加一个NUL字节,而且它不会像strncpy那样对目标数组用NUL字节进行填充。注意目标数组中原先的字符串并没有算在strncat的长度中。strncat最多向目标数组复制len个字符(再加一个结尾的NUL字节),它才不管目标参数除去原先存在的字符串之后留下的空间够不够。
3.strncmp也用于比较两个字符串,但它最多比较len个字节。如果两个字符串在第len个字符之前存在不相等的字符,这个函数就像strcmp一样停止比较,返回结果。如果两个字符串的前len个字符相等,函数就返回零。
17.查找一个字符
在一个字符串中查找一个特定字符最容易的方法是使用strchr和strrchr函数,它们的原型如下所示:
1.strchr在字符串str中查找字符ch第1次出现的位置,找到后函数返回一个指向该位置的指针。如果该字符并不存在于字符串中,函数就返回一个NULL指针。
2.trrchr的功能和strchr基本一致,只是它所返回的是一个指向字符串中该字符最后一次出现的位置.
3.注意这里大小写是有区别的。
18.查找任何几个字符
strpbrk是个更为常见的函数。它并不是查找某个特定的字符,而是查找任何一组字符第1次在字符串中出现的位置。它的原型如下:
1 | char *strpbrk( char const *str, char const *group ); |
这个函数返回一个指向str中第1个匹配group中任何一个字符的字符位置。如果未找到匹配,函数返回一个NULL指针。
19.查找一个子串
为了在字符串中查找一个子串,我们可以使用strstr函数,它的原型如下:
1 | char *strstr( char const *s1, char const *s2 ); |
这个函数在s1中查找整个s2第1次出现的起始位置,并返回一个指向该位置的指针。如果s2并没有完整地出现在s1的任何地方,函数将返回一个NULL指针。如果第2个参数是一个空字符串,函数就返回s1。
标准库中并不存在strstr或strpbrk函数。不过,如果你需要它们,它们是很容易实现的。程序9.2显示了一种实现strstr的方法。这个技巧同样也可以用于实现strpbrk。
1 | /* |
- 实测:标准库里是有这两个函数的不用自己写.
20.查找一个字符串前缀
strspn和strcspn函数用于在字符串的起始位置对字符计数。它们的原型如下所示:
1 | size_t strspn( char const *str, char const *group ); |
group字符串指定一个或多个字符。strspn返回str起始部分匹配group中任意字符的字符数。例如,如果group包含了空格、制表符等空白字符,那么这个函数将返回str起始部分空白字符的数目。str的下一个字符就是它的第1个非空白字符。
strcspn函数和strspn函数正好相反,它对str字符串起始部分中不与group中任何字符匹配的字符进行计数。返回起始到匹配的字符数.
如果你使用“ \n\r\f\t\v”作为group参数,这个函数将返回第1个参数字符串起始部分所有非空白字符的值。
1 | char q[]="hello world"; |
1 | char q[]="hello world"; |
21.查找标记
这个任务正是strtok函数所实现的功能。它从字符串中隔离各个单独的称为标记(token)的部分,并丢弃分隔符。它的原型如下:
1 | char *strtok( char *str, char const *sep ); |
strtok找到str的下一个标记,并将其用NUL结尾,然后返回一个指向这个标记的指针。
当strtok函数执行任务时,它将会修改它所处理的字符串。如果源字符串不能被修改,那就复制一份,将这份拷贝传递给strtok函数。
如果字符串内不存在更多的标记,strtok函数就返回一个NULL指针。
1 | /* |
由于strtok函数保存它所处理的函数的局部状态信息,所以你不能用它同时解析两个字符串。因此,如果for循环的循环体内调用了一个在内部调用strtok函数的函数,不能嵌套使用.