10

私はこれが何千回も尋ねられたことを知っていますが、私のコードでエラーを見つけることができません。誰かが私が間違っていることを親切に指摘できますか?

#include <stdlib.h>
#include <string.h>

void reverseString(char *myString){
  char temp;
  int len = strlen(myString);

  char *left = myString;
  //  char *right = &myString[len-1];                                                                                        
  char *right = myString + strlen(myString) - 1;

  while(left < right){
    temp = *left;
    *left = *right; // this line seems to be causing a segfault                                                              
    *right = temp;
    left++;
    right--;
  }
}

int main(void){
  char *somestring = "hello";
  printf("%s\n", somestring);
  reverseString(somestring);

  printf("%s", somestring);

}
4

6 に答える 6

13

最終的には、次のように元に戻す方がクリーンです。

#include <stdio.h>
#include <string.h>

void
reverse(char *s)
{
    int a, b, c;
    for (b = 0, c = strlen(s) - 1; b < c; b++, c--) { 
        a = s[b]; 
        s[b] = s[c]; 
        s[c] = a; 
    }

    return; 
}

int main(void)
{
    char string[] = "hello";
    printf("%s\n", string);
    reverse(string);
    printf("%s\n", string);

    return 0;
}

あなたのソリューションは、本質的にこれの意味的に大きなバージョンです。ポインタと配列の違いを理解してください。標準では、そのような操作 (文字列リテラルの内容の変更) の動作は未定義であると明示的に述べています。のエスキモーからの抜粋もご覧ください。

文字配列を文字列定数で初期化する場合:

char string[] = "Hello, world!";

文字列を含む配列になり、配列の内容を思いのままに変更できます。

string[0] = 'J';

ただし、コード内の他の場所で文字列定数 (正式な用語は文字列リテラル) を使用することは可能です。それらは配列であるため、通常どおり、式で使用されると、コンパイラは最初の要素へのポインターを生成します。つまり、あなたが言うなら

char *p1 = "Hello";
int len = strlen("world");

それはほとんどあなたが言ったかのようです

char internal_string_1[] = "Hello";
char internal_string_2[] = "world";
char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);

ここで、internal_string_1 および internal_string_2 という名前の配列は、コード内で文字列定数を使用するたびに、コンパイラが実際には小さな一時配列を生成していることを示しているはずです。しかし、微妙な事実として、文字列定数の「後ろ」にある配列は、必ずしも変更可能であるとは限りません。特に、コンパイラはそれらを読み取り専用メモリに格納する場合があります。したがって、あなたが書くならば

char *p3 = "Hello, world!";
p3[0] = 'J';

値 (この場合は文字「J」) を書き込み不可能なメモリに保存しようとするため、プログラムがクラッシュする可能性があります。

教訓として、文字列を作成または変更するときはいつでも、それらを作成または変更しているメモリが書き込み可能であることを確認する必要があります。そのメモリは、割り当てた配列か、次の章で説明する手法によって動的に割り当てたメモリのいずれかである必要があります。プログラムのどの部分も、文字列定数の 1 つに応答してコンパイラが生成した名前のない、書き込み不可能な配列の 1 つである文字列を変更しようとしないことを確認してください。(唯一の例外は配列の初期化です。そのような配列に書き込む場合、配列の初期化に使用した文字列リテラルではなく、配列に書き込むことになるためです。)"

于 2010-02-27T00:19:21.737 に答える
12

問題はここにあります

char *somestring = "hello";

somestringは、文字列リテラル「hello」を指します。C ++標準はこれを保証しませんが、ほとんどのマシンでは、これは読み取り専用データであるため、変更することはできません。

代わりにこのように宣言してください

char somestring[] = "hello";
于 2010-02-26T23:54:50.553 に答える
5

読み取り専用の可能性のあるメモリ領域を変更しようとして、未定義動作を呼び出しています(文字列リテラルは暗黙的constに-読み取りは可能ですが、書き込みはできません)。新しい文字列を作成して返すか、十分な大きさのバッファを渡して、逆の文字列を書き込みます。

于 2010-02-26T23:54:01.727 に答える
0

strrev()を呼び出すのは問題外だと思いますか?

于 2010-03-01T09:47:54.043 に答える
0

次のコードを使用できます

#include<stdio.h>
#include<string.h>
#include<malloc.h>
char * reverse(char*);

int main()
{
        char* string = "hello";
        printf("The reverse string is : %s", reverse(string));
        return 0;
}

char * reverse(char* string)
{

   int var=strlen(string)-1;
     int i,k;
     char *array;
     array=malloc(100);
     for(i=var,k=0;i>=0;i--)
    {
           array[k]=string[i];
            k++;
   }
  return array;
}
于 2010-03-01T09:37:13.297 に答える
-1

あなたの論理は正しいようです。ポインターを使用する代わりに、 を処理する方がクリーンchar[]です。

于 2010-02-27T00:00:57.873 に答える