2

必要に応じて、realloc()を使用してバッファーを拡張するfgetsを使用して文字列を読み取る関数を作成しました。

char * read_string(char * message){
    printf("%s", message);
    size_t buffsize = MIN_BUFFER;
    char *buffer = malloc(buffsize);
    if (buffer == NULL) return NULL;
    char *p;
    for(p = buffer ; (*p = getchar()) != '\n' && *p != EOF ; ++p)
        if (p - buffer == buffsize - 1) {
            buffer = realloc(buffer, buffsize *= 2) ;
            if (buffer == NULL) return NULL;
        }
    *p = 0;
    p = malloc(p - buffer + 1);
    if (p == NULL) return NULL;
    strcpy(p, buffer);
    free(buffer);
    return p;
}

プログラムをコンパイルして試してみたところ、期待通りに動作しました。しかし、valgrindを使用して実行すると、読み取り文字列が> = MIN_BUFFERであり、valgrindが次のように言うと、関数はNULLを返します。

(...)
==18076==  Invalid write of size 1
==18076==    at 0x8048895: read_string (programme.c:73)
==18076==    by 0x804898E: main (programme.c:96)
==18076==  Address 0x41fc02f is 0 bytes after a block of size 7 free'd
==18076==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==18076==    by 0x8048860: read_string (programme.c:76)
(...)
==18076== Warning: silly arg (-48) to malloc()
(...)

* p=0の間にprintfステートメントを追加しました。そしてp=malloc...そして渡されたargが-48の値を持っていることを確認しました。単独でvalgrindを使用して起動した場合、プログラムが同じように実行されないことを知りませんでした。私のコードに何か問題がありますか、それとも単なるvalgrindのバグですか?

4

3 に答える 3

7

バッファを再割り当てしても、ポインタ'p'は引き続き古いバッファを指します。

これはメモリを浪費し、将来の割り当てで偽の値を使用する原因にもなります。

于 2012-12-09T21:27:46.723 に答える
2

reallocmalloc渡されたポインタが以前にまたはによって返されたと仮定して、渡されたポインタと同じ内容の要求されたサイズの新しいバッファへのポインタを返しますrealloc。同じポインタであることを保証するものではありません。Valgrindは、の動作を変更する可能性が非常に高いですreallocが、仕様の範囲内に保ちます。

ループ内でメモリのサイズを変更しているので、ポインタではなくbuffer、先頭からのオフセットとして位置を追跡する方が適切です。buffer

于 2012-12-09T22:26:32.997 に答える
1

男3reallocが言うように

...この関数は、メモリブロックを新しい場所に移動する場合があります。

これが意味するのは、

p = malloc(p - buffer + 1);

問題です。realloc()が呼び出された場合、バッファはメモリと式の新しいブロックを指している可能性があります

(p - buffer)

意味がありません。

于 2012-12-09T21:45:15.847 に答える