在 ANSI C 中使用指针替换字符



我正在使用 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)中,这样,即使它没有出现故障,内存也保持不变。

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

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

undefined的地址为0x1234defined的地址为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

最新更新