C 内存管理错误?

C 内存管理错误?,c,memory-management,free,C,Memory Management,Free,这是我的C程序: #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <ctype.h> #define FALSE 0 #define TRUE 1 typedef struct _Frag { struct _Frag *next; char *seq; int x1; int length; }

这是我的C程序:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define FALSE 0
#define TRUE 1

typedef struct _Frag
{
  struct _Frag *next;
  char *seq;
  int x1;
  int length;
} Frag;

typedef struct _Fragment
{
  int type;
  Frag *frag_list;
} Fragment;

static void
free_frags (Fragment * frags, int len)
{
  int i;
  for (i = 0; i < len; i++)
    {
      Fragment *fragment = &frags[i];
      Frag *current = fragment->frag_list;

      while (current != NULL)
    {
      free (current->seq);
      fragment->frag_list = current->next;
      free (current);
      current = fragment->frag_list;
    }

      /* to do : free fragment */
      free (fragment);
      fragment = NULL;
    }
  free (frags);
}

int
main ()
{
  Fragment *frags = (Fragment *) malloc (10 * sizeof (Fragment));
  int i, j;
  for (i = 0; i < 10; i++)
    {
      Fragment *fragment = &frags[i];
      fragment->frag_list = (Frag *) malloc (1 * sizeof (Frag));
      Frag *frag = fragment->frag_list;
      frag->seq = malloc (6 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next = (Frag *) malloc (1 * sizeof (Frag));
      frag = frag->next;
      frag->seq = malloc (6 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next=NULL;
    }
  free_frags (frags, 10);
  return 0;
}
valgrind消息如下所示:

==2832== Memcheck, a memory error detector.
==2832== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==2832== Using LibVEX rev 1884, a library for dynamic binary translation.
==2832== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==2832== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==2832== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==2832== For more details, rerun with: -v
==2832== 
==2832== Invalid read of size 4
==2832==    at 0x8048442: free_frags (main.c:31)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b034 is 12 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid write of size 4
==2832==    at 0x8048460: free_frags (main.c:36)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b034 is 12 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid read of size 4
==2832==    at 0x8048471: free_frags (main.c:38)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b034 is 12 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid free() / delete / delete[]
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b030 is 8 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid free() / delete / delete[]
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x80484A5: free_frags (main.c:45)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b028 is 0 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== ERROR SUMMARY: 55 errors from 5 contexts (suppressed: 13 from 1)
==2832== malloc/free: in use at exit: 0 bytes in 0 blocks.
==2832== malloc/free: 41 allocs, 51 frees, 520 bytes allocated.
==2832== For counts of detected errors, rerun with: -v
==2832== All heap blocks were freed -- no leaks are possible.

请帮助我修复它们,谢谢。

如果要将Frag.next指针用作哨兵(在free_frags()中),则需要在代码中的某个位置将其设置为NULL


另外,要小心-您正在使用malloc()为Frag.seq分配5个字符,并且正在该空间中复制一个以非空结尾的字符串。

您正在引用一个不属于您的内存地址。这是在free_frags()函数中发生的,特别是在第41行free(fragment)

您正试图释放数组的中间部分

Fragment *fragment = &frags[i];
...
...
/* to do : free fragment */
free (fragment);
fragment = NULL;

您将
frag_list
视为
frag
指针的链接列表,但在创建列表时,您没有添加终止符

试试这个:

int
main ()
{
  Fragment *frags = (Fragment *) malloc (10 * sizeof (Fragment));
  int i, j;
  for (i = 0; i < 10; i++)
    {
      Fragment *fragment = &frags[i];
      fragment->frag_list = (Frag *) malloc (1 * sizeof (Frag));
      Frag *frag = fragment->frag_list;
      frag->seq = malloc (5 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next = (Frag *) malloc (1 * sizeof (Frag));
      frag = frag->next;
      frag->seq = malloc (5 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next = NULL; // <--------------------- This is what you need to do
    }
  free_frags (frags, 10);
  return 0;
}
int
主要()
{
片段*frags=(片段*)malloc(10*sizeof(片段));
int i,j;
对于(i=0;i<10;i++)
{
片段*片段=&frags[i];
碎片->碎片列表=(碎片*)malloc(1*sizeof(碎片));
碎片*碎片=碎片->碎片列表;
frag->seq=malloc(5*sizeof(char));
strcpy(框架->序号,“55555”);
frag->next=(frag*)malloc(1*sizeof(frag));
frag=frag->next;
frag->seq=malloc(5*sizeof(char));
strcpy(框架->序号,“55555”);

frag->next=NULL;//这些行似乎有缓冲区溢出

因为字符串
55555
还将包含一个终止零字符,该字符也会写入分配的5字节之外的内存中

相反,您可以使用
strdup()
来分配和复制字符串

  frag->seq = strdup("55555");

你有很多问题

在这里,为5个字符分配空间,但复制6个字符(字符串末尾的nul终止符也需要一个空间):

在同一点上,您从未在分配的第二个
frag
中设置
frag->next
。您需要将其设置为
NULL
,以便
free\u frag
例程中的
while
循环不会跑掉

第三个问题是:

  /* to do : free fragment */
  free (fragment);

您可以释放
片段
,但它不是从
malloc
接收到的整个块-它只是您一次性分配的10个片段的单个块中的一个。稍后的
免费(frags)
正确地释放该块,因此您只需删除该错误行。

尝试使用Valgrind的Memcheck-它将显示您失败的地方。注意:如果您要键入定义结构,那么命名结构绝对没有意义。它只是用一个无意义的名称将代码弄乱,让所有阅读代码的人都无法阅读“嗯……我想知道这个名字是用来干什么的?"然后在找不到名称时感到困惑。是的,我正在投影,但这并不意味着我错了。@unwind:你错了。如果你需要在结构体本身中使用结构定义,那么你需要一个名称和一个typedef。这正是他对_Frag/Frag struct所做的。@unwind-第一个结构是一个链接的list、 所以他必须给它命名,以便它有一个自身的引用。第二个,不太多。所以Valgrind在你的代码中发现了许多内存错误,告诉你问题发生的确切位置。我想你现在可以结束你的问题,开始修复你的代码。不要指望其他人为你修复它-这是你的决定。我随着你的改变而改变但是你的提示是对的,我忘了。谢谢你。这并没有直接或间接地造成他的问题,但确实很危险。
strdup()
是非标准的(除非POSIX对你足够好),虽然如果你的操作系统没有提供,编写自己的代码是相当容易的。作为一个随机注释,为什么要获取指针解引用的地址?为什么不使用指针算术?我认为
frags+I
&frags[I]
更清晰一些,但这只是我的观点。我个人认为
&frags[I]
frags+i
更清晰,因为第一个显然是一个指向数组元素的指针,只需查看它即可。如果不检查其他代码行,
frags+i
可能只是一个算术表达式。在我看来,理解表达式所需的上下文越少越好。(想想提问者的同事,他刚刚被告知,“今天下午之前去修复那个bug。”)+1,这将其他人的答案合并为一个答案。我相信它涵盖了你需要的一切。出于对所有神圣事物的热爱,请使用strdup()用于制作动态分配的字符串副本-这样您的第一个错误就不会再次发生。有关更多信息,请参阅此处:
  frag->seq = strdup("55555");
  frag->seq = malloc (5 * sizeof (char));
  strcpy (frag->seq, "55555");
  /* to do : free fragment */
  free (fragment);