我正在使用 ubuntu 12.04lts 和 gcc(Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3。我可以替换第一个程序中的字符,但是为什么我不能在第二个程序中获得输出,即使它编译成功?我得到分段错误。谁能解释一下原因?
#include<stdio.h>
int main(void)
{
char word[] = "Bhilip";
char *cp = word ;
puts(word);
cp[1] = 'T'; // allowed??
puts(word);
return 0;
}
#include<stdio.h>
int main(void)
{
char * p1 = "Bhilip";
p1[0] = 'T'; //allowed?
printf("nThilip");
printf(" %s nn", "Thilip");
return 0 ;
}
根据ISO C11 6.4.5 String literals /6
(尽管这种行为在标准的早期迭代中已经存在了相当长的一段时间):
如果这些数组的元素具有适当的值,则无法指定这些数组是否不同。如果程序尝试修改此类数组,则行为未定义。
这意味着,如果您希望明确定义行为,则不允许修改字符串文本的内容。它可能适用于某些实现,但绝不保证。在某些实现中,字符串文本被放置在标记为只读的内存中,因此尝试修改它会导致引发错误。在其他系统(如嵌入式系统)中,它可能被放置在实际的只读存储器(ROM)中,这样,即使它没有出现故障,内存也保持不变。
这背后的一个可能原因是,它使编译器能够将字符串文本折叠在一起以提高效率。例如,如果您的代码具有两个字符串 defined
和 undefined
,它们可能存在于内存中,如下所示:
+---+---+---+---+---+---+---+---+---+----+
0x1234: | u | n | d | e | f | i | n | e | d | |
+---+---+---+---+---+---+---+---+---+----+
undefined
的地址为0x1234
,defined
的地址为0x1236
。
这样做的原因:
char word[] = "Bhilip";
是因为它创建了一个可合法修改的字符数组,有效地:
- 创建可修改的数组;然后
- 将单个字符复制到其中。
换句话说,它在功能上等效于:
char word[7]; // modifiable
strcpy (word, "Bhilip"); // initialise
char * p1 = "Bhilip";
声明指向字符串文本的指针。 这可能保存在只读内存中,因此无法修改。
p1[0] = 'T';
尝试修改字符串文本中的第一个字符。 这会导致未定义的行为,包括可能的段错误。
如果你想要一个可写的字符串,你可以声明一个堆栈缓冲区,并使用字符串文字初始化它
char p1[] = "Bhilip";
p1[0] = 'T'; // now allowed