0

gcc(Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 で ubuntu 12.04lts を使用しています。最初のプログラムでは文字を置き換えることができますが、正常にコンパイルされたにもかかわらず、2 番目のプログラムで出力を取得できないのはなぜですか? セグメンテーション違反が発生します。誰でも理由を説明できますか?

  #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

ごとISO C11 6.4.5 String literals /6に(ただし、この動作は標準の初期の反復でかなり長い間存在していましたが):

これらの配列の要素が適切な値を持っている場合、これらの配列が異なるかどうかは指定されていません。プログラムがそのような配列を変更しようとした場合、動作は未定義です。

つまり、動作を明確に定義したい場合、文字列リテラルの内容を変更することは許可されていません。特定の実装で動作する可能性がありますが、保証されるものではありません。一部の実装では、文字列リテラルは読み取り専用とマークされたメモリに配置されるため、変更しようとするとエラーが発生します。他のシステム (組み込みシステムなど) では、実際の読み取り専用メモリ (ROM) に配置されるため、障害が発生しなくてもメモリは変更されません。

この背後にある可能性のある理由の 1 つは、効率のために文字列リテラルをまとめる機能をコンパイラに与えることです。たとえば、コードに と の 2 つの文字列がdefinedあるundefined場合、これらは次のようにメモリに存在する可能性があります。

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

as のアドレスとundefinedas0x1234のアドレスをdefined使用し0x1236ます。

これが機能する理由:

char word[] = "Bhilip";

これは、合法的に変更可能な文字の配列を効果的に作成するためです。

  • 変更可能な配列を作成します。それから
  • 個々の文字をそれにコピーします。

つまり、機能的には次のものと同等です。

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