所以我正在学习使用编译器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();
}
输出: 你好世界
为什么当我声明我的字符串只能容纳3个字符时,它会显示所有“Hello world”?
问题2:
char line[3] = "Hello world";
printf("%s", line);
输出: 赫尔
为什么显示“Hel”?它不应该只显示“He”,因为行[0] = H,行[1] = e和行[2] ='\ 0'? %s的工作原理是搜索'\ 0'?
请帮助我了解最新情况。谢谢!
答案 0 :(得分:11)
请帮助我了解最新情况。
未定义的行为!
执行此操作时,您需要buffer overrun:
char line[3];
strcpy(line, "Hello world");
为什么当我声明我的字符串只能容纳3个字符时,它会显示所有“Hello world”?
您复制的数量超过了已分配数组的大小。这是未定义的行为,因此任何输出都是可能的,包括但不限于调用阿姨Tilda,格式化硬盘等。:) See here以获取更多信息。
char line[3] = "Hello world";
printf("%s", line);
这里有buffer over-read!有关为何只将3个字符复制到line
的原因,请参阅alk's answer。
为什么显示“Hel”?它不应该只显示“他”
不,它可以显示任何内容,因为未定义的行为。看看我的机器输出了什么:
Hel☻
这是未定义的行为,因为printf
期望你有一个以null结尾的字符串,是的,但这并不意味着你可以访问超出数组的大小,即你在内存中有这样的数组
[0] [1] [2] ----------------------------------------------- . . . █ | █ | █ | H | e | l | █ | █ | █ | . . . ----------------------------------------------- <-- line --->
上面写的任何东西都是未知的值,不是你的权力,因此访问它们是不明确的。但是,%s
中的printf
需要一个以空字符结尾的字符串,因此,在您的命令下,它会超出允许的范围(允许的是只有三个元素,直到l
)。在我的情况下,\0
在l
之后出现了一个元素(笑脸),而在你的情况下,它恰好在l
之后出现正确,但只有运气,它可能会出现1000个元素。
如果你真的想打印{null}终止的char
数组,只能达到允许的限制,你可以在不遇到任何未定义的行为的情况下执行其中一个。
printf("%.3s", line); // length specified at compile-time
printf("%.*s", 3, line); // length fed at run-time
See here了解更多信息。
答案 1 :(得分:3)
参考问题2:
当使用“string”-literal作为初始化时,0
- 终结符仅在有空间时才会应用。
来自C99-Standard:
6.7.8初始化
[...]
14可以选择使用字符串文字初始化字符数组 用括号括起来。字符串文字的连续字符(包括 如果有空间或数组的大小未知,则终止空字符)初始化 数组的元素。
答案 2 :(得分:1)
程序的两个示例都有未定义的行为。 在第一个示例中,您将覆盖数组之外的内存。 在第二个示例中,C不允许使用比对象可以接受的更多的初始化器。
2初始化程序不应尝试为对象提供值 包含在正在初始化的实体中。
对于允许忽略终止零
的字符数组,唯一的排除是完成的14字符串数组可以用字符串初始化 文字或UTF-8字符串文字,可选择用大括号括起来。 字符串文字的连续字节(包括终止空值) 字符,如果有空间或数组的大小未知) 初始化数组的元素。
因此不应编译第二个代码片段,或者至少编译器应发出诊断消息。
答案 3 :(得分:0)
为什么当我声明我的字符串只能容纳3个字符时,它会显示所有“Hello world”?
因为printf()
读取一个字符串直到null终止符。它不知道存储有多大,strcpy()
也不知道;如果您想确保副本不超过存储空间的长度,请使用strncpy()
(注意中间的n
。)
为什么显示“Hel”?
没有必要对此进行解释,因为你已经溢出了缓冲区 - 这可能对程序产生任何奇怪的后果。您可能已经覆盖了其他内容(相反,您的数据可能会被覆盖)。如果违反规则,则很可能会调用“未定义的行为”。
在这种情况下,编译器只能编写3个字符,因为初始化的形式,但这不是值得信赖的事情 - 当你违反规则时,不一定有规则。< / p>