C语言中字符串的几种定义方式和有没有’\0‘

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36391130/article/details/81590176

( 主要解决 什么时候是 “abcd\0” 什么时候是 “abcd” 的问题 )

几种常用方式
1.char* str = “abcd”;
2.char str[] = { “abcd” };
3.char str[] = { ‘a’, ‘b’, ‘c’, ‘d’ }; //要用户自己加入’\0‘,应为str[] = { ‘a’, ‘b’, ‘c’, ‘d’ ,’\0’};
4.char str[5];scanf(“%s”,str);
5.char str[5];gets(str);

其中第2,3种方式没有指定数组的大小,如果正确指定当然更好。
那么问题来了;
怎么算是正确指定呢?
如果没有正确指定,字符串是什么样子呢?
第4,5种由用户输入的方法生成的字符串,会有‘\0’吗?
为了理清其中关系,我们搞几个字符串试一试;
首先,我们约定一个比较简单的字符串,比如:字符串 “abcd” ,加上 ‘\0’ 是 “abcd\0” 5个字符的字符串;
接下来,上代码:
代码
可以看到,第60行有报错,第55行有警告;
警告我们先不管;
报错的是 char str22[3] = { ‘a’,’b’,’c’,’d’ }; 这一句,原因是“初始值设定项太多”
于是我们就得到一个结论:在字符数组进行逐一赋值时,字符个数不能大于数组容量。

将报错的语句注释掉,重新编译,警告不理会,于是:
代码

接下来,我们运行代码,并且在运行到scanf()和gets()函数时,我们都输入 abcd
(说明:fflush()函数用来清空缓冲区,防止之前输入字符串后按的Enter键停留在缓冲区,gets()读取键盘时直接将其读走,导致gets()无法正确读取键盘输入 的问题)
运行结果:
这里写图片描述
打印各字符串的大小或者字符数组的大小(用sizeof()操作符):
这里写图片描述
看到这个结果,就发现其中几个字符串的打印是有问题的,那么是什么问题呢?

(说明:在Debug 模式下,VC 会把未初始化的栈内存全部填成0xcc,0xcc超过了ASCII码0-127这个范围,于是这个“字符串”被系统当成了宽字符组成的字符串,即两个字节数据组成一个字符,而0xCCCC表示的宽字符正好是个“烫”字。当字符串看就是 烫烫烫烫……会把未初始化的堆内存全部填成0xcd,当字符串看就是 屯屯屯屯……。Release 模式下,那块内存里本来装的什么值就是什么值。)

这时我们做一个假设:因为字符串没有结束标志‘\0’,从而在解析字符串时没法停下来,直到遇到了下一个字符串的‘\0’。
接下来,我们来看一看,我们的假设是否正确。

在本图中,我将每个字符串的地址都放在了语句后面,并且在内存窗口中直接查看每个字符串对应的内存,以这种方式来分析各种字符串的生成方式的差别。
这里写图片描述

接下来,我们分析上图:
1.为什么不看字符串 str0 呢?
str0是类型为 char* 指针,它指向“abcd”这个字符串常量,而且这个字符串常量被放置在此程序的内存静态区,它与栈中的内存的地址距离甚远,所以在图中无法找到。我将其单独放在这里:
这里写图片描述
从str0的内存来看,我们可以发现,字符串常量 “abcd” 我们并没有给它赋‘\0’,但是它 “abcd” 后面自动跟了四个字节,四个字节中都存了0,也就是‘\0’。而且sizeof(str0) == 4;也就是说,这个字符串中并不包含‘\0’,但它仍是以‘\0’为结束标志的字符串。
2.字符数组整体赋值
a.当不指定数组大小时
str1[] = {“abcd”};
字符数组自动跟了个‘\0’,并且本字符串sizeof(str1)==5;也就是说这个字符串是包含‘\0’,也就是“abcd\0”
b.当指定数组大小 == 字符个数+1时
和不指定数组大小的情况相同 ;“abcd\0”
c.当指定数组大小 == 字符个数时
字符串之后没有‘\0’这个结束标志,sizeof(str12)==字符数组大小;“abcd”
d.当指定数组大小 < 字符个数时
编译器会发出警告,并且字符串没有‘\0’这个结束标志,sizeof(str12)==字符数组大小
e.当指定数组大小 > 字符个数时
字符填入数组,并且剩余的数组空间全为0;

3.字符数组逐一赋值
a.当不指定数组大小时
不会添加‘\0’,并且sizeof(str2) == 4,字符串为 “abcd” 后面为随机值
b.当指定数组大小 == 字符个数+1时
字符数组自动跟了个‘\0’,并且本字符串sizeof(str21)==5;也就是说这个字符串是包含‘\0’,也就是“abcd\0”
c.当指定数组大小 < 字符个数时
编译器报错,无法进行编译
d.当指定数组大小 > 字符个数时
字符填入数组,并且剩余的数组空间全为0;

4.由用户输入
字符数组自动跟了个‘\0’,并且本字符串sizeof(str1)==5;也就是说这个字符串是包含‘\0’,也就是“abcd\0”

总结:
此时,我们就可以得出结论,我们的假设是正确的,而且结合第二条说明,我们可以看出,打印出不正常的字符串都是没有’\0‘的字符串,也就是没有字符串结束标志,于是将内存中的随机值当字符串打印了出来,直到遇到了下一个字符串的’\0‘。我们应当注意这些情况,并且在定义字符串时,根据这些字符串生成方式的特点,结合实际需要生成更加合适的字符串。

展开阅读全文

没有更多推荐了,返回首页