2

我编写了一个函数来使用 fgets 读取字符串,该函数使用 realloc() 使缓冲区在需要时增长:

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 说:

(...)
==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

realloc返回一个指向所请求大小的新缓冲区的指针,其内容与传入的指针相同,假设传入的指针先前由mallocor返回realloc。它不保证它是同一个指针。Valgrind 很可能会修改 的行为realloc,但将其保持在规范内。

由于您在循环中调整内存大小,因此最好通过跟踪您的位置buffer作为从开头的偏移量buffer而不是指针来为您提供更好的服务。

于 2012-12-09T22:26:32.997 回答
1

正如 man 3 realloc 所说

...该函数可能会将内存块移动到新位置。

这意味着什么

p = malloc(p - buffer + 1);

是问题所在。如果调用 realloc(),缓冲区可能指向一个新的内存块和表达式

(p - buffer)

没有任何意义。

于 2012-12-09T21:45:15.847 回答