[英]Confusion on strings in C programming
所以我正在学习使用编译器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
为什么显示“ Hel”? 由于line [0] = H,line [1] = e和line [2] ='\\ 0',它不应该只显示“ He”吗? 并且%s通过搜索'\\ 0'起作用吗?
请帮助我了解实际情况。 谢谢!
请帮助我了解实际情况。
不确定的行为!
执行此操作时, 缓冲区溢出 :
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
希望您有一个以空值结尾的字符串,是的,但这并不意味着您可以访问超出数组大小的内存,即您在内存中拥有这样的数组
[0] [1] [2] ----------------------------------------------- . . . █ | █ | █ | H | e | l | █ | █ | █ | . . . ----------------------------------------------- <-- line --->
上面写为█的任何东西都是未知值,不在您的权力之下,因此访问它们是不确定的。 但是, printf
%s
期望以空字符结尾的字符串,因此,在您的命令下,它读取的内容超出了所允许的范围(直到l
为止,所允许的只是三个元素)。 在我的情况下, \\0
在l
(笑脸)之后出现了一个元素,而在您的情况下,它恰好在l
之后出现,因此只是靠运气,它很可能以后会出现1000个元素。
如果您真的要打印不以null终止的char
数组,但只能打印到允许的限制,则可以执行其中之一而不会遇到任何未定义的行为。
printf("%.3s", line); // length specified at compile-time
printf("%.*s", 3, line); // length fed at run-time
提及问题2:
当使用“字符串”字面量作为初始化程序时,仅在有空间的情况下应用0
终止符。
从C99-Standard :
6.7.8初始化
[...]
14字符类型数组可以由字符串文字初始化,并可选地用大括号括起来。 字符串文字的连续字符(如果有空间或数组大小未知,则包括终止空字符)将初始化数组的元素。
这两个程序示例均具有未定义的行为。 在第一个示例中,您将覆盖数组之外的内存。 在第二个示例中,C不允许使用超出对象可以接受的数量的初始化程序。
2初始化程序不得尝试为未包含在正在初始化的实体内的对象提供值。
唯一的排除是针对允许忽略终止零的字符数组进行的
14字符类型的数组可以由字符串文字或UTF-8字符串文字初始化,并可选地用大括号括起来。 字符串文字的连续字节(如果有空间或数组大小未知,则包括终止空字符)将初始化数组的元素。
因此,不应编译第二个代码片段,或者至少编译器应发出诊断消息。
当我声明我的字符串仅包含3个字符时,为什么它显示所有“ Hello world”?
因为printf()
读取的字符串最多为空终止符。 它不知道存储空间有多大, strcpy()
也不知道; 如果要确保副本不超过存储空间的长度,请使用strncpy()
(注意中间的n
)。
为什么显示“ Hel”?
不必对此进行解释,因为您已经溢出了缓冲区-这可能会对程序产生任何奇怪的结果。 您可能已经覆盖了其他内容(相反,您的数据随后可能会被覆盖)。 如果您违反规则,则很可能会调用“未定义的行为”。
在这种情况下,由于初始化的形式,编译器可能只写了3个字符,但这并不是值得指望的事情-违反规则并不一定要遵循规则。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.