0

所以我正在学习使用编译器 Dev C++ 对 c 进行编程。问题一:

#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(); 
} 

输出:你好世界

为什么当我声明我的字符串只包含 3 个字符时它显示所有“Hello world”?

问题2:

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

输出:赫尔

为什么它显示“Hel”?由于 line[0] = H、line[1] = e 和 line[2] = '\0',它不应该只显示“He”吗?%s 通过搜索“\0”来工作?

请帮助我了解真正发生的事情。谢谢!

4

4 回答 4

11

请帮助我了解真正发生的事情。

未定义的行为!

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

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

为什么当我声明我的字符串只包含 3 个字符时它显示所有“Hello world”?

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


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

在这里,您有一个缓冲区过度读取!请参阅alk 的回答,了解为什么只有 3 个字符会被复制到line.

为什么它显示“Hel”?它不应该只显示“他”吗

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

嘿☻</p>

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

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

上面写成 █ 的任何东西都是未知值,不在你的权力范围内,因此访问它们是未定义的。但是,%sinprintf需要一个以 null 结尾的字符串,因此,根据您的命令,它读取的内容超出了允许的范围(允许的内容只有三个元素 until l)。在我的情况下,在(笑脸)\0之后出现了一个元素l,而在你的情况下,它只是在l出现正确但仅靠运气之后,它很可能会在 1000 个元素之后出现。


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

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

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

请参阅此处了解更多信息。

于 2014-08-02T11:07:02.810 回答
3

参考问题2:

当使用“字符串”字面量作为初始化器时,0只有在有空间时才会应用 -terminator。

C99 标准

6.7.8 初始化

[...]

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

于 2014-08-02T11:03:53.630 回答
1

这两个程序示例都有未定义的行为。在第一个示例中,您覆盖了数组之外的内存。在第二个示例中,C 不允许使用比对象可以接受的更多的初始化程序。

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

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

14 字符类型数组可以由字符串文字或 UTF-8 字符串文字初始化,可选用大括号括起来。字符串文字的连续字节(如果有空间或数组大小未知,则包括终止的空字符)初始化数组的元素。

因此,不应编译第二个代码片段,或者至少编译器应发出诊断消息。

于 2014-08-02T11:11:18.490 回答
0

为什么当我声明我的字符串只包含 3 个字符时它显示所有“Hello world”?

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

为什么它显示“Hel”?

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

在这种情况下,由于初始化的形式,编译器可能只写了 3 个字符,但这不是可以指望的——当你违反规则时,不一定有规则。

于 2014-08-02T11:06:58.370 回答