这段代码存在内存泄漏问题,如何修复?

7
在我的项目中,有一个从整数创建字符串并将其写入文件的方法(使用strcat)。不幸的是,它存在内存泄漏问题。在追踪该泄漏时,我将代码简化为以下形式。但是我似乎无法找到或修复它。这是该代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[] )
{
 char* output = "\0";
 int counter = 5;
  while(counter > 0)
  {
      char buffer[20];
      sprintf(buffer, "%u", counter);
      char* temp;
      temp = malloc((strlen(output) + strlen(buffer) + 1));
      strcpy(temp, buffer);
      strcat(temp, output);
      char* oldmemory = output;
      output = temp;
      free(oldmemory);
      counter--;
  }
printf("output: %s\n", output);
free(output);
return 0;
}

Valgrind返回:

==7125== Memcheck, a memory error detector
==7125== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==7125== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==7125== Command: ./foo
==7125== Parent PID: 4455
==7125== 
==7125== Invalid free() / delete / delete[]
==7125==    at 0x4024B3A: free (vg_replace_malloc.c:366)
==7125==    by 0x8048662: main (foo.c:20)
==7125==  Address 0x8048780 is not stack'd, malloc'd or (recently) free'd
==7125== 
==7125== 
==7125== HEAP SUMMARY:
==7125==     in use at exit: 0 bytes in 0 blocks
==7125==   total heap usage: 5 allocs, 6 frees, 20 bytes allocated
==7125== 
==7125== All heap blocks were freed -- no leaks are possible
==7125== 
==7125== For counts of detected and suppressed errors, rerun with: -v
==7125== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 15 from 8)

内存泄漏在哪里,我该如何解决?

4个回答

9
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[] )
{
 char* output = "\0";

字符串字面量会自动以 '\0' 结尾,您无需手动添加。
 int counter = 5;
  while(counter > 0)
  {
      char buffer[20];
      sprintf(buffer, "%u", counter);
      char* temp;
      temp = malloc((strlen(output) + strlen(buffer) + 1));
      strcpy(temp, buffer);
      strcat(temp, output);
      char* oldmemory = output;
      output = temp;
      free(oldmemory);

第一次调用free()时,它释放的是输出的初始值,该值是指向字符串文字"\0"的指针。对于除从*alloc()NULL返回的有效指针之外的任何内容调用free()都是未定义的行为。
      counter--;
  }
printf("output: %s\n", output);
free(output);
return 0;
}

Valgrind报告:

==7125== Invalid free() / delete / delete[]
==7125==    at 0x4024B3A: free (vg_replace_malloc.c:366)
==7125==    by 0x8048662: main (foo.c:20)
==7125==  Address 0x8048780 is not stack'd, malloc'd or (recently) free'd

这不是内存泄漏,而是无效的free()

4

你的代码出现了问题。第一次经过时,你将oldmemory设置为指向尚未在堆上分配的内存的输出。稍后,你试图释放这个内存。这会生成关于释放未通过malloc分配的内存的valgrind错误。因此,你最初分配的内存永远不会被释放。


我认为他/她知道它已经坏了,没有必要对此表现粗鲁。 - SSH This
什么鬼?我写的话怎么会是粗鲁的呢?我觉得你的敏感度有点太高了。或者我指出这一点是不礼貌的吗?也许你已经知道了。 - sizzzzlerz
不用随意给我的问题点踩,婊子。 - SSH This

3

您的应用程序崩溃了,试图释放("\0")。请注意,如果您想要一个空字符串,""就足够了,"\0"实际上是字符串\0\0。

不要使用malloc和strcpy,看一下realloc,它可以更好地完成你想要的所有操作 :) 但是最好向前构建你的字符串(counter = 0; counter < 5; count++),而不是向后。


3
除了重新分配内存失败会返回NULL,所以在使用p = realloc(p, new_size)时要注意内存泄漏的情况。 - Roger Lipscombe
@Roger:realloc 失败可能意味着程序必须优雅地终止。不要认为内存泄漏对此有太大的影响。 - Jens Gustedt
使用realloc时,很容易捕获潜在的泄漏,只需在调用过程中保留原始指针的副本,以便可以释放它。或者,假设失败的realloc意味着世界末日,直接退出即可。我个人喜欢使用assert()进行检查,因为它确保退出是一个显著的失败。 - RBerteig

1
如果您想使用此算法,则应使用malloc为输出指向的初始空间分配内存,如下所示:

 char *output = malloc(1);
 if(!output) { /* handle error */ }
 output[0] = '\0';
 ... rest of code as is ...

字符串字面量不是使用malloc分配的,因此无法进行free操作,这就是您遇到问题的根源。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接