C语言 C free(): 无效指针
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20297524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C free(): invalid pointer
提问by Dan
I am teaching myself C. My goal is to make a C function that just walks a query string and splits on the ampersand and the equals sign. I am getting stuck on this error from Valgrind.
我正在自学 C。我的目标是制作一个 C 函数,它只遍历查询字符串并在与号和等号上进行拆分。我陷入了 Valgrind 的这个错误。
==5411== Invalid free() / delete / delete[] / realloc()
==5411== at 0x402AC38: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5411== by 0x804857C: main (leak.c:28)
==5411== Address 0x420a02a is 2 bytes inside a block of size 8 free'd
==5411== at 0x402AC38: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5411== by 0x804857C: main (leak.c:28)
==5411==
==5411==
==5411== HEAP SUMMARY:
==5411== in use at exit: 0 bytes in 0 blocks
==5411== total heap usage: 1 allocs, 2 frees, 8 bytes allocated
==5411==
==5411== All heap blocks were freed -- no leaks are possible
==5411==
==5411== For counts of detected and suppressed errors, rerun with: -v
==5411== ERROR SUMMARY: 20 errors from 9 contexts (suppressed: 0 from 0)
and the backtrace :
和回溯:
*** Error in `./leak': free(): invalid pointer: 0x08c1d00a ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767c2)[0xb75f17c2]
/lib/i386-linux-gnu/libc.so.6(+0x77510)[0xb75f2510]
./leak[0x804857d]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0xb7594905]
./leak[0x8048421]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:05 262764 /home/danny/dev/c-qs-parser/leak
08049000-0804a000 r--p 00000000 08:05 262764 /home/danny/dev/c-qs-parser/leak
0804a000-0804b000 rw-p 00001000 08:05 262764 /home/danny/dev/c-qs-parser/leak
08c1d000-08c3e000 rw-p 00000000 00:00 0 [heap]
b757a000-b757b000 rw-p 00000000 00:00 0
b757b000-b7729000 r-xp 00000000 08:05 1312132 /lib/i386-linux-gnu/libc-2.17.so
b7729000-b772b000 r--p 001ae000 08:05 1312132 /lib/i386-linux-gnu/libc-2.17.so
b772b000-b772c000 rw-p 001b0000 08:05 1312132 /lib/i386-linux-gnu/libc-2.17.so
b772c000-b772f000 rw-p 00000000 00:00 0
b772f000-b774a000 r-xp 00000000 08:05 1312589 /lib/i386-linux-gnu/libgcc_s.so.1
b774a000-b774b000 r--p 0001a000 08:05 1312589 /lib/i386-linux-gnu/libgcc_s.so.1
b774b000-b774c000 rw-p 0001b000 08:05 1312589 /lib/i386-linux-gnu/libgcc_s.so.1
b774c000-b7750000 rw-p 00000000 00:00 0
b7750000-b7751000 r-xp 00000000 00:00 0 [vdso]
b7751000-b7771000 r-xp 00000000 08:05 1312116 /lib/i386-linux-gnu/ld-2.17.so
b7771000-b7772000 r--p 0001f000 08:05 1312116 /lib/i386-linux-gnu/ld-2.17.so
b7772000-b7773000 rw-p 00020000 08:05 1312116 /lib/i386-linux-gnu/ld-2.17.so
bfe93000-bfeb4000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
finally here is the code:
最后这里是代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
//char p[] = "t=quote&k=id&v=10";
char p[] = "t=quote";
char* token;
char* tk;
char* s;
unsigned short int found;
s = strdup(p);
if (s != NULL) {
while ((token = strsep(&s, "&")) != NULL) {
found = 0;
printf("TOKEN: %s\n\n", token);
while ((tk = strsep(&token, "=")) != NULL) {
printf("TK: %s\n\n", tk);
free(tk);
}
free(token);
}
}
free(s);
return 0;
}
Thanks
谢谢
回答by GraphicsMuncher
You're attempting to free something that isn't a pointer to a "freeable" memory address. Just because something is an address doesn't mean that you need to or shouldfree it.
您正在尝试释放不是指向“可释放”内存地址的指针的内容。仅仅因为某物是地址并不意味着您需要或应该释放它。
There are two main types of memory you seem to be confusing - stack memory and heap memory.
您似乎混淆了两种主要类型的内存 - 堆栈内存和堆内存。
Stackmemory lives in the live span of the function. It's temporary space for things that shouldn't grow too big. When you call the function
main, it sets aside some memory for your variables you've declared (p,token, and so on).Heapmemory lives from when you
mallocit to when youfreeit. You can use much more heap memory than you can stack memory. You also need to keep track of it - it's not easy like stack memory!
堆栈内存存在于函数的有效范围内。这是不应该长得太大的东西的临时空间。当您调用该函数时
main,它会为您声明的变量(p、token等)留出一些内存。堆内存从你
malloc它到你free它都存在。您可以使用比堆栈内存多得多的堆内存。您还需要跟踪它 - 它不像堆栈内存那样容易!
You have a few errors:
你有几个错误:
You're trying to free memory that's not heap memory. Don't do that.
You're trying to free the inside of a block of memory. When you have in fact allocated a block of memory, you can only free it from the pointer returned by
malloc. That is to say, only from the beginning of the block. You can't free a portion of the block from the inside.
您正在尝试释放不是堆内存的内存。不要那样做。
您正在尝试释放内存块的内部。当您实际上分配了一块内存时,您只能从 返回的指针中释放它
malloc。也就是说,只能从块的开头。你不能从内部释放块的一部分。
For your bit of code here, you probably want to find a way to copy relevant portion of memory to somewhere else...say another block of memory you've set aside. Or you can modify the original string if you want (hint: char value 0 is the null terminator and tells functions like printf to stop reading the string).
对于这里的一些代码,您可能想找到一种方法将内存的相关部分复制到其他地方……比如说您预留的另一块内存。或者,您可以根据需要修改原始字符串(提示:char 值 0 是空终止符,并告诉 printf 之类的函数停止读取字符串)。
EDIT:The malloc function does allocate heap memory*.
编辑:malloc 函数确实分配了堆内存*。
"9.9.1 The malloc and free Functions
"9.9.1 malloc 和 free 函数
The C standard library provides an explicit allocator known as the malloc package. Programs allocate blocks from the heap by calling the malloc function."
C 标准库提供了一个显式分配器,称为 malloc 包。程序通过调用 malloc 函数从堆中分配块。”
~Computer Systems : A Programmer's Perspective, 2nd Edition, Bryant & O'Hallaron, 2011
~计算机系统:程序员的观点,第 2 版,Bryant 和 O'Hallaron,2011 年
EDIT 2:* The C standard does not, in fact, specify anything about the heap or the stack. However, for anyone learning on a relevant desktop/laptop machine, the distinction is probably unnecessary and confusing if anything, especially if you're learning about how your program is stored and executed. When you find yourself working on something like an AVR microcontroller as H2CO3 has, it is definitely worthwhile to note all the differences, which from my own experience with embedded systems, extend well past memory allocation.
编辑 2:* 事实上,C 标准没有指定关于堆或堆栈的任何内容。但是,对于任何在相关台式机/笔记本电脑上学习的人来说,这种区分可能是不必要的,而且很容易混淆,尤其是当您正在学习如何存储和执行程序时。当您发现自己在像 H2CO3 这样的 AVR 微控制器上工作时,绝对值得注意所有差异,根据我自己在嵌入式系统方面的经验,这些差异远远超出了内存分配。
回答by Dan
From where did you get the idea that you need to free(token)and free(tk)? You don't. strsep()doesn't allocate memory, it only returns pointers inside the original string. Of course, those are not pointers allocated by malloc()(or similar), so free()ing them is undefined behavior. You only need to free(s)when you are done with the entire string.
从你从哪里得到的想法,你需要free(token)和free(tk)?你没有。strsep()不分配内存,它只返回原始字符串内的指针。当然,那些不是由malloc()(或类似的)分配的指针,因此free()它们是未定义的行为。您只需要free(s)在完成整个字符串后。
Also note that you don't need dynamic memory allocation at allin your example. You can avoid strdup()and free()altogether by simply writing char *s = p;.
还要注意的是,你并不需要动态内存分配都在你的榜样。您可以避免strdup()和free()通过简单地写完全char *s = p;。
回答by Tim Pierce
You can't call freeon the pointers returned from strsep. Those are not individually allocated strings, but just pointers into the string sthat you've already allocated. When you're done with saltogether, you should free it, but you do not have to do that with the return values of strsep.
您不能调用free从strsep. 这些不是单独分配的字符串,而只是指向s您已经分配的字符串的指针。当您s完全完成后,您应该释放它,但您不必对strsep.

