0

文字列を元に戻す小さな C++ 関数があります。

void reverse1(string& s, int start, int end) {
  if (s.empty()) return;
  char tmp;

  while (start < end) {
    tmp = s[end];
    s[end] = s[start];
    s[start] = tmp;
    ++start;
    --end;
  }
}

この機能は正常に動作します。しかし、以下のようにcで書き直すと、ステートメント11でセグメントフォルトに遭遇しました。

  5 void reverse2(char *s, int start, int end) {
  6   if (!s) return;
  7   char tmp;
  8   
  9   while (start < end) {
 10     tmp = s[end];
 11     *(s + end) = *(s + start);
 12     *(s + start) = tmp;
 13     ++start;
 14     --end;
 15   } 
 16 } 

関数を呼び出すドライバー プログラム:

int main() {
  /* Flavor1 works */
  string a = "hello world2012!";
  reverse1(a, 0, a.length() - 1);

  /* Flavor2 does not - segmentation fault */ 
  char *b = "hello world2012!";
  reverse2(b, 0, strlen(b) - 1);
}

プログラムのコンパイルには gcc v 4.6.1 を使用しています。gdb を使用してコードをステップ実行すると、プログラムが実行時にセグメンテーション違反でクラッシュします。

文字列 s は const ではありません。誰かがここで何が起こっているのか提案できますか? この問題を解決するにはどうすればよいですか。ありがとう。

更新: 文字列リテラルで reverse2 関数が呼び出されます。問題は、文字列リテラルを変更しようとしていたことです。Jim と H2CO3 が指摘したように、これは未定義の動作です。

文字列リテラルで初期化された文字列オブジェクト (a) と文字列リテラル (b) の正確な違いは何ですか?

4

2 に答える 2

0

以下のようにコードを書き直すことができます

void reverse(char *s, int start, int end) {
  if (!s) return;
  char tmp;

  if( end >= strlen(s) )
      end = strlen(s)-1;

  while (start < end) {
    tmp = s[end];
    *(s + end) = *(s + start);
    *(s + start) = tmp;
    ++start;
    --end;
  } 
} 
于 2012-09-21T04:37:51.200 に答える
0

ルーチンを呼び出す方法によって異なります。endC でよくあるように、 が配列の長さである場合s[end]、 は有効な参照ではありません ... を超える 1 文字sです。

また、!sC++ と同等ではありませんs.empty。文字列が空かどうかではなく、ポインタが NULL かどうかをテストします。そのためには、、、、などを!*s使用!s[0]しますs[0] == '\0'strlen(s) == 0

文字列 s は const ではありません。

文字列リテラル定数の場合、とにかく失敗する可能性があります。そのような文字列への書き込みは未定義の動作です。

于 2012-09-21T04:27:14.367 に答える