【问题标题】:Why does Valgrind show a memory leak on a calloc statement为什么 Valgrind 在 calloc 语句上显示内存泄漏
【发布时间】:2016-01-02 09:25:33
【问题描述】:

我正在尝试学习一些东西(只是作为一种爱好)并尝试学习使用 Valgrind。然而,这对我来说似乎没有意义。 Valgrind 似乎在说,当我在使用任何东西之前用 calloc 分配字节时,字节会丢失!有人可以解释这里发生了什么以及为什么第二个程序有效吗?我在 Eclipse 中以调试模式编译程序并在调试可执行文件上运行 Valgrind。

这是程序:

1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 int main(void) {
6
7     char* origstr = calloc(37, sizeof(char*));
8     char* newsubstr = calloc(9, sizeof(char*));
9
10    origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";
11
12    strncpy(newsubstr, origstr + 8, 8);
13    printf("SubString is: %s\n", newsubstr);
14
15    free(newsubstr);
16    free(origstr);
17    return 0;
18 }

这是 Valgrind 给我的:

$ valgrind --tool=memcheck --leak-check=full ./test
==25404== Memcheck, a memory error detector
==25404== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25404== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==25404== Command: ./test
==25404== 
SubString is: BrownFox
==25404== Invalid free() / delete / delete[] / realloc()
==25404==    at 0x4C29E90: free (vg_replace_malloc.c:473)
==25404==    by 0x400665: main (test.c:16)
==25404==  Address 0x4006f8 is not stack'd, malloc'd or (recently) free'd
==25404== 
==25404== 
==25404== HEAP SUMMARY:
==25404==     in use at exit: 296 bytes in 1 blocks
==25404==   total heap usage: 2 allocs, 2 frees, 368 bytes allocated
==25404== 
==25404== 296 bytes in 1 blocks are definitely lost in loss record 1 of 1
==25404==    at 0x4C2AD10: calloc (vg_replace_malloc.c:623)
==25404==    by 0x4005FC: main (test.c:7)
==25404== 
==25404== LEAK SUMMARY:
==25404==    definitely lost: 296 bytes in 1 blocks
==25404==    indirectly lost: 0 bytes in 0 blocks
==25404==      possibly lost: 0 bytes in 0 blocks
==25404==    still reachable: 0 bytes in 0 blocks
==25404==         suppressed: 0 bytes in 0 blocks
==25404== 
==25404== For counts of detected and suppressed errors, rerun with: -v
==25404== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

如果我删除了两个 free() 语句,Valgrind 给我的结果如下:

$ valgrind --tool=memcheck --leak-check=full ./test
==25597== Memcheck, a memory error detector
==25597== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25597== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==25597== Command: ./test
==25597== 
SubString is: BrownFox
==25597== 
==25597== HEAP SUMMARY:
==25597==     in use at exit: 368 bytes in 2 blocks
==25597==   total heap usage: 2 allocs, 0 frees, 368 bytes allocated
==25597== 
==25597== 72 bytes in 1 blocks are definitely lost in loss record 1 of 2
==25597==    at 0x4C2AD10: calloc (vg_replace_malloc.c:623)
==25597==    by 0x4005BF: main (test.c:8)
==25597== 
==25597== 296 bytes in 1 blocks are definitely lost in loss record 2 of 2
==25597==    at 0x4C2AD10: calloc (vg_replace_malloc.c:623)
==25597==    by 0x4005AC: main (test.c:7)
==25597== 
==25597== LEAK SUMMARY:
==25597==    definitely lost: 368 bytes in 2 blocks
==25597==    indirectly lost: 0 bytes in 0 blocks
==25597==      possibly lost: 0 bytes in 0 blocks
==25597==    still reachable: 0 bytes in 0 blocks
==25597==         suppressed: 0 bytes in 0 blocks
==25597== 
==25597== For counts of detected and suppressed errors, rerun with: -v
==25597== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

现在,如果我运行这个程序:

1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 int main(void) {
6
7    char* origstr;
8    char* newsubstr = calloc(9, sizeof(char*));
9
10   origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";
11
12   strncpy(newsubstr, origstr + 8, 8);
13   printf("SubString is: %s\n", newsubstr);
14
15   free(newsubstr);
16
17   return 0;
18 }

它表明一切都很好:

$ valgrind --tool=memcheck --leak-check=full ./test
==25862== Memcheck, a memory error detector
==25862== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25862== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==25862== Command: ./test
==25862== 
SubString is: BrownFox
==25862== 
==25862== HEAP SUMMARY:
==25862==     in use at exit: 0 bytes in 0 blocks
==25862==   total heap usage: 1 allocs, 1 frees, 72 bytes allocated
==25862== 
==25862== All heap blocks were freed -- no leaks are possible
==25862== 
==25862== For counts of detected and suppressed errors, rerun with: -v
==25862== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

为什么我不能 calloc(分配) origstr 然后给它一些东西?如果我想分配该变量并在程序过程中将其作为另一个字符串变量中的一部分或使用它来捕获另一个返回字符串的函数的结果怎么办?然后我是否必须像处理 newsubstr 一样处理它?

这让我有点困惑,所以有人可以解释一下它是如何工作的,以便我更好地理解它吗?

【问题讨论】:

  • 您正在丢失(泄漏)calloc()ed 指针以及第 10 行的赋值。
  • origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";NOT设置origstr的内容;它将origstr 设置为指向包含字符串文字的内存的只读部分。你之前分配给origstr的内存丢失了,你不能在字符串文字上调用free

标签: c gcc memory-leaks valgrind


【解决方案1】:
origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";

通过这样做,您将更改为 origstr 指向的内容。在此之后 origstr 不指向由 calloc 分配的内存块。

而你free内存不是由calloc或类似函数分配的,从而导致你的程序出错。

使用strcpy 将字符串复制到origstr -

strcpy(origstr,"TheQuickBrownFoxJumpedOverTheLazyDog");

然后你可以free你的指针origstr

【讨论】:

  • 我正在使用 strncpy(newsubstr, origstr + 8, 8);因为我在那里做的是获取原始字符串的子字符串(即“BrownFox”)。我认为这是最简单的方法(基于我读过的一些东西)。
  • @RavenLX 那么也许你可以有一个字符串文字,但这会使那个常量。而且我认为您在calloc 上很清楚您使用了大量内存。 calloc(37,1); 可以为您完成。
【解决方案2】:

通过将字符串文字分配给origstr,您不要复制字符串,而只是更改origstrs 的值,从而丢失指向calloc 的指针。 freeing origstr 现在会导致未定义的行为。

使用strcpystrncpy 将字符串真正存储在堆上。但实际上将calloc 删除为origstr 就足够了。


注意事项:

  • 正如 @LeeDanielCrocker 在 cmets 中提到的那样,您可能打算为 chars 分配空间,而不是为 char*s 分配空间,从而大大减少了分配内存的大小。您应该将 sizeof(char*) 替换为 sizeof(char) (a.k.a. 1)。

【讨论】:

  • 另外,他分配了太多的内存:一个 37 个字符的字符串只需要 38 个字节(一个额外的用于终止零)。您正在为 37 个字符指针分配内存;每个指针可能长达 8 个字节,这就是您丢失的块如此之大的原因。
  • 字符串本身只有 36 个字符,这就是我使用 37 的原因(包括将有一个空终止符的想法)。我假设空终止符是自动输入的。但也许不是?我现在知道我应该使用 strcpy 所以我应该复制到它“TheQuickBrownFoxJumpedOverTheLazyDog\0”?出于某种原因,这对我来说看起来很奇怪。
  • @RavenLX "" 是一个char[1],因为它只包含一个空字节。 strcpy 自动复制空字节,strncpy 只有在 n 足够大时才会这样做。
  • 我刚刚用 calloc(1, sizeof(char)) 尝试过,但由于空间不足而出现错误。 calloc(9, sizeof(char)) 没有错误。因此,它似乎确实需要您希望字符串中包含的字符数。这是我在网上找到的一个对我来说似乎有意义的示例:tutorialspoint.com/c_standard_library/c_function_calloc.htm(我希望可以发布链接吗?)
  • @RavenLX 是的,当然你需要传递chars 的数量。我的意思是sizeof(char) == 1。我还链接到一个关于该事实的问题。
【解决方案3】:

因为存在内存泄漏。你重新分配指针,它实际上是不正确的 free() 它,因为你有它。

要将内容复制到分配的指针,请使用strcpy()

strcpy(origstr, "TheQuickBrownFoxJumpedOverTheLazyDog");

让我们看看如何:

  1. 你用calloc()请求内存

    origstring = calloc(9, sizeof(char*))
    

    这是错误的,原因有很多

    1. 您正在为9 指针分配空间,而不是9 字符。
    2. 你真的不需要calloc(),因为你会立即覆盖内容,使用malloc()
  2. 你用字符串覆盖指针

    origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";
    

    现在您丢失了对calloc() 之前返回的指针的引用,并且您不可能free() 它,您应该只返回free() 指针由malloc()/calloc()/realloc() 返回。

事实是,你不需要calloc()oristring指针,calloc()/malloc()不是用来让你赋值给一个指针,而是写到由指向的内存指针,或者更好的是,指向一些你可以读/写的内存。

【讨论】:

  • 如果这个“You don't really need calloc()”指的是newsubstr,则OP显示的代码不正确。 0-initialising calloc() 本质上是必要的,因为strncpy() 确实复制0-terminator。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-29
  • 2019-07-17
  • 2019-02-10
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
  • 2011-10-22
相关资源
最近更新 更多