6

これは宿題の一部です。

メソッド getLine でファイルの 1 行を読み取って返そうとしています。

char *getLine(FILE *input) {
    char line[30];
    if(fgets(line, sizeof(line), input)!=NULL)
    {
        return line;
    }else{
        return NULL;
    }
}

これは、ポインターに関して教えられたことからうまくいくようですが、警告メッセージを削除することはできませんwarning: function returns address of local variable [enabled by default]。この警告は行を参照していますreturn line;。私の割り当てでは、コンパイル時に警告やエラーが発生しないことが必要です。私が間違っていることはわかりません。

私が見つけたヘルプのほとんどは、テキスト行の malloc-ing スペースを提案していましたが、別のクラスでいくつか行ったことがあるにもかかわらず、クラスではまだカバーしていません。それは本当にこれを行うための最良の方法ですか?もしそうなら、私はプログラムのどこでも自由にすることができますか?

4

2 に答える 2

14

char line[30];自動保存期間を持つ配列です。実行が関数のスコープ外になると、メモリが存在するメモリの割り当てが解除されるため、返されるこのメモリへのポインタは無効になります (ダングリング ポインタ)。

既に割り当てが解除されているメモリにアクセスしようとすると、未定義の動作が発生します。

配列を動的に割り当てて、呼び出し元に明示的に割り当てを解除させることができます。

char *getLine() {
    char* line = malloc(30);
    ...
    return line;
}

// somewhere:
char* line = getLine();
...
free(line);
于 2013-02-14T10:23:18.673 に答える
5

私が見つけることができる限り、以前の質問ではカバーされていない、mallocを使用しない代替案:

/* Warning, this function is not re-entrant. It overwrites result of previous call */
char *getLine(FILE *input) {
    static char line[30];
    return fgets(line, sizeof(line), input);
    /* fgets returns NULL on failure, line on success, no need to test it */
}

説明:関数スコープ内の静的変数は、関数が戻った後でも値を保持します。そのような変数のインスタンスは 1 つだけで、その関数へのすべての呼び出しで同じインスタンスが使用されます (したがって、再入可能/スレッドセーフではありません)。静的変数用のメモリは、プログラムの起動時に割り当てられます。ヒープでもスタックでもなく、実行中のプログラムのメモリ空間にある独自の予約領域です。静的変数の値は、最初に使用される前に一度だけ初期化されます (上記には特定の初期化がないため、0 で埋められますが、初期化子も持つことができ、関数が初めて呼び出されたときの値になります)。

この方法で static 変数を使用することは少しハックに見えるかもしれませんが (そして私もそうであることに同意します)、これは依然として有効なパターンであり、たとえばfunctionを使用して標準 C でも採用されていstrtok()ます。また、C 標準にもあるように、再入可能なバージョンの必要性を示していますstrtok_r()。これは、ローカルの静的変数ではなく、追加のパラメーターが 1 つあるため、使用がより複雑です。

于 2013-02-14T10:30:40.590 に答える