【发布时间】:2021-09-19 13:04:49
【问题描述】:
我正在学习 C,来自 Python,我试图理解 printf() 为何会这样。
我的理解是C中的字符串是一个字符数组,后面跟着一个空字符。
如果你这样声明你的字符串:
char string[] = "I am a string";
printf("char: %lu bytes\n", sizeof(char));
printf("%s\n", string);
printf("%lu\n", sizeof(string));
编译器会在末尾隐式插入空字符。输出:
char: 1 bytes
I am a string
14
注意一个 char 的大小是 1 个字节,字符串中有 13 个字符(10 个字母和 3 个空格),字符串的大小是 14 个字节。额外的字节是空字符。
或者,我们这样声明我们的字符串:
char string2[] = {'h', 'e', 'l', 'l', 'o', '\0'};
printf("%s\n", string2);
printf("%lu\n", sizeof(string2));
我们手动将空字符插入到我们的数组中,当我们打印它或获取它的大小时它的行为与预期一样:
hello
6
但是,如果我们不手动插入空字符,并尝试打印它:
char string3[] = {'w', 'o', 'r', 'l', 'd'};
printf("%s\n", string3);
printf("%lu\n", sizeof(string3));
我们得到(或者至少,在我的机器上,我得到了)
worldhello
5
它在最后打印 string2。我们可以深入挖掘一下,看看为什么:
char *strAddr = string2;
char *str3Addr = string3;
char *lastElemStr3 = &string3[4];
printf("Address of hello string:\t\t\t%p\n", strAddr);
printf("Address of world string:\t\t\t%p\n", str3Addr);
printf("Address of string 3 last element + one byte:\t\t%p\n", lastElemStr3 + 1);
给了
Address of hello string: 0x7ffee10768a4
Address of world string: 0x7ffee107689f
Address of string 3 last element + one byte: 0x7ffee10768a4
所以 printf 将我们的数组“超出”了一个字节并打印了该内存单元中的任何内容 - 在这种情况下,它恰好是存储前一个数组的位置。为什么这样做,只有在最后没有空字符的情况下?这有什么好处?
【问题讨论】:
-
您正在使用两种不同类型的初始化程序。为什么您希望它们表现相同?
-
OT:“请注意 char 的大小是 1 字节”...
sizeof(char)始终为 1。 -
printf读取超出数组边界,因为不包含终止空字符,因此您会引发未定义的行为。 -
@4386427 你能详细说明一下吗?
-
@HoldenNelson 来自 C 规范:“当 sizeof 应用于类型为 char [...] 的操作数时,结果为 1。”