C编程中对字符串的混淆



所以我正在学习使用编译器Dev c++编程c。问题1:

#include <stdio.h> 
#include <conio.h> //for the getch() function
#include <string.h> 
int main(void) 
{ 
    char line[3]; 
    strcpy(line, "Hello world"); 
    printf("%s", line); 
    getch(); 
} 

输出:Hello world

为什么当我声明我的字符串只容纳3个字符时,它会显示所有的"Hello world"?

问题2:

char line[3] = "Hello world"; 
printf("%s", line); 

输出:冥界

为什么显示"Hel"?它不应该只显示"He",因为行[0]= H,行[1]= e,行[2]= ''?而%s是通过搜索''来工作的吗?

请帮助我了解到底发生了什么。谢谢!

请帮助我了解到底发生了什么。

未定义的行为!

当你这样做的时候,你有一个缓冲区溢出:

char line[3]; 
strcpy(line, "Hello world"); 

为什么当我声明我的字符串只容纳3个字符时,它会显示所有的"Hello world"?

复制的数组大于已分配数组的大小。这是未定义的行为,因此任何输出都是可能的,包括但不限于,打电话给Tilda阿姨,格式化硬盘等:)更多信息请参阅这里。


char line[3] = "Hello world"; 
printf("%s", line); 

这里缓冲区读过了!参考alk的回答,为什么只有3个字符会被复制到line

为什么显示"Hel"?难道它不应该只显示"He"

不,它可以显示任何东西,还是因为未定义的行为。看看我在我的机器上得到了什么输出:

冥界☻

这是未定义的行为,因为printf期望你有一个以null结尾的字符串,是的,但这并不意味着你可以访问超出数组大小的数组,也就是说,你在内存中有一个像这样的数组

                 [0] [1] [2]
-----------------------------------------------
. . . █ | █ | █ | H | e | l | █ | █ | █ | . . .
-----------------------------------------------
                <-- line --->

上面写为█的任何东西都是一个未知的值,不在你的能力范围内,因此访问它们是未定义的。然而,printf中的%s期望一个以空结尾的字符串,因此,在您的命令下,它的读取超出了允许的范围(允许的只是三个元素,直到l)。在我的情况下,出现在l (smiley)之后的一个元素,而在你的情况下,它只是在l之后,因此看起来是正确的,但只是运气好,它可能会出现1000个元素。


如果您真的想打印char数组,它不是以空结束的,只到允许的限制,您可以执行以下操作之一,而不会遇到任何未定义的行为。

printf("%.3s", line);       // length specified at compile-time
printf("%.*s", 3, line);    // length fed at run-time

参考问题2:

当使用"string"字面值作为初始化项时,0 -终止符仅在有空间时才应用。

来自c99标准:

<

6.7.8初始化/strong>

[…]

14字符类型的数组可以任意地用字符串字面值初始化用大括号括起来。字符串字面值的连续字符(包括如果有空间或数组大小未知,则终止null字符)初始化

这两个例子的程序都有未定义的行为。在第一个示例中,覆盖数组之外的内存。在第二个例子中,C不允许使用超出对象可接受范围的初始化式。

2任何初始化器都不能试图为对象提供值包含在被初始化的实体中。

唯一的排除是对于允许忽略终止零的字符数组

14字符类型的数组可以用字符串初始化字面量或UTF - 8字符串字面量,可选地用大括号括起来。字符串字面值的连续字节数(包括结束的null)字符(如果有空间或数组大小未知)初始化数组元素

那么第二个代码段将不被编译,或者至少编译器将发出诊断消息。

为什么当我声明我的字符串只容纳3个字符时,它会显示所有的"Hello world"?

因为printf()读取字符串直到空终止符。它不知道存储空间有多大,strcpy()也不知道;如果您想确保复制不超过存储的长度,请使用strncpy()(注意中间的n)。

为什么显示"Hel"?

不需要对此进行解释,因为已经溢出了缓冲区——这可能会对程序产生任何奇怪的结果。您可能已经覆盖了其他内容(相反,您的数据随后也可能被覆盖)。如果你违反了规则,你很可能会调用"未定义行为"。

在这种情况下,由于初始化的形式,编译器可能只写了3个字符,但这不是什么值得指望的事情——当你违反规则时,没有必要的规则。

相关内容

  • 没有找到相关文章