C free():无效指针

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

我在自学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)
以及回溯:

*** 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
    ,等等)

  • 内存从
    malloc
    it到
    free
    it。您可以使用比堆栈内存多得多的堆内存。您还需要跟踪它-它不像堆栈内存那样容易

您有一些错误:


  • 您试图释放的内存不是堆内存。不要那样做

  • 您正在尝试释放内存块的内部。当您实际分配了一块内存时,您只能从
    malloc
    返回的指针中释放它。也就是说,仅从块的开头开始。无法从内部释放该块的一部分

对于这里的代码,您可能想找到一种方法,将内存的相关部分复制到其他地方……比如说,另一块您预留的内存。如果需要,也可以修改原始字符串(提示:char值0是空终止符,并告诉printf等函数停止读取字符串)

编辑:malloc函数不分配堆内存*

“9.9.1 malloc和free函数

C标准库提供了一个称为malloc包的显式分配器。程序通过调用malloc函数从堆中分配块。”

~Computer Systems:A Programmer's Perspective,第二版,Bryant&O'Hallaron,2011


编辑2:*事实上,C标准没有指定关于堆或堆栈的任何内容。然而,对于任何在相关的台式机/笔记本电脑上学习的人来说,这种区别可能是不必要的,如果有什么区别的话,那就很容易混淆,尤其是当你正在学习如何存储和执行你的程序时。当您发现自己正在开发像H2CO3那样的AVR微控制器时,绝对值得注意所有的差异,根据我自己对嵌入式系统的经验,这些差异远远超过了内存分配。

感谢您的回复。当我取出免费(代币)和免费(tk)时。Valgrind报告我泄漏了8个字节。当我把它们放回去的时候。它报告说我不再泄密了,但程序不会运行。这很有效。我拨打了strdup电话,Valgrind报告没有内存泄漏。非常感谢。@user964491(不客气,但请下次阅读文档!),因为另一个给了我更多的信息和更深入的解释。在我看来,像我这样的初学者会从中受益。尽管如此,我还是很感激您的回答。@user964491但请注意,您接受的答案是错误的(从我对它的评论中可能可以明显看出)…我认为如果这三个答案都保留在这个线程上,他们就会知道。“您试图释放的内存不是堆内存。”-未指定
malloc()
(和co.)是否返回指向的指针“堆内存”、“堆栈内存”“或者别的什么。重要的一点是,它不是由标准分配器函数分配的。@H2CO3不必要的副本?有什么必要?这是一个练习。此外,我还查找了malloc,它似乎确实分配了堆内存。@GrpahicsMuncher不需要,因为分配的内存没有在函数外部使用。就像整个字符串本身不会在函数的作用域之外使用一样。我不知道你是从哪里得到关于
malloc()
的想法的,但是尽管“堆”是桌面上现代内存体系结构的一个常见概念,但是在一些系统中
malloc()
不使用它(系统也没有),并且