我知道const char *
是指向const char的指针,而char *const
是指向char的常量指针。
我在以下代码中测试它:
const char *s = "hello"; // Not permitted to modify the string "hello"
char *const t = "world"; // Not permitted to modify the pointer t
s = "hello2"; // Valid
// t = "world2"; // Invalid, gives compilation error
// *(s + 1) = 'a'; // Invalid, gives compilation error
*(t + 1) = 'a'; // Why does this not work?
最后一行没有给出任何错误,但导致程序意外终止。为什么修改t
指向的字符串是不允许的?
答案 0 :(得分:7)
t
指向字符串文字修改字符串文字是未定义的行为。 C ++草案标准部分2.14.5
字符串文字段 12 表示(强调我的):
是否所有字符串文字都是不同的(即存储在非重叠对象中)是实现定义的。 尝试修改字符串文字的效果未定义。
C99标准草案的相关部分是6.4.5
字符串文字段 6 ,其中写着(强调我的):< / p>
如果这些数组的元素具有不同的数据,则未指定 适当的价值观如果程序试图修改这样的数组,则行为是 未定义。强>
在典型的现代Unix平台上,您会在只读段中找到字符串文字,如果我们尝试修改它,将导致访问冲突。我们可以使用 objdump 来检查只读部分,如下所示:
objdump -s -j .rodata
我们可以在下面的live example中看到字符串文字确实可以在只读部分中找到。请注意,我必须添加printf
,否则编译器会优化字符串文字。示例` objdump 输出:
Contents of section .rodata:
400668 01000200 776f726c 64002573 0a00 ....world.%s..
另一种方法是让t
指向一个带有字符串文字副本的数组,如下所示:
char r[] = "world";
char *const t = r ;
答案 1 :(得分:3)
虽然C中的字符串文字正式具有char[]
类型(char
的数组,而不是const
),但C标准明确规定必须将它们视为不可修改的。编译器倾向于将字符串文字放在只读段中,因此尝试修改它们会导致访问冲突。
字符串文字在C11标准(ISO / IEC 9899:2011)的6.4.5
部分中描述。
答案 2 :(得分:1)
您可以通过将其重新编译为char*
来绕过编译器错误,就像在*((char*)s + 1) = 'a';
中一样,但由于它已经在其他答案中被清除,这是未定义的行为,并且可能会导致分段错误,因为您是编辑字符串文字。
答案 3 :(得分:1)
如果要正确测试它,请在函数中初始化字符串,以便初始化可以是动态的,并使用strdup()
。
int
main(int argc, char **argv)
{
char *d1 = strdup("hello");
char *d2 = strdup("world");
const char *s = d1;
char *const t = d2;
...
free(d1);
free(d2);
}
主要使用d1和d2变量,以便最后使用free()
正确释放动态分配。此外,正如其他答案所示,始终将字符串文字视为const char *
。