char数组如何存储在C++中?

Posted

技术标签:

【中文标题】char数组如何存储在C++中?【英文标题】:How is char array stored in C++? 【发布时间】:2020-10-04 15:47:51 【问题描述】:
int main()

    char c1[5]="abcde";
    char c2[5]='a','b','c','d','e';

    char *s1 = c1;
    char *s2 = c2;

    printf("%s",s1);
    printf("%s",s2);

    return 0;

在这段代码 sn-p 中,char 数组 C2 没有返回任何错误,但 char 数组 C1 返回的字符串太长。我知道 C1 必须要求大小为 6 才能存储 5 个字符,因为它将 \0 (NULL 字符)存储在最后一个索引中。但我很困惑为什么 C2 工作得很好?

此外,当使用%s 打印C2 时,输出为abcde@,其中@ 是一个乱码。 %sprintf 打印从给定地址开始的所有字符,直到遇到 \0。我不明白为什么要在末尾打印那个额外的字符

【问题讨论】:

我刚刚回答了这个问题here(尽管该问题的OP需要从不同的角度进行解释)。无需发布重复的答案(尤其是因为您已经有了一个好的答案)。 不,c1 不得产生错误。问题很可能是您使用的是 C++,而不是 C 编译器来编译代码 无论如何,请您在问题中添加实际错误消息 @AnttiHaapala:关于“不,c1 不得产生错误”:C 标准允许实现提供额外的诊断消息,尽管它应该是警告,而不是错误,因为程序应该被接受。 @EricPostpischil 这是真的。但是,我个人不知道任何会产生此消息的 C 编译器。 【参考方案1】:

您已经创建了两个未终止的字符串。使您的数组足够大以容纳空终止符,您将避免这种未定义的行为:

char c1[6] = "abcde";
char c2[6] = 'a','b','c','d','e','\0';

严格来说,后者实际上不需要'\0'。此声明是等效的,并且将包含空终止符:

char c2[6] = 'a','b','c','d','e';

我个人更喜欢第一种形式,但更方便的是可以省略显式长度:

char c1[] = "abcde";

【讨论】:

char a[100]='x'; 会被初始化为 99 个空字符吗? 是的 - 任何未显式初始化的数组成员都会得到0。 C11 6.7.9. 粗糙!你确实每天都能学到新东西。【参考方案2】:

我知道 C1 必须要求大小为 6 才能存储 5 个字符,因为它将 \0(NULL 字符)存储在最后一个索引中。但我很困惑为什么 C2 工作得很好?

编译器不会抱怨c2 的初始化,因为使用'a','b','c','d','e' 进行初始化不会隐式包含终止空字符。

相比之下,使用"abcde" 进行初始化确实包含一个空字符:C 标准定义了一个包含终止空字符的字符串文字,因此char c1[5]="abcde"; 名义上用6 个值初始化一个5 元素数组。在这种情况下,C 标准不需要警告或错误,因为 C 2018 6.7.9 14 表示如果数组没有空间可以忽略空字符。但是,您正在使用的编译器1 选择发出警告消息,因为这种形式的初始化通常指示错误:程序员试图用字符串初始化数组,但没有空间完整的字符串。

在 C 中,字符数组和字符串是不同的东西:数组是一个值序列,字符数组可以包含这些字符的任意值,包括末尾没有零值和可能的零值中间。例如,如果我们有一个来自二进制文件的字节缓冲区,那么这些字节对我们来说只是整数值;它们作为可能被打印的字符的含义是无关紧要的。字符串是一个以空字符结尾的字符序列。它不能有内部零值,因为第一个空字符标志着结束。

因此,当您定义一个字符数组(例如char c1[5])时,编译器不会自动知道您是打算使用它来保存字符串还是打算将其用作任意值的数组。当你用一个字符串初始化数组时,你的编译器本质上是在计算你打算使用数组来保存字符串,如果你用来初始化数组的字符串不合适,它会警告你。当您使用值列表初始化数组时,您的编译器基本上认为您可能正在使用它来保存任意值,并且它不会警告您可能缺少终止符。

另外,当使用%s 打印C2 时,输出为abcde@,其中@ 是一个乱码。

因为c2 没有终止字符,所以尝试打印它会超出数组的末尾,从而导致 C 标准未定义的行为。通常情况下,printf 会继续读取数组之外的内存,打印发生在那里的任何内容,直到它到达一个空字符。

脚注

1 这假设您确实使用 C 编译器来编译此源代码。 C++ 有不同的规则,并且不允许使用字符串字面量初始化的数组太短而不能包含终止的空字符。

【讨论】:

我相信 OP 正在使用 C++ 编译器...不幸的是 OP 没有在问题中包含错误消息。 @AnttiHaapala:即使在 C 模式下,MSVC 也会发出警告。 嗯,必须是一个选项,不会在编译器资源管理器上发出警告 嗯,如果您添加 /Wall 或类似名称 @AnttiHaapala 是的,我正在使用 C++ 编译器。错误是字符数组的初始化字符串太长。我上传了它,但它在编辑中被剪掉了。

以上是关于char数组如何存储在C++中?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 如何使用和传递一个 3 维字符数组?

数组如何在 C++ 的内存中存储字符串?

如何在 C++ 中将字符串转换为 char 数组?

在c++中实现,如何创建一个char的数组

如何在 C++ 中将数组 char 复制到字符串或 int* (void *) 中? [关闭]

在 C++ 中连接 char 数组