我编写了一个函数,用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说:
时,该函数返回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错误?
答案 0 :(得分:6)
当您重新分配缓冲区时,指针'p'仍然指向旧缓冲区。
这会破坏内存,并导致将来的分配使用虚假值。
答案 1 :(得分:1)
正如man 3 realloc所说
...该功能可能会将内存块移动到新位置。
这意味着什么呢
p = malloc(p - buffer + 1);
是问题所在。如果调用realloc(),缓冲区可能指向一个新的内存和表达式块
(p - buffer)
没有任何意义。
答案 2 :(得分:1)
realloc
返回一个指向所请求大小的新缓冲区的指针,其内容与传入的指针相同,假设传入的指针先前由malloc
或realloc
返回。它不保证它是相同的指针。 Valgrind很可能修改realloc
的行为,但将其保持在规范范围内。
由于您要在循环中调整内存大小,因此您可以通过跟踪buffer
中的位置作为buffer
开头的偏移而不是指针来提供更好的服务。