使用此代码,我会遇到分段错误:
char* inputStr = "abcde";
*(inputStr+1)='f';
如果代码是:
const char* inputStr = "abcde";
*(inputStr+1)='f';
我将收到“分配只读位置”的编译错误。 但是,对于第一种情况,没有编译错误;只是分配操作实际发生时的分段错误。
任何人都能解释一下吗?
答案 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
“