1

文字列内の単語/引数をその番号で取得する簡単な関数を作成しようとしています:

char* arg(char* S, int Num) {
    char* Return = "";
    int Spaces = 0;
    int i = 0;
    for (i; i<strlen(S); i++) {
        if (S[i] == ' ') {
            Spaces++;
        }
        else if (Spaces == Num) {
            //Want to append S[i] to Return here.
        }
        else if (Spaces > Num) {
            return Return;
        }
    }
    printf("%s-\n", Return);
    return Return;
}

文字を に入れる方法が見つかりませんReturn。ポインターを提案またはトリックする投稿をたくさん見つけましたがstrcat()、すべて segfaults です。それを使うべきだと言っている人も見たことmalloc()がありますが、このようなループでどのように使用したかはわかりません。

4

5 に答える 5

2

私はあなたがやろうとしていることが何であるかを理解しているとは主張しませんが、あなたのコードには2つの問題があります。

  • 読み取り専用の文字列をReturn;に割り当てています。その文字列は、読み取り専用のバイナリのデータセクションにあり、変更しようとすると、セグメンテーション違反が発生します。
  • forループはO(n ^ 2)です。これstrlen()は、O(n)だからです。

「文字列を返す方法」の問題を解決するには、いくつかの異なる方法があります。たとえば、次のことができます。

  • 提案されているように、malloc()/を使用して新しい文字列を割り当てますcalloc()
  • を使用asprintf()します。これは似ていますが、必要に応じてフォーマットできます
  • 出力文字列(およびその最大サイズ)をパラメーターとして関数に渡します

free()最初の2つは、戻り値を呼び出す関数を必要とします。3つ目は、呼び出し元が文字列(スタックまたはヒープ)の割り当て方法を決定できるようにしますが、出力文字列に必要な最小サイズについて何らかの契約が必要です。

于 2012-07-04T20:06:26.957 に答える
1

あなたのコードでは、関数が戻ると、それReturnも消えてしまうので、この振る舞いは定義されていません。それはうまくいくかもしれませんが、決してそれに頼るべきではありません。

通常、Cでは、代わりに「return」文字列を引数として渡し、常に渡す必要がないようにしますfree。どちらも呼び出し側にローカル変数mallocが必要ですが、割り当てられたメモリを解放するために追加の呼び出しが必要になり、単にローカル変数にポインタを渡すよりもコストがかかります。

文字列への追加については、配列表記を使用し(現在の文字/インデックスを追跡します)、最後にヌル文字を追加することを忘れないでください。

例:

int arg(char* ptr, char* S, int Num) {
    int i, Spaces = 0, cur = 0;
    for (i=0; i<strlen(S); i++) {
        if (S[i] == ' ') {
            Spaces++;
        }
        else if (Spaces == Num) {
            ptr[cur++] = S[i]; // append char
        }
        else if (Spaces > Num) {
            ptr[cur] = '\0';   // insert null char
            return 0;          // returns 0 on success
        }
    }

    ptr[cur] = '\0';           // insert null char
    return (cur > 0 ? 0 : -1); // returns 0 on success, -1 on error
}

次に、次のように呼び出します。

char myArg[50];
if (arg(myArg, "this is an example", 3) == 0) {
    printf("arg is %s\n", myArg);
} else {
    // arg not found
}

オーバーフローしないように注意してくださいptr(たとえば、サイズを渡し、関数にチェックを追加します)。

コードを改善する方法はいくつかありますが、まずは標準を満たすようにすることから始めましょう。;-)

PS:必要がmallocない限りしないでください。そしてその場合、あなたはそうしません。

于 2012-07-04T20:14:44.643 に答える
0
char * Return;   //by the way horrible name for a variable.
Return = malloc(<some size>);
......
......
*(Return + index) = *(S+i); 
于 2012-07-04T20:03:07.707 に答える
0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *arg(const char *S, unsigned int Num) {
    char *Return = "";
    const char *top, *p;
    unsigned int Spaces = 0;
    int i = 0;

    Return=(char*)malloc(sizeof(char));
    *Return = '\0';
    if(S == NULL || *S=='\0') return Return;
    p=top=S;
    while(Spaces != Num){
        if(NULL!=(p=strchr(top, ' '))){
            ++Spaces;
            top=++p;
        } else {
            break;
        }
    }
    if(Spaces < Num) return Return;
    if(NULL!=(p=strchr(top, ' '))){
        int len = p - top;
        Return=(char*)realloc(Return, sizeof(char)*(len+1));
        strncpy(Return, top, len);
        Return[len]='\0';
    } else {
        free(Return);
        Return=strdup(top);
    }
    //printf("%s-\n", Return);
    return Return;
}

int main(){
    char *word;

    word=arg("make a quick function", 2);//quick
    printf("\"%s\"\n", word);

    free(word);
    return 0;
}
于 2012-07-05T11:17:22.023 に答える
0

"" などの文字列リテラルには何も代入できません。

ループを使用して、探している文字列内の単語の開始位置のオフセットを決定することができます。次に、末尾または別のスペースに遭遇するまで文字列を続けて、その長さを見つけます。次に、オフセット + 1 のサイズに等しいサイズの char の配列を malloc できます (ヌル ターミネータの場合)。最後に、部分文字列をこの新しいバッファにコピーして返します。

また、前述のように、ループから strlen 呼び出しを削除することもできます。ほとんどのコンパイラはそれを最適化しますが、実際には配列内のすべての文字に対して線形操作であり、ループ O(n**2) を作成します。

于 2012-07-05T00:51:49.737 に答える