第11章 字符串和字符串函数
——《C Primer Plus》的搬运工,仅记录自己觉得重要的内容,方便以后参考
11.1表示字符串和字符串I/O
puts()函数只显示字符串,而且自动在显示的字符串末尾加\n
11.1.1在程序中定义字符串
- 字符串常量,“串”,编译器自动补\0,存储在内存中
字符串常量属于静态存储类别,字符串只会被存储一次,直到整个程序的声明周期
%p-printf,打印字符串首字符的地址>> *'串'
char arr[40]="串" == char arr[40]={‘字符’,‘字符’,'\0'};//必须加\0,自动变为串
未被赋值的元素,自动补0,实际上是补\0
arr=&arr[0];
*arr='首字符';
char* pt="串";== char arr[40]="串" ; ==char arr[40]={‘字符’,‘字符’,'\0'};
- 自动计算大小
char arr[]="串"
; - 这种方式不允许
const char arr[] ; arr = "hello";
- 这种方式是允许的
const char* arr; arr = "hello world";
数组与指针
- 数组形式
编译器将数组名识别为数组首元素地址的别名,但是数组名为常量,不能更改 - 字符形式
#define MSG "hello world";
char arr[]=MSG;
char* pt=MSG;
(%p MSG) == (%p pt) != (%p arr);//因为arr为MSG的拷贝,所以地址不一样
字符串数组
- 指向字符串的指针数组
这里不同于二维数组的表现形式(定义方式)
const char* arr1[N]={"串1","串2",...,"串N"};
printf("%s",arr1[i]);//0<=i<N
- char类型数组的数组
const char arr2[M][40]={"串1","串2",...,"串M"};
printf("%s",arr2[i]);//0<=i<M
- 二者区别
arr1数组是一个内含5个指针的数组,共占N·(1个指针类型所占字节数)个字节
arr2是一个内含5个数组的数组,每个数组含有40个char类型的值,共M·40个字节arr1中的指针指向初始化时所用的字符串字面量的位置,这些字面量(字符串常量)被存储在静态内存中
arr2中的数组存储的是字符串常量的副本,所以每个字符串都存储了两次,与上面介绍的字符串的解释一样
arr1数组的指针元素所指向的字符串不必存储在连续的内存中
11.1.2指针和字符串
char* pt="串";
*"hello world "==h;//说明"表示的是一个地址"
11.2.2不幸的gets()函数
gets()用于读取一行字符(串),知道遇到换行符,然后丢弃换行符,存储其余字符,并在末尾自动添加一个空字符 ‘\0’
puts()函数用于显示字符,遇到空字符 '\0’停止输出,并在末尾自动添加换行符 ‘\n’
缺点:无法检查数组时候装得下输入行。gets()只知道数组的开始处,不知道数组中有多少个元素
gets()函数遇到文件结尾返回空指针NULL或0
11.2.2gets()的替代品
C11中可以用gets_s() 函数代替gets() 函数
fgets()函数和fputs()函数
fgets() 函数通过第2个参数限制读入的字符数来解决字符数溢出的问题。
fgets() -> \n\0
fgets()函数,当时输入字符比定义的要长时,只放\0,没有\n
fputs()函数不再末尾加\n
fputs()函数遇到文件结尾返回NULL指针,或为0
如果不想修改字符常量,那么就最好不要用指针。
gets_s()函数
11.2.4scanf()函数
scanf()函数从第一个非空白符作为字符串的的开始
用%s转换说明,下一个空白字符(空行、空格、制表符、换行符)作为字符串的结束标志,输入的结果字符不包含空白字符
%10s可以限定读入的次数
scanf()函数返回一个整数值,该值等于成功读取的项数或EOF(表示文件的结尾),即可以一次性读入多个字符
11.3字符串输出
11.3.1puts()函数
puts(字符串的地址);
输出字符串直到\0位置,即遇到空字符停止,并为每行末尾添加一个\n
字符串常量被认为该字符串的地址
11.3.2fputs()函数
fputs()函数的第二个参数指明要写入数据的文件,或stdout表示打印在显示器上
fputs()函数不会在末尾自动添加\n
11.3.3printf()函数
printf()函数不会自动在字符串的末尾添加一个\n
11.4自定义输入输出函数
*string++;
等价于
*string;
string++;
11.5字符串函数
11.5.2strcat()函数
用于拼接字符串,接受两个字符串作为参数,把第2个字符串的备份附加在第一个字符串的结尾,并把拼接后形成的新字符串作为第一个字符串,第二个字符串不变
char arr[100] = "hello";
const char* arr2 = "world";
strcat(arr, arr2);
//错误示范
char* arr = "hello";
const char* arr2 = "world";
strcat(arr, arr2);
strcat()函数返回char*类型,返回第一个拼接后形成的新字符串的地址
strcat()函数第一个数组必须有足够的空间
覆盖第一个字符串的\0
11.5.3strncat()函数
strncat()函数,中的第三个参数指定了最大添加字符数
- 时刻注意末尾\0的问题
- 不会拷贝第二个字符中空字符和其后的字符,但是对新拼接的字符后面自动加上一个空字符\0
11.5.4strcmp()函数
用于字符串比较
strcmp(str1,str2);
直接比较字符串的时候,比较的是两个字符串的地址是否相同,不能直接比较
strcmp()函数可以比较不同大小的字符串(存储在不同大小数组中),逐次比较每个字符
参数相同返回0,不相同返回非零值,即小则返回复数,大则返回正数
strncmp()函数中第三个参数指定要比较的字符个数
11.5.5strcpy()函数和strncpy()函数
strcpy()接受两个字符串指针作为参数
可以把指向源字符串的第二个指针声明为指针、数组名、或字符串常量
把指向源字符串副本的第一个指针参数指向一个数据对象(数组)
char arr1[M][N];
char arr2[N];
gets(arr2);//scanf("%s",arr2);
strcpy(arr[i],arr2);//拷贝字符串
//==//
char arr3[N];
strcpy(arr3,"hello world");//N要大于都等于strlen("hello world")+'\0'
//错误示范
char* str;
strcpy(str,"hello world");
- strcpy()函数的返回类型为char*,返回的是第一个参数的地址,即一个字符的地址。拷贝之后两个指针指向的地址不一样
- 第一个参数不必指向数组的开始,可用于拷贝数组的一部分
- strcpy()函数把源字符串中的空字符也拷贝进去,
- 函数返回值为char*
strcncpy()函数中的第3个参数指明要拷贝的最大字符数
注意部分拷贝的情况可能没有\0,需要自己添加
函数返回值为char*
11.5.6sprintf()函数
把数据写入字符串,而不是打印在显示器中
第一个参数是目标字符串的地址,其余参数与printf()相同
本质上与printf()函数相同,只是将输出转移到数组(字符串中)
char formal[M];
sprintf(formal, "%s,%s\n", "hello", "world");//\n也会存储在formal中
11.5.7其他字符串函数
- strchr
char* strchr(const char* s,int c);
如果s字符串中包含c字符,该函数返回s字符串首位置的指针(末尾的空字符也是字符串的一部分,所以在查找范围内);如果未找到,该函数返回NULL
- strrchr
char* strrchr(const char* s,int c);
该函数返回s字符串中c字符的最后一次出现的位置,末尾的空字符也是字符串的一部分,在查找范围内,未找到则返回NULL
- strpbrk
char* strpbrk(const char* s1,const char* s2);
如果s1字符中包含s2字符串中的任意字符,该函数返回指向s2,如果在s1字符串中未找到任何s2字符串中的字符,返回NULL
- strstr
char* strstr(const char* s1,const char* s2);
该函数返回指向s1字符串中s2字符串出现的首位置,如果没找到则返回NULL
11.6字符串示例:字符串排序
11.6.1排序指针而非字符串
排序指针而非排序原来的数组
11.6.2选择排序算法
见其他算法
11.7 cytype.h字符函数和字符串
7.2.2ctype.h系列的字符函数
isalnum();//字母或数字
isalpha();//字母
isblank();//标准的空白字符(空格、水平制表符、换行符)
iscntrl();//控制字符
isdigit();//数字
isgraph();//除空格外的任意可打印字符
islower();//小写字母
isprint();//可打印字符
ispunct();//标点符号
isspace();//空白字符(空格、换行符、换页符、回车符、垂直制表符、水平制表符)
isupper();//大写字符
isxdigit();//十六进制数字符
tolower();//如果参数是大写字符,返回小写字符,否则不动
toupper();//如果参数是小写字符,返回大写字符,否则不动
11.8命令行参数
int main(int argc,char* argv[]);
argc表示命令行中的字符串数量,系统用空格表示一个字符串的结束和下一个字符串的开始
把命令行字符串存储在内存中,并把每个字符串的地址存储在指针数组中
argv存储数组的地址,argv是一个指向指针的指针(相当于字符串数组),一把argv[0]表示可执行程序的名称
等价于
int main(int argc,char** argv);
11.9把字符串转换为数字
-
atio()
将字母数字转换为整数
参数不是数字则返回0 -
atof()
将字符串转换为double类型的值 -
atol()
函数把字符串转换成long类型的值
其他智能转换函数,书P366
——所有代码仅表示关键步骤,可能无法正常运行