0

我正在使用带有 gcc(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3 的 ubuntu 12.04lts。我可以在第一个程序中替换一个字符,但是为什么我不能在第二个程序中得到输出,即使它编译成功了?我得到分段错误。谁能解释原因?

  #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 \n\n", "Thilip");
    return 0 ;
  }
4

2 回答 2

3
char * p1 = "Bhilip";

声明一个指向字符串文字的指针。这可能保存在只读存储器中,因此无法修改。

p1[0] = 'T';

尝试修改字符串文字中的第一个字符。这会导致未定义的行为,包括可能的段错误。

如果你想要一个可写的字符串,你可以声明一个堆栈缓冲区并用字符串文字初始化它

char p1[] = "Bhilip";
p1[0] = 'T'; // now allowed
于 2013-11-10T23:47:34.790 回答
3

根据ISO C11 6.4.5 String literals /6(尽管这种行为在标准的早期迭代中已经存在了很长一段时间):

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

这意味着如果您希望明确定义行为,则不允许修改字符串文字的内容。它可能适用于某些实现,但不能保证。在一些实现中,字符串文字被放置在标记为只读的内存中,以便尝试修改它会导致引发错误。在其他(例如嵌入式系统)中,它可能被放置在实际的只读存储器(ROM)中,这样即使它没有故障,存储器也保持不变。

这背后的一个可能原因是它使编译器能够将字符串文字折叠在一起以提高效率。例如,如果您的代码有两个字符串definedundefined,它们可能以如下形式存在于内存中:

        +---+---+---+---+---+---+---+---+---+----+
0x1234: | u | n | d | e | f | i | n | e | d | \0 |
        +---+---+---+---+---+---+---+---+---+----+

带有 as 的地址和asundefined0x1234地址。defined0x1236

这样做的原因:

char word[] = "Bhilip";

是因为它创建了一个可以合法修改的字符数组,有效地:

  • 创建可修改数组;然后
  • 将单个字符复制到其中。

换句话说,它在功能上等同于:

char word[7];             // modifiable
strcpy (word, "Bhilip");  // initialise
于 2013-11-10T23:50:18.327 回答