为什么更改非const char *的分段错误?

时间:2011-08-04 22:05:36

标签: c++ pointers char const

使用此代码,我会遇到分段错误:

   char* inputStr = "abcde";
   *(inputStr+1)='f';

如果代码是:

   const char* inputStr = "abcde";
   *(inputStr+1)='f';

我将收到“分配只读位置”的编译错误。 但是,对于第一种情况,没有编译错误;只是分配操作实际发生时的分段错误。

任何人都能解释一下吗?

9 个答案:

答案 0 :(得分:6)

以下是标准中关于[2.13.4 / 2]部分中字符串文字的内容:

  

不以u,U或L开头的字符串文字是普通的字符串文字,也称为窄字符串文字。普通的字符串文字具有“n const char数组”类型,其中n是下面定义的字符串的大小;它具有静态存储持续时间(3.7)并使用给定的字符初始化。

因此,严格地说,“abcde”有类型

const char[6]

现在你的代码中发生了隐式转换为

char*

以便允许分配。其原因可能是与C.的兼容性。另请参阅此处的讨论:http://learningcppisfun.blogspot.com/2009/07/string-literals-in-c.html

一旦完成转换,你在语法上可以自由地修改文字,但它失败了,因为编译器将文字存储在不可写的内存段中,正如标准本身允许的那样。

答案 1 :(得分:3)

这是在代码段中创建的:

char *a = "abcde";

基本上它是常量。

如果您想编辑它,请尝试:

char a[] = "abcde";

答案 2 :(得分:2)

标准声明不允许您直接修改字符串文字,无论您是否将它们标记为const

  

是否所有字符串文字都是不同的(即,存储在非重叠中   对象)是实现定义的。尝试修改字符串文字的效果未定义。

事实上,在C语言中(与C ++不同),字符串文字不是 const但你仍然不允许写入它们。

这种写作限制允许进行某些优化,例如分享文字:

char *ermsg = "invalid option";
char *okmsg =   "valid option";

其中okmsg实际上可以指向'v'中的ermsg字符,而不是一个独特的字符串。

答案 3 :(得分:1)

字符串文字通常存储在只读内存中。试图更改此内存将导致您的程序失效。

以下是一个很好的解释:Is a string literal in c++ created in static memory?

答案 4 :(得分:1)

这主要是古代历史;很久以前,字符串文字并不是一成不变的。

但是,大多数现代编译器将字符串文字放入只读内存(通常是程序的文本段,代码也存在),任何更改字符串文字的尝试都会产生核心转储或等效内容。 / p>

使用G ++,您肯定可以获得编译警告(-Wall,如果默认情况下未启用)。例如,在MacOS X 10.6.7上编译的G ++ 4.6.0(但在10.7上运行)产生:

$ cat xx.cpp
int main()
{
    char* inputStr = "abcde";
   *(inputStr+1)='f';
}
$ g++ -c xx.cpp
xx.cpp: In function ‘int main()’:
xx.cpp:3:22: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
$

因此默认情况下启用警告。

答案 5 :(得分:1)

发生的事情是编译器将常量"abcde"放在某个只读内存段中。你把你的(非常数)char* inputStr指向那个常数,然后用kaboom,segfault。

要学习的课程:不要调用未定义的行为。

编辑(详解)

  

然而,对于第一种情况,没有编译错误,只是在实际发生分配操作时出现分段错误。

您需要启用编译器警告。始终将编译器警告设置得尽可能高。

答案 6 :(得分:0)

即使"abcde"是一个不应修改的字符串文字,你已告诉编译器你不关心它,因为它有一个非常量char*指向它。

编译器很乐意假设您知道自己在做什么,而不是抛出错误。但是,当您确实尝试修改字符串文字时,代码很可能在运行时失败。

答案 7 :(得分:0)

字符串文字,虽然官方非常量,但几乎总是存储在只读内存中。在你的设置中,显然只有它被声明为const char数组的情况。

请注意,该标准禁止您修改任何字符串文字。

答案 8 :(得分:0)

Ritchie所说的字符串文字的一点历史。 主要是关于来自K& R 1的字符串文字的orgin和演变。 希望这可以澄清关于const和字符串文字的一两件事。

“来自:Dennis Ritchie 主题:回复:历史问题:字符串文字。 日期:1998年6月2日 新闻组:comp.std.c

当C89委员会工作时,可写 字符串文字不是“遗留代码”(Margolin)和什么标准 存在(K& R 1)非常明确(A.2.5) 字符串只是初始化静态数组的一种方式。 而巴里指出,有一些(mktemp)例程 使用了这个事实。

我不在委员会对此事的审议 点,但我怀疑BSD实用程序是为了摆弄 用于移动字符串初始化的汇编程序代码 文本而不是数据,以及最多的实现 文字字符串实际上没有被覆盖,更多 比一些早期版本的gcc重要。

我认为委员会可能错过了什么 未能找到解释的配方 字符串文字在const方面的行为。 也就是说,如果“abc”是类型的匿名文字   const char [4] 然后几乎所有的属性(包括 能够进行只读,甚至共享其存储 与其他出现的相同文字)差不多 说明。

这个问题不仅仅是相对较少的问题 字符串文字实际上写的地方,但很多 更重要的是,制定可行的作业规则 to pointers-to-const,特别是函数的实际 参数。实际上,委员会知道无论如何 他们制定的规则不需要强制性 现有世界中每个func(“string”)的诊断。

所以他们决定离开普通char数组的“......” 类型,但要求一个人不要写它。

本说明BTW不打算作为狙击手阅读 在C89的配方中。得到的东西很难 正确(连贯和正确)和可用(一致 足够,有吸引力)。

Dennis