C free():无效指针
我在自学C语言。我的目标是制作一个C函数,它只需遍历一个查询字符串,并在符号和等号上拆分。我被Valgrind的错误缠住了C free():无效指针,c,pointers,free,valgrind,C,Pointers,Free,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) ==5
==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)
以及回溯:
*** 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)
最后,代码如下:
#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;
}
#包括
#包括
#包括
int main(){
//字符p[]=“t=quote&k=id&v=10”;
字符p[]=“t=quote”;
字符*令牌;
char*tk;
char*s;
找到无符号短整数;
s=标准偏差(p);
如果(s!=NULL){
while((token=strep(&s,“&”)!=NULL){
发现=0;
printf(“令牌:%s\n\n”,令牌);
while((tk=strep(&token,“=”)!=NULL){
printf(“TK:%s\n\n”,TK);
免费(tk);
}
免费(代币);
}
}
免费的;
返回0;
}
谢谢您是从哪里想到需要
免费(代币)
和免费(tk)
?你没有strep()
不分配内存,它只返回原始字符串中的指针。当然,这些指针不是由malloc()
(或类似)分配的,因此free()
对它们进行加密是未定义的行为。当您处理完整个字符串时,只需free
还请注意,在您的示例中,根本不需要动态内存分配。只需编写
char*s=p,就可以避免strdup()
和free()
您不能对从strep
返回的指针调用free
。这些不是单独分配的字符串,而是指向已分配的字符串s
的指针。当您完全使用s
时,您应该释放它,但您不必使用strep
的返回值来释放它。您试图释放的不是指向“可释放”内存地址的指针。仅仅因为某物是一个地址并不意味着你需要或者应该释放它
您似乎混淆了两种主要的内存类型—堆栈内存和堆内存
- 堆栈内存在函数的有效期内。这是一个暂时的空间,用来放不应该长得太大的东西。调用函数
时,它会为您声明的变量留出一些内存(main
,p
,等等)token
- 堆内存从
it到malloc
it。您可以使用比堆栈内存多得多的堆内存。您还需要跟踪它-它不像堆栈内存那样容易free
- 您试图释放的内存不是堆内存。不要那样做
- 您正在尝试释放内存块的内部。当您实际分配了一块内存时,您只能从
返回的指针中释放它。也就是说,仅从块的开头开始。无法从内部释放该块的一部分malloc
编辑2:*事实上,C标准没有指定关于堆或堆栈的任何内容。然而,对于任何在相关的台式机/笔记本电脑上学习的人来说,这种区别可能是不必要的,如果有什么区别的话,那就很容易混淆,尤其是当你正在学习如何存储和执行你的程序时。当您发现自己正在开发像H2CO3那样的AVR微控制器时,绝对值得注意所有的差异,根据我自己对嵌入式系统的经验,这些差异远远超过了内存分配。感谢您的回复。当我取出免费(代币)和免费(tk)时。Valgrind报告我泄漏了8个字节。当我把它们放回去的时候。它报告说我不再泄密了,但程序不会运行。这很有效。我拨打了strdup电话,Valgrind报告没有内存泄漏。非常感谢。@user964491(不客气,但请下次阅读文档!),因为另一个给了我更多的信息和更深入的解释。在我看来,像我这样的初学者会从中受益。尽管如此,我还是很感激您的回答。@user964491但请注意,您接受的答案是错误的(从我对它的评论中可能可以明显看出)…我认为如果这三个答案都保留在这个线程上,他们就会知道。“您试图释放的内存不是堆内存。”-未指定
malloc()
(和co.)是否返回指向的指针“堆内存”、“堆栈内存”“或者别的什么。重要的一点是,它不是由标准分配器函数分配的。@H2CO3不必要的副本?有什么必要?这是一个练习。此外,我还查找了malloc,它似乎确实分配了堆内存。@GrpahicsMuncher不需要,因为分配的内存没有在函数外部使用。就像整个字符串本身不会在函数的作用域之外使用一样。我不知道你是从哪里得到关于malloc()
的想法的,但是尽管“堆”是桌面上现代内存体系结构的一个常见概念,但是在一些系统中malloc()
不使用它(系统也没有),并且