4

void reverse(char *str){
    int i,j;
    char temp;
    for(i=0,j=strlen(str)-1; i<j; i++, j--){
     temp = *(str + i);
     *(str + i) = *(str + j);
     *(str + j) = temp;
     printf("%c",*(str + j));
    }
}



int main (int argc, char const *argv[])
{
    char *str = "Shiv";
    reverse(str);
    printf("%s",str);
    return 0;
}

char *str = "Shiv" を使用すると、逆関数、つまり str[i]=str[j] のスワッピング部分の行が機能しないように見えますが、str を char str[] = "Shiv" として宣言すると、スワップ部分は機能しますか?この理由は何ですか。プログラムを実行しようとすると、「バスエラー」というメッセージが表示され続けました。

4

8 に答える 8

16

を使用するchar *str = "Shiv";と、指しているメモリを所有しておらず、書き込みが許可されていません。文字列の実際のバイトは、プログラムのコード内の定数である可能性があります。

を使用するchar str[] = "Shiv";と、4(+1) 文字バイトと配列自体がスタック上にあり、好きなだけ書き込むことができます。

于 2009-10-13T19:47:48.633 に答える
4
char *str = "Shiv";

これは次のようになります。

const char *str = "Shiv";

そして今、あなたはエラーになるでしょう;)

于 2009-10-13T19:49:53.683 に答える
4

char *str = "Shiv" は、文字列定数へのポインタを取得します。これは、読み取り専用の保護されたメモリ領域 (実行可能コードの一部など) にロードできます。

于 2009-10-13T19:48:28.487 に答える
1

試す

int main (int argc, char const *argv[])
{
    char *str = malloc(5*sizeof(char)); //4 chars + '\0'
    strcpy(str,"Shiv");
    reverse(str);
    printf("%s",str);
    free(str); //Not needed for such a small example, but to illustrate
    return 0;
}

代わりは。これにより、ポインターを使用するときにメモリの読み取り/書き込みが可能になります。[] 表記を使用すると、スタックにスペースが直接割り当てられますが、const ポインターを使用すると割り当てられません。

于 2009-10-13T19:50:26.053 に答える
1

文字列リテラルは、C と C++ の両方で変更不可能なオブジェクトです。文字列リテラルを変更しようとすると、常に未定義の動作が発生します。これは、「バスエラー」が発生したときに観察するものとまったく同じです

char *str = "Shiv";

変異体。この場合、「逆」関数は文字列リテラルを変更しようとします。したがって、動作は未定義です。

char str[] = "Shiv";

variant は、変更可能な配列 'str' に文字列リテラルのコピーを作成し、'reverse' はそのコピーに対して動作します。これはうまくいきます。

PS 文字列リテラルへの const 修飾されていないポインターを作成しないでください。最初のバリアントは

const char *str = "Shiv";

(余分な「const」に注意してください)。

于 2009-10-13T19:51:43.633 に答える
1

文字列リテラル ("Shiv") は変更できません。
このような文字列リテラルのアドレスをポインターに代入し、ポインター値を逆参照して文字列リテラルの内容を変更しようとします。それは大きなNO-NOです。

代わりに str を配列として宣言します。

char str[] = "Shiv";

これにより、str が 5 文字の配列として作成され、文字 'S'、'h'、'i'、'v'、および '\0' が str[0]、str[1]、...、str[ にコピーされます。 4]。の各要素の値strは変更可能です。

文字列リテラルへのポインタを使用したいときは、通常それを宣言しconstます。そうすれば、コンパイラは、コードが文字列リテラルの内容を変更したいときにメッセージを発行することで私を助けることができます

const char *str = "Shiv";

整数でも同じことができると想像してください。

/* Just having fun, this is not C! */
int *ptr = &5;                      /* address of 5   */
*ptr = 42;                          /* change 5 to 42 */
printf("5 + 1 is %d\n", *(&5) + 1); /* 6? or 43?  :)  */

標準からの引用:

6.4.5 文字列リテラル
...
6 ... プログラムがそのような配列 [文字列リテラル] を変更しようとした場合、動作は未定義です。

于 2009-10-13T19:55:47.067 に答える
0

char *str は、文字ブロック (文字列) へのポインター/参照です。しかし、メモリのブロックのどこかに座っているので、そのように割り当てることはできません。

于 2009-10-13T19:49:26.770 に答える
0

これに今まで気がつかなかったのは興味深い。VS2008 C++ でこの状態を再現できました。

通常、定数をインプレースで変更することはお勧めできません。

いずれにせよ、この投稿はこの状況をかなり明確に説明しています。

最初の (char[]) は編集可能なローカル データです (配列はローカル データであるため)。

2 番目 (char *) は、グローバルな静的 (定数) データへのローカル ポインターです。定数データを変更することはできません。

GNU C を使用している場合は、-fwritable-strings を使用してコンパイルして、グローバル文字列が定数にならないようにすることができますが、これはお勧めできません。

于 2009-10-13T19:53:11.440 に答える