2

我知道这const char *是一个指向 const char 的指针,而是一个指向 charchar *const的常量指针。我正在以下代码中对此进行测试:

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为什么不允许修改指向的字符串?

4

4 回答 4

7

t指向字符串文字修改字符串文字是未定义的行为。C++ 标准草案标准部分2.14.5 字符串文字12段说(强调我的):

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

C99 标准草案的相关部分是6.4.5 字符串文字6段,其中说(强调我的):

如果它们的元素具有适当的值,则未指定这些数组是否不同。如果程序尝试修改这样的数组,则行为未定义。

在典型的现代 Unix 平台上,您会在只读段中找到字符串文字,如果我们尝试修改它会导致访问冲突。我们可以使用objdump来检查只读部分,如下所示:

objdump -s -j .rodata

我们可以在下面的实时示例中看到字符串文字确实会在只读部分中找到。请注意,我必须添加一个,printf否则编译器会优化字符串文字。示例 ` objdump输出:

Contents of section .rodata:
 400668 01000200 776f726c 64002573 0a00      ....world.%s..

另一种方法是t指向一个带有字符串文字副本的数组,如下所示:

char r[] = "world";    
char *const t = r ;
于 2013-10-15T03:47:48.160 回答
3

尽管 C 中的字符串文字正式具有char[](array of char, not const) 类型,但 C 标准明确规定它们必须被视为不可修改。编译器倾向于将字符串文字放在只读段中,因此尝试修改它们会导致访问冲突。

字符串文字在6.4.5C11 标准 (ISO/IEC 9899:2011) 的部分中进行了描述。

于 2013-10-15T03:47:34.737 回答
1

您可以通过将编译器错误重铸为 来绕过编译器错误char**((char*)s + 1) = 'a';因为它已经存在于其他答案中,这是未定义的行为,并且可能会导致分段错误,因为您正在编辑字符串文字。

于 2013-10-15T03:55:01.927 回答
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 *.

于 2013-10-15T08:13:05.560 回答