为何对malloc分配的字符串调用realloc却失效?
问题:realloc调用返回NULL且Valgrind报无效内存操作错误
我为了理解malloc的工作机制,写了个程序观察数组扩容后的内存地址变化,但调用realloc时返回NULL,Valgrind还报了错误。
原代码:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <string.h> int main(int argc, char *argv[]) { char* buff; buff = malloc(10); buff = "hi"; printf("%c\n", buff[0]); printf("%p\n", &buff[0]); if (realloc(buff, (size_t) 20) == NULL){ printf("no\n"); exit(1); } printf("%p\n", &buff[0]); return 0; }
Valgrind运行结果:
valgrind ./test ==3421== Memcheck, a memory error detector ==3421== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==3421== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==3421== Command: ./test ==3421== h 0x400734 ==3421== Invalid free() / delete / delete[] / realloc() ==3421== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3421== by 0x400673: main (in /home/puf311/cs3733/practice/test) ==3421== Address 0x400734 is not stack'd, malloc'd or (recently) free'd ==3421== no==3421== ==3421== HEAP SUMMARY: ==3421== in use at exit: 10 bytes in 1 blocks ==3421== total heap usage: 2 allocs, 1 frees, 15 bytes allocated ==3421== ==3421== LEAK SUMMARY: ==3421== definitely lost: 10 bytes in 1 blocks ==3421== indirectly lost: 0 bytes in 0 blocks ==3421== possibly lost: 0 bytes in 0 blocks ==3421== still reachable: 0 bytes in 0 blocks ==3421== suppressed: 0 bytes in 0 blocks ==3421== Rerun with --leak-check=full to see details of leaked memory ==3421== ==3421== For counts of detected and suppressed errors, rerun with: -v ==3421== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
我原以为字符串是malloc分配的且没提前free,为啥会出问题?
问题分析:
核心错误在buff = "hi";这行代码:
- 你先用
malloc(10)给buff分配了一块堆内存,此时buff指向堆里的地址。 - 但紧接着
buff = "hi";把buff的指针值改成了字符串常量"hi"的地址——这个地址属于程序的只读数据段,根本不是malloc分配的堆内存。 - 后面调用
realloc(buff, 20)时,传入的是只读数据段的地址,不是malloc返回的有效堆指针,所以Valgrind报错“地址不是栈、malloc分配或最近free的”,realloc自然返回NULL。 - 另外,原来malloc的10字节堆内存因为指针被覆盖,再也无法访问,造成了内存泄漏(对应Valgrind里的“definitely lost:10 bytes”)。
修正后的代码:
要把字符串复制到malloc分配的堆内存里,而不是直接赋值指针,同时还要正确保存realloc的返回值(因为realloc可能返回新的地址):
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <string.h> int main(int argc, char *argv[]) { char* buff; buff = malloc(10); if (buff == NULL) { // 先检查malloc是否成功 printf("malloc failed\n"); exit(1); } strcpy(buff, "hi"); // 把字符串复制到堆内存中,而不是修改指针 printf("%c\n", buff[0]); printf("%p\n", &buff[0]); char* temp = realloc(buff, 20); // 用临时变量保存realloc返回值,避免原指针丢失 if (temp == NULL){ printf("realloc failed\n"); free(buff); // 原内存还在,要释放避免泄漏 exit(1); } buff = temp; // 重新赋值buff到新的内存地址 printf("%p\n", &buff[0]); free(buff); // 最后释放内存 return 0; }
内容的提问来源于stack exchange,提问作者gwynb2001
相关产品推荐
相关产品推荐

