包含3个字符的字符串显示意外输出,而包含6个字符的字符串显示正确的输出

时间:2017-09-17 06:17:12

标签: c string

这是我的C代码

#include <stdio.h>

int main()
{
    char c[3] = "abc";
    char a[6] = "Shamal";

    printf("%s\n\n", c);
    printf("%s\n\n", a);

    return 0;
}

这里的输出是

abcW?

Shamal

6个字符的字符串正确显示字符串,3个字符的字符串显示W?在代码的最后。

我知道我们需要把空字符&#39; \ 0&#39;终止字符串。但是这里两个字符串都没有空字符但只有一个正常工作。这是什么原因?

3 个答案:

答案 0 :(得分:2)

正如上面的评论所说,undefined是未定义的,但对你的问题的确切答案是,它偶然发生在第一个字符串之后的内存字节不是0,但是&#39; W&#39;然后&#39;?&#39;然后是0,终止一个字符串。

对于第二个字符串,碰巧字符串后面的一个字节意外地为0,因此它被正确打印。

尝试重新排序初始化并查看输出是否会发生变化(最有可能)。

答案 1 :(得分:2)

每当你写char c[4] = "abc";char c[] = "abc";之类的内容时,字符串abc都会被存储内存(并且你无法更改此字符串)并自动附加\0 。在这两种情况下,您都没有为终止NUL字符分配空间。

对于char a[6] = "Shamal";,如果您要遍历字符并按索引0通过5打印它们,您将收到字符串。

现在,如果您仔细注意,您已为六个字符仅留出空间并且\0没有空间。 \0可能会写入您不拥有的空间,即l之后。在这个阶段,你已经超出了你认为足够的缓冲空间。这本身足以导致UB。当您要求printf打印出您的字符串时,会出现另一个问题。 printf会继续打印,直到找到\0为止。一旦你调用UB,就不知道将会发生什么。

检查this以获取其他说明。

答案 2 :(得分:1)

继续我的评论,您只是没有提供足够的空间来在初始化中创建字符字符串。以下内容为 nul-terminatedating 字符创建了字符数组 ,没有空间:

char c[3] = "abc";
char a[6] = "Shamal";

编译期间不会收到任何警告,因为初始化是字符数组的有效初始化 - 而不是字符串

例如,char c[3] = "abc";会在内存中产生以下连续字节:

    | a | b | c |

这是一个由3个元素组成的有效字符数组,每个元素都可以编入索引为c[0], c[1], c[2]。但是,要将c用作字符串c需要以下内存中的4个连续字节

    | a | b | c |\0|

要纠正问题并允许编译器在初始化过程中包含 nul-terminatedating 字符,请不要为数组提供大小,编译器会自动调整数组的大小以提供包含 nul-character 所需的额外空间,例如

char c[] = "abc";
char a[] = "Shamal";

或者(更容易出错),为自己提供 nul-character 的空间,例如

char c[4] = "abc";
char a[7] = "Shamal";

两者都会导致ca包含 nul-terminatedating 字符,允许每个字符在代码中用作字符串