C free():指针无效

Dan*_*Dan 16 c free valgrind pointers

我正在自学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)
Run Code Online (Sandbox Code Playgroud)

和回溯:

*** 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)
Run Code Online (Sandbox Code Playgroud)

最后这里是代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

谢谢

Gra*_*her 35

你试图释放一些不是指向"可用"内存地址的指针.仅仅因为某些东西是地址并不意味着你需要或应该释放它.

你似乎有两种主要的内存类型 - 堆栈内存和堆内存.

  • 堆栈内存存在于函数的实时范围内.这是不应该变得太大的事物的临时空间.当你调用该函数时main,它会为你声明的变量(p,token等等)留出一些内存.

  • 堆积记忆的存在时间从你mallocfree它的时候.您可以使用比堆栈内存更多的堆内存.你还需要跟踪它 - 它就像堆栈内存一样容易!

你有一些错误:

  • 你试图释放不是堆内存的内存.不要那样做.

  • 你试图释放一块内存.实际上你已经分配了一块内存,你只能从返回的指针中释放它malloc.也就是说,仅从块的开头.你不能从内部释放一部分块.

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

编辑: malloc函数确实分配堆内存*.

"9.9.1 malloc和自由函数

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

〜计算机系统:程序员的观点,第2版,Bryant&O'Hallaron,2011

编辑2:*事实上,C标准没有指定关于堆或堆栈的任何内容.但是,对于在相关台式机/笔记本电脑上学习的人来说,这种区别可能是不必要的,如果有的话会让人感到困惑,特别是如果你正在学习如何存储和执行你的程序.当您发现自己正在像H2CO3那样使用AVR微控制器之类的东西时,绝对值得注意的是,根据我自己的嵌入式系统经验,这些差异远远超出了内存分配.

  • “您正在尝试释放不是堆内存的内存。” - 未指定 `malloc()`(和 co.)是否返回指向“堆内存”、“堆栈内存”或其他任何内容的指针。重要的一点是它不是由标准分配器函数分配的。 (2认同)
  • 不必要的副本是不必要的,而且术语也很困难。在大多数系统上,`malloc()`确实会返回“堆内存”,但是[标准](http://web.archive.org/web/20050207010641/http://dev.unicals.com/papers/c99 -draft.html#7.20.3.3)对此只字未提,因此确实可能存在没有“堆”的系统。OTOH,在这些系统上,我们可以增强“堆”的定义,使其表示“malloc()”从中获取内存的内存区域,一切都会好起来的。 (2认同)

小智 11

你是从哪里得到你需要的想法free(token)free(tk)?你没有.strsep()不分配内存,它只返回原始字符串内的指针.当然,那些不是由malloc()(或类似的)分配的指针,因此free()它们是未定义的行为.您只需要free(s)完成整个字符串.

还要注意的是,你并不需要动态内存分配在你的榜样.你可以通过简单的写作来避免strdup()free()完全char *s = p;.