c primer plus(第六版) - 11 字符串和字符串函数

c库提供大量的函数处理字符串。c++则提供string类。

初始化如上(可以有字符串常量、字符串数组、字符串指针),puts闪亮登场,puts只用于字符串输出,printf可以输出很多类型。

字符串常量属于静态存储类别。只被存储一次,在整个程序的生命期内存在。

问:还有哪些属于静态存储类别?存储在什么地方?特点是什么?

试一试:

printf(“%c, %c”, “space”, *“space”); // 第一个是输出e吗?第二个是输出s吗?

字符串数组也可以让编译器确定数组的大小,很方便:

char array[] = “space”;  // 这样就可以修改数组的值了

问题:

int n = 8;

char crumbs[n]; // 有效吗?C99之前无效,在之后是变长数组。P343

const char *pt1 = “Something is pointing at me.”; //

const char at1[] = “Something is pointing at me.”; // 几乎相同。这里有29个元素。

红框两个地址是一样的,说明字面量一样时,编译器只使用了一

putchar:打印一个字符

问:P346

char *p1 = “Klingon”;

p1[0] = ‘F’; // 可以吗?取决于编译器!如果可以,所有“Klingon”的地方都会改成F…

5. 字符串数组

指向字符串的指针数组和char类型数组的数组

LIM是行数5SLEN是列数40,指向字符串的指针数组,保留行数,省略列数

理解一下:

Mytalents内只包含5个指针,作者的系统,每个指针占8个字节,所以总占有40个字节。其中的字符串是字符串常量,存储在静态存储区。

Yourtalents好理解,5*40 = 200

问:yourtalents不也是字符串常量?不是,这里是字符串常量的副本,每个字符串都被存储了两次!为什么?P347

如果要改变字符串或为字符串输入预留空间,不要使用指向字符串常量的指针。

下面注意指针的地址和指针的值的区别。

例如:

  1. int变量的值,就是它存储的值,如100
  2. 同理指针变量的值,就是它存储的值,这个值是个地址。

// 不要指望计算机在读取字符串时顺便计算它的长度。如下有问题。

char *name;

scanf(“%s”, name);

读入字符串的函数:scanf()gets()fgets()  // getsfgets有什么区别?P350

scanf:只能读取一个单词。许多年前gets()用于读取一行,经常和puts配对使用

为什么叫“不幸的gets()?现在这个函数还在用吗?

有些编译器会提示:warning: this program uses gets(), which is unsafe

gets(words); //为什么会与这个警告?因为words只是数组首地址,它无法确定是否装的下输入的内容。如果输入的字符串过程,会导致缓冲区溢出,如果擦写掉的是其它程序的数据,会导致程序异常。

比如会出现 查询:Segmentation fault11。分段错误:试图访问未分配的内存。过去,有些通过系统编程,利用gets()插入和运行一些破坏系统安全的代码

为了兼容性,保持了一段时间的gets(),但后面不支持了。

fgets()gets_s()来代替gets()gets_s()更接近gets。但编译器不一定支持gets_s()

fgets()通过第2个参数限制字符数来解决溢出问题,专门用于文件输入,所以一般情况可能不太好用。问题:怎么使用?为什么不好用?

问:如果要读取换行符,用哪个函数?为什么?

答:用fgets,因为它只考虑第2个参数字符数即便是换行符,它也会读入

问:从字面上fgets用于文件读取,如果读取键盘输入,应该怎么写?

答:以stdin作为第3个参数作为输入。同理,fputs输出到显示器则使用stdout

注意:fgets换行符放在字符串的末尾。比如“apple pie\n\o

细微差别:puts增加换行符,而fputs则不会。

试一试:fgets读到文件尾不是EOF而是NULL

因为这里有while,所有再读取10个字符后,仍会继续读取后面10个字符。

注:

1)以后可以把fgetsc++getline比较看看。

2fgetsfputs都有各自的缓冲区。P353

问:为什么‘\0’可以用来作为字符串末尾字符?

答:因为其它字符的编码不可能是0

空字符是整数类型,而空指针是指针类型。两者容易混淆的原因是:它们都可以用数值0来表示,但两者是不同类型0(这)。空字符是一个字符,1个字节;空指针4个字节

C++新增的gets_s()(可选),在https://cplusplus.com/中却找不到!!

gets_s()fgets()的区别

3个不好理解,既然是可选,先略过。

个人总结:读单词就用scanf(),读字符串甚至含换行符的字符串用fgets()(注意参数3

scanf更像是“获取单词”函数,冷知识scanf可以只读取确定个数的字符,例如:

scanf(“%5s”, name); // 输入Fleebert Hupname的内容是Fleeb

3个输出puts()fputs()printf(),为什么需要这么多?为什么没有puts_s()?

puts():传入字符串地址即可,末尾会添加换行符;

冷考题:以下会输出什么?

答:WOWSide A  // 作者的编译器把side_a放在don’t的后面,puts遇到side_a中的‘\0’,才输出完成。

fputs():有第二个参数指定输出的位置。且不添加换行符。

printf()用起来没有puts()方便,但它可以格式化不同数据类型。

没用过:还可以在getchar()putchar()的基础上自定义所需的函数。

11.5 终于到字符串函数了

sprintf的原型在stdio.h中!!

查询string.h的完整列表:附录B参考资料V P362

strcatstrncat,因为strcat无法判断是否能容纳第二个参数,而strncat第三个参数指定了最大添加字符数。

strcat也会导致缓冲区溢出,程序员在使用时要小心。

strcmp返回的是两个字符之间的差值。

strncopy的注意事项:copy的副本不一定有空字符,所以要预留一个字符。

sprintf()函数声明在stdio.h而不是string.h中!!类似于printf把数据写入显示器,它把数据写入字符串!!可以把多个元素组合成一个字符串。

其它函数:

1char *strchr(const char *s, int c); // 可判断是否包含字符c,注意是int型的

2char *strpbrk(const char *s1, const char *s2); // 冷函数,用于判断s1是否包含s2中任意字符!!

3char *strrchr(…):多了个r,就是right,返回sc字符最后一次出现的位置。这个在c++中应该也支持吧。

4char *strstr(…):找第二个字符串的

restrict关键字:作用举例:不能把字符串copy给本身。

查询:C库中有个更高级的排序算法:qsort() // P382,在16章中会介绍

查询:ctype.h可以处理字符串中的字符。16章介绍预处理宏和函数的区别。

还有人没弄懂argcargv吗?书中有个很好的例子,一目了然:

argc是参数个数,argv是参数数组。argv[0]存储运行程序名称。目前385

argv是什么的缩写知道吗?argument value

11.9

字符串转成数据:

如数字213’2’, ’1’, ’3’形式存储在数组中。

C语言要求用数值形式进行数值计算,但在屏幕上显示数字则要求字符串形式printf()通过%d,将数字从数值形式转成字符串形式。

查询:atoi(把字母数字转成整数)的用法P385,为什么不是ctoi()?属于stdlib.h

查询:带错误检测功能的strtol()函数更安全(基本没用过)

此外还有atof()atol()strtol, strtoul, strtod等,strtol的第三个参数还可以指定进制

而要转换成字符串呢?用sprintf代替itoaftoa,注意itoaftoa不是c标准库成员。

再次强调查询:

字符串处理函数:string.h

字符处理函数:ctype.h

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值