C++ 为什么更改非常量字符时出现分段错误*?

C++ 为什么更改非常量字符时出现分段错误*?,c++,pointers,char,constants,C++,Pointers,Char,Constants,使用此代码,我得到一个分段错误: char* inputStr = "abcde"; *(inputStr+1)='f'; 如果代码为: const char* inputStr = "abcde"; *(inputStr+1)='f'; 我将得到“分配只读位置”的编译错误。 然而,对于第一种情况,没有编译错误;只是在实际发生赋值操作时出现的分段错误 有人能解释一下吗?即使“abcde”是一个字符串文字,不应该修改它,但您已经告诉编译器,您不在乎它,让一个非常量字符*

使用此代码,我得到一个分段错误:

   char* inputStr = "abcde";
   *(inputStr+1)='f';
如果代码为:

   const char* inputStr = "abcde";
   *(inputStr+1)='f';
我将得到“分配只读位置”的编译错误。 然而,对于第一种情况,没有编译错误;只是在实际发生赋值操作时出现的分段错误

有人能解释一下吗?

即使
“abcde”
是一个字符串文字,不应该修改它,但您已经告诉编译器,您不在乎它,让一个非常量
字符*
指向它


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

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


这里有一个很好的解释:

标准规定,无论您是否将字符串文本标记为常量,都不允许直接修改字符串文本:

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

事实上,在C语言中(与C++不同),字符串文字不是常量,但仍然不允许对其进行写入

这种对书写的限制允许进行某些优化,例如沿以下行共享文字:

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

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

这大部分是古代历史;很久以前,字符串文字不是常量

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

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


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

发生的情况是编译器将常量
“abcde”
放在某个只读内存段中。您将(非常量)
char*inputStr
指向该常量,然后将kaboom和segfault指向该常量

要吸取的教训:不要调用未定义的行为

编辑(精化)

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


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

字符串文字虽然正式为非常量,但几乎总是存储在只读内存中。在您的设置中,显然只有声明为const char array时才会出现这种情况


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

这将在代码段中创建:

char *a = "abcde";
本质上是常数

如果要编辑它,请尝试:

char a[] = "abcde";

以下是标准在第[2.13.4/2]节中对字符串文字的说明:

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

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

const char[6]
现在,代码中发生的是对

char*
这样作业就可以了。之所以如此,很可能是因为与C的兼容性。请看下面的讨论:


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

Ritchie单词中字符串文本的一点历史。 主要是关于K&R 1中字符串文字的起源和演变。 希望这能澄清关于常量和字符串文字的一两件事

发信人:丹尼斯·里奇 主题:Re:历史问题:字符串文本。 日期:1998年6月2日 新闻组:comp.std.c

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

我没有出席委员会对这一问题的审议 这一点很重要,但我怀疑BSD实用程序用于摆弄 用于移动字符串初始化的汇编代码 以文本代替数据,并实现 事实上,文字字符串并没有被覆盖,而是更多 比gcc的一些早期版本更重要

我认为委员会可能遗漏了什么 没有找到一个公式来解释 字符串文字在常量方面的行为。 也就是说,如果“abc”是类型为的匿名文本 常量字符[4] 然后是它的所有属性(包括 能够使其成为只读,甚至可以共享其存储 与其他出现的相同文字)几乎相同 解释道

这方面的问题不仅仅是相对较少的人 实际写入字符串文字的位置,但很多 更重要的是,为作业制定可行的规则 指向常量的指针,特别是函数的实际 事实上,委员会知道 他们制定的规则不能要求强制执行 对现有世界中的每个func(“字符串”)进行诊断

所以他们决定离开普通字符数组的“…” 输入,但说一个是不需要写在上面的

顺便说一句,这张便条不是故意的
char*
Dennis