C++11 字符数组初始化和字符串字面量

Posted

技术标签:

【中文标题】C++11 字符数组初始化和字符串字面量【英文标题】:C++11 char array intializations and string literals 【发布时间】:2021-07-02 18:09:53 【问题描述】:

在 C++11 中,char 指针不能直接初始化为字符串字面量。 在早期版本的 C++ 中,我可以毫无问题地做到这一点。

如果允许以下代码:

char arr[] = "Hello";
char *p_str1 = arr;  //allowed

那为什么下面的代码不允许呢?

char *p_str3 = "Hello"; //Not allowed

注意:我知道添加 const 会解决问题。但我需要知道原因。

【问题讨论】:

恕我直言,错误消息中的原因很清楚。第二个和第一个类似,但 const char arr[] = "Hello";. @S.M.需要知道第一个与第二个有何不同 C相关问题:C: differences between char pointer and array @CEPB 我不知道有任何 C++ 实现会为这两种情况执行堆分配。 @CEPB 对您的评论的编辑使它变得更加错误,而不是更少。这与跟踪动态内存分配的能力无关。 【参考方案1】:

char arr[] = "Hello" 将字符串文字"Hello" 的可修改副本存储在字符数组arr 中。 p_str1是指向那个数组的指针,数据是可修改的,所以指针不需要是const

char *p_str3 = "Hello" 是直接指向只读字符串文字的指针。指针不拥有字符串文字,通常这些都存储在内存的一些只读部分中,无论哪种方式您都可以访问数据,但您不能修改它,所以const 指针强制避免在运行时出现不希望出现的问题。

C++ 标准不允许非常量指针指向不可修改的数据。这是幸运的,因为它通过尝试修改它来避免未定义的行为,就像在不存在此规则的 C 中经常发生的那样。

在 C++03 中使用非常量 char 指针仍然是合法的(可能是出于兼容性原因),当它被弃用时,在 C++11 之后它被禁止,但据我所知,尝试修改这些字符串文字总是未定义的行为。

【讨论】:

好的。不过只是一个问题。那么在 C++11 之前,这部分不是只读的吗? 不,它可能仍然是只读的。允许指向字符串文字的非常量指针是非强制错误的常见来源,因此标准编写者决定硬着头皮将其正式定为非法。 @SumaiyaA,我误解了你的问题,它永远无法修改,const 规则的实施是为了避免尝试修改它所产生的问题。 @user4581301 是的,这是我的主要困惑点。感谢您清除该部分始终是只读的,但修改它会导致错误。所以现在受到了正确的限制。 我不说“始终为只读” 我不相信标准要求它是只读的,只是它可能是只读的记忆。我不擅长标准解析和语言法,但总的来说 C++ 标准不喜欢指定这样的细节。只有在 C++20 中,2s Compliment 在成为事实上的标准几十年后才成为一项要求。我相信会有一些奇怪的系统可以修改文字,但我怀疑你会在实验室之外看到一个。我从来没有见过。【参考方案2】:

因为C++明白字符串常量会被存储在不可修改的内存中,所以必须标记为const。在许多编译器中,它存储在只读的 data segment 中。

任何修改该字符串的尝试都可能导致分段错误。

在第一种情况下,您实际上是在复制到本地数组。这是可以修改的。

【讨论】:

第一种方法与方法 2 有何不同。需要明确。那么字符串常量不会存储在不可修改的内存中? 在第一种情况下,您说的是“请创建一个包含以下内容副本的本地数组”,并且在大多数编译器上存储在堆栈中。 任何修改该字符串的尝试都可能导致分段错误。 或更糟。我记得邪恶而神秘的“巴士错误”。

以上是关于C++11 字符数组初始化和字符串字面量的主要内容,如果未能解决你的问题,请参考以下文章

总结了一些指针易出错的常见问题

Go语言 多维数组使用

go语言之字符串指针数组切片

用字符串字面量初始化非常量参数

Golang 什么叫字面量和组合字面量?

Golang 什么叫字面量和组合字面量?