11

環境

私は C を学んでいて、ポインターを使用してその場で文字列を逆にしようとしています。(配列を使用できることは知っています。これは、ポインターについて学習することに関するものです。)

問題

以下のコードを実行しようとすると、セグメンテーション違反が発生し続けます。GCCはこの行が気に入らないよう*end = *begin;です。何故ですか?

特に私のコードは、別の質問ですでに説明されている悪意のない C 関数とほぼ同じであるためです。

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

void my_strrev(char* begin){
    char temp;
    char* end;
    end = begin + strlen(begin) - 1;

    while(end>begin){
        temp = *end;
        *end = *begin;
        *begin = temp;
        end--;
        begin++;
    }
}

main(){
    char *string = "foobar";
    my_strrev(string);
    printf("%s", string);
}
4

8 に答える 8

22

1 つの問題は、関数に渡すパラメーターにあります。

char *string = "foobar";

これは、読み取り専用部分に割り当てられた静的文字列です。で上書きしようとすると

*end = *begin;

セグメンテーション違反になります。

試してみてください

char string[] = "foobar";

違いに気付くはずです。

重要なポイントは、最初のケースでは文字列が読み取り専用セグメントに存在し、それへのポインタのみが使用されるのに対し、2 番目のケースでは適切なサイズの文字の配列がスタックと静的文字列 (これは常に存在する) がそれにコピーされます。その後、配列の内容を自由に変更できます。

于 2010-01-23T20:35:47.617 に答える
5

また、文字列内の文字を交換するために文字列の末尾にヌル文字を使用することもできます。これにより、余分なスペースの使用を避けることができます。コードは次のとおりです。

#include <stdio.h>

void reverse(char *str){    
    int length=0,i=0;

    while(str[i++]!='\0')
        length++;

    for(i=0;i<length/2;i++){
        str[length]=str[i];
        str[i]=str[length-i-1];
        str[length-i-1]=str[length];
    }

    str[length]='\0';
}

int main(int argc, char *argv[]){

    reverse(argv[1]);

    return 0;
}
于 2012-08-14T15:13:53.450 に答える
4

コードには次のものがあります。

*end--;
*begin++;

これが正しいことをするのは純粋な運だけです(実際、理由は演算子の優先順位です)。コードが実際に実行することを意図していたようです

(*end)--;
(*begin)++;

これは完全に間違っています。あなたがそれを持っている方法で、操作は次のように起こります

  • デクリメントendしてから逆参照します
  • インクリメントbeginしてから逆参照します

どちらの場合も、間接参照は不要であるため、削除する必要があります。あなたはおそらくその振る舞いを意図していたでしょう

end--;
begin++;

これらは、追跡するのが非常に難しいため、開発者のバティを駆り立てるものです。

于 2010-01-23T21:36:14.477 に答える
3

これは適切であり、ポインターを使用します

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

 void reve(char *s)
 {
    for(char *end = s + (strlen(s) - 1); end > s ; --end, ++s)
    {
        (*s) ^= (*end);
        (*end) ^= (*s);
        (*s) ^= (*end);
    }
 }

int main(void)
{
    char *c = malloc(sizeof(char *) * 250);
    scanf("%s", c);
    reve(c);
    printf("\nReverse String %s", c);
}
于 2012-01-13T08:10:07.247 に答える
2

に変更char *string = "foobar";char string[] = "foobar";ます。問題は、achar *が読み取り専用メモリを指していて、それを変更しようとするとセグメンテーション違反が発生することです。

于 2010-01-23T20:37:08.303 に答える
0

これは、インプレース C 文字列反転の私のバージョンです。

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

int main (int argc, const char * argv[])
{
    char str[] = "foobar";
    printf("String:%s\n", str);
    int len = (int)strlen(str);
    printf("Lenth of str: %d\n" , len);
    int i = 0, j = len - 1;
    while(i < j){
        char temp = str[i];
        str[i] = str[j];
        str[j] = temp;
        i++;
        j--;
    }

    printf("Reverse of String:%s\n", str);
    return 0;
}
于 2011-12-10T20:49:47.373 に答える
0

これにより、小さな(っぽい)再帰関数が作成され、スタックを下る途中で値を保存し、戻る(戻る)ときに文字列の先頭へのポインタ(* s)をインクリメントすることで機能します。

コードは巧妙に見えますが、スタックの使用に関してはひどいものです。

#include <stdio.h>

char *reverse_r(char val, char *s, char *n)
{
    if (*n)
        s = reverse_r(*n, s, n+1);
   *s = val;
   return s+1;
}

int main(int argc, char *argv[])
{
    char *aString;

    if (argc < 2)
    {
        printf("Usage: RSIP <string>\n");
        return 0;
    }

    aString = argv[1];
    printf("String to reverse: %s\n", aString );

    reverse_r(*aString, aString, aString+1); 
    printf("Reversed String:   %s\n", aString );

    return 0;
}
于 2012-02-22T10:23:57.390 に答える
0

以下に、この問題に対する私のコードを示します。

#include <string>
#include <iostream>

char* strRev(char* str)
{
    char *first,*last;

    if (!str || !*str)
        return str;

    size_t len = strlen(str);
    for (first = str, last = &str[len] - 1; first < last ; first++, last--)
    {
        str[len] = *first;
        *first = *last;
        *last = str[len];
    }
    str[len] = '\0';
    return str;
}

int main()
{
    char test[13] = "A new string";
    std::cout << strRev(test) << std::endl;
    return 0;
}
于 2018-03-10T22:26:02.603 に答える