2013-10-15 135 views
2

我知道const char *是一个指向const char的指针,而char *const是一个指向char的常量指针。 我在下面的代码测试此:修改char * 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指向的字符串不允许?

回答

7

t指向一个字符串字面这是不确定的行为修改字符串字面。 C++标准牵伸部2.14.5字符串文字段落说重点矿山):

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

从C99标准草案中的相关部分是6.4.5字符串文字段落它说(重点矿山):

它是未指定的这些阵列是否是不同的提供它们的元素有 适当的值。 如果程序试图修改这样一个数组,行为是 未定义。

在一个典型的现代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

你说出了标准,但你并没有真正说出为什么(程序如何)会因为错误而终止......只是说... Elchonon Edelson给出了实际的原因,我认为这是正确的答案。 –

+0

@AlexisWilke该标准意味着与平台无关,这些细节依赖于平台,这就是为什么标准使用诸如未定义行为之类的语言来涵盖整个范围的行为,包括正常工作但不能依赖的行为。我为典型的现代unix平台添加了更多细节。 –

3

虽然在C字符串文字正式具有类型char[](阵列的char,不const)的,C标准明确规定,他们必须为不可修改的处理。编译器倾向于将字符串文字放在只读段中,因此尝试修改它们会导致访问冲突。

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

1

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

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 *