2017-11-26 15 views
2

私はこのプログラムをどこかから手に入れ、理解しようとしています。s [j] = s [i];文字をコピーしようとしているときにセグメンテーションエラーが発生しました

この行:s[j++] = s[i];がクラッシュの原因です。私の理解は、jが後で増分されるため、少なくともプログラムがクラッシュしないようにすることです。最初のjとiの値は0になります。

したがって、これはs [0] = s [0]のようになります。

なぜこのクラッシュが発生するのですか?

#include <iostream> 

using namespace std; 


void squeeze(char a[], char c); 

int main() 
{ 
    squeeze("qwiert", 'i'); 

    return 0; 
} 

void squeeze(char s[], char c) 
{ 
    int i, j; 

    for (i = j = 0; s[i] != '\0'; i++) 
    { 
     if (s[i] != c) 
     { 
      std::cout << "\ni: " << s[i]; 
      s[j++] = s[i]; 
      std::cout << "\nj: " << s[j]; 

      std::cout << "\nj : " << j; 
      exit(0); 
     } 
    } 

    s[j] = '\0'; 
} 

出力:このプログラムがクラッシュした後

i: q

私はsegfaultを見つけるためのプログラムを停止するexitステートメントを置いています。

あなたがなどのように、文字列に リテラルを変更することが許可されていない
+1

がsのために予約アドレス空間は、書き込み保護されていませんか? main()では定数のように定義されているため、コンパイラはそれを特殊なメモリ領域に入れることができます。しかしそれはちょうど推測です。 – KillPinguin

+0

ええ、それが理由でした。 @KillPinguin –

+1

コンパイルすると、次のような警告が表示されます。「ISO C++では、文字列定数を 'char *' [-Wwrite-strings]に変換することが禁止されています。いくつかのコンパイラはこれを完全に拒否し(技術的にはすべて)、エラーを出します。プログラムは警告とともにコンパイルされますが、警告はかなり正当なものではないことを意味し、プログラムは期待どおりに動作しない可能性があります。 – user4581301

答えて

4

squeeze("qwiert", 'i'); 

これはのほとんどすべての反復で覆われている標準(a)の

  • C++03 2.13.4.String literals [lex.string] /2
  • C++11 2.14.5.String literals [lex.string] /12;および
  • C++14 2.14.5.String literals [lex.string] /13

同じ文言は、それぞれに存在する:

すべての文字列リテラルが明瞭であるかどうか(つまり、重複しないオブジェクトに格納されている)実装定義です。 文字列リテラルを変更しようとすると、結果は未定義です。

文言は、最新のC++ 17標準ではほとんど変化が、現在C++17 5.13.5.String literals [lex.string] /16、あまりに同じ金額ました:

すべての文字列リテラルが異なっている(つまり、保存されているかどうか)、文字列リテラルの連続した評価が同じか異なるオブジェクトをもたらすかどうかは不特定であるかどうか。 [注:文字列リテラルを変更しようとすると、結果が不定になります。 -エンドノート]

私はあなたのような何かをしようと提案する:

char str[] = "qwiert"; // Make a writable copy. 
squeeze(str, 'i');  // then fiddle with that. 

(a)は、この答えで ISOの引用符は、実際に なぜこれまでのように暗示を提供

その場合です。

我々は常にマルチギガバイトのマシンを持っているとは限らず、初期のコンパイラで最適化するために特定のステップを取らなければならないケースがしばしばでした(CのほとんどはC++に移行しました。 C)。

このため、同じ文字(または、ある特定の方法で重複する文字、たとえば"successful"および"unsuccessful")を持つ2つの文字列は、同じメモリを共有して領域を減らすことができます。

もちろん、あなたは他の人に影響を与えることなく1つを変更することができないということでした。そのため、このルールが導入されました。

4

文字列定数"qwiert"squeeze関数に渡しています。この関数は、文字列定数の変更を試みますが、これは不正です。これにより、コアダンプが発生します。これが機能するために

、あなたは配列を渡す必要があります。

int main() 
{ 
    char str[] = "qwiert"; 
    squeeze(str, 'i'); 

    return 0; 
} 
+0

今すぐ試してみてください。問題は解決されました。あなたに全く感謝しています。 –

3

他の回答が問題を指摘し、どのようにそれを解決しなければなりません。

コンパイラの警告レベルを上げることで、このようなエラーを検出できることを指摘します。 g++ -Wall

、私は次の警告メッセージが表示されます:

socc.cc: In function ‘int main()’: 
socc.cc:10:26: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings] 
    squeeze("qwiert", 'i'); 
+0

あなたに感謝しています。 –

関連する問題