3

次のコードがある場合、メイン関数にメモリを割り当ててから、関数に渡します。これにより、次のようにメモリがいっぱいになります。

main()
{
    char *bar = (char*) malloc(sizeof(char));

    while(1)
    {
        foo(bar);
        free(bar);
        bar = (char*) malloc(sizeof(char));
    }
}

foo(char *bar)
{
    int c;
    int i = 0;
    while((c = getchar()) != '\n' && c != EOF)
    {
        bar[i++] = c;
        bar = (char*) realloc(bar, sizeof(char) * (i+1));
    }
}

いくつかの入力後にセグメンテーション違反が発生します。ただし、これを行う場合:

main()
{
    char *bar;

    while(1)
    {
        bar = foo();
        free(bar);
    }
}

char *foo()
{
    char *bar = (char*) malloc(sizeof(char));
    int c;
    int i = 0;
    while((c = getchar()) != '\n' && c != EOF)
    {
        bar[i++] = c;
        bar = (char*) realloc(bar, sizeof(char) * (i+1));
    }

    return bar;
}

つまり、関数にメモリ割り当てを配置すると、すべてが正常に機能しているように見えます。何故ですか?

4

4 に答える 4

4

これは非常に予想される動作です。realloc() は、渡されたポインタを新しいアドレスに「移動」する場合としない場合があります。その場合、free() も元のアドレスになります。C は値渡しであり、参照渡しではないためbar、main() 関数内のポインターは古いアドレスを参照し続け、効果的に double free (および realloc() されたポインター) を実行します。失うだろう)。

于 2013-01-15T18:44:02.697 に答える
2

C は値渡し言語です。bar内部への変更は、その関数呼び出しfoo()の外部には影響しません。barやろうとしていることを行うには、そのパラメーターを に変更し、の中でchar **bar使用する必要があります。*barfoo()

いくつかの編集上のメモ:

  1. malloc()またはの戻り値をrealloc()Cでキャストする必要はありません。

  2. に渡すのと同じポインターに代入しないでくださいrealloc()。失敗すると、メモリ リークが発生します。

  3. sizeof(char)1、なぜ余分な入力を気にするのですか?

于 2013-01-15T18:41:40.653 に答える
0

最初のケースでは、メモリを 2 回解放している可能性があります。このrealloc呼び出しは、メモリの別のチャンクを返すことができます。その場合、最初のチャンク (main で malloc されたチャンク) が解放されます。

于 2013-01-15T18:42:33.350 に答える
0

realloc常に同じメモリを拡張するとは限りません。拡張が不可能な場合、メモリの新しいチャンクが割り当てられることがあります。

main()
{
    char *bar = (char*) malloc(sizeof(char));

    while(1)
    {
        foo(&bar);
        free(bar);
        bar = (char*) malloc(sizeof(char));
    }
}

foo(char **dbar)
{
    char *bar = *dbar;
    int c;
    int i = 0;
    while((c = getchar()) != '\n' && c != EOF)
    {
        bar[i++] = c;
        bar = (char*) realloc(bar, sizeof(char) * (i+1));
    }
    *dbar = bar;
}
于 2013-01-15T18:45:30.103 に答える