C 在发生故障时释放所有分配的内存

C 在发生故障时释放所有分配的内存,c,memory,memory-management,malloc,C,Memory,Memory Management,Malloc,我正在做一个C项目(学校作业)。其中一个要求是,如果出现malloc()故障,程序必须free()所有分配的内存并exit() 考虑这样一种情况,函数a()构造一个链表,并在每次迭代中调用另一个函数B()。现在,如果malloc故障发生在B(),它必须释放它分配的内存,但是函数a()也应该这样做 当函数调用树大于两个时,事情变得相当复杂 在我以前的项目中,我使用了一个标志来通知malloc()失败-如果一个函数使用了另一个可能使用malloc()的函数,它必须立即检查标志。它起作用了,但代码有点

我正在做一个C项目(学校作业)。其中一个要求是,如果出现
malloc()
故障,程序必须
free()
所有分配的内存并
exit()

考虑这样一种情况,函数
a()
构造一个链表,并在每次迭代中调用另一个函数
B()
。现在,如果malloc故障发生在
B()
,它必须
释放它分配的内存,但是函数
a()
也应该这样做

当函数调用树大于两个时,事情变得相当复杂

在我以前的项目中,我使用了一个标志来通知malloc()失败-如果一个函数使用了另一个可能使用
malloc()
的函数,它必须立即检查标志。它起作用了,但代码有点乱

有解决这个问题的好办法吗?
当然,对于“真正的”应用程序,所有内存都是由操作系统分配的,但我想这是一种教学需求。

是的。最好的(也是传统的)方法是将每个指针值初始化为零。然后在malloc()赋值期间设置它。例如:myPtr=malloc(10)

如果发生故障,它将为零,您可以检查它。最后,当您开始释放时,在调用free()之前,始终要检查指针值:


不需要额外的标志。

您可以查看
atexit()
函数,以注册程序终止时将执行的代码。这样的代码就可以检查是否有任何东西需要
free()
d

请注意,
atexit()
无法取消注册。因此,您需要确保每个清理函数只注册一次,并且当没有任何东西需要清理时,它会做正确的事情

#include <stdlib.h>
#include <stdio.h>

int *ptr1;
char *ptr2;
int clean1_registered, clean2_registered;

void clean1(void)
{
    printf("clean1 called\n");
    if (ptr1) {
        free(ptr1);
        ptr1 = NULL;
    }
}

void clean2(void)
{
    printf("clean2 called\n");
    if (ptr2) {
        free(ptr2);
        ptr2 = NULL;
    }
}

void B(void)
{
    ptr2 = malloc(100);
    if (!clean2_registered) {
        atexit(clean2);
    }
}

void A(void)
{
    ptr1 = malloc(100 * sizeof(int));
    if (!clean1_registered) {
        atexit(clean1);
    }
    B();
}

int main(int argc, char **argv)
{
    A();
}
#包括
#包括
int*ptr1;
char*ptr2;
int clean1_注册,clean2_注册;
空隙清理1(空隙)
{
printf(“clean1调用\n”);
if(ptr1){
免费(ptr1);
ptr1=NULL;
}
}
空隙清理2(空隙)
{
printf(“clean2调用\n”);
如果(ptr2){
免费(ptr2);
ptr2=NULL;
}
}
无效B(无效)
{
ptr2=malloc(100);
如果(!clean2_已注册){
atexit(清洁2);
}
}
作废A(作废)
{
ptr1=malloc(100*sizeof(int));
如果(!clean1_已注册){
atexit(清洁1);
}
B();
}
int main(int argc,字符**argv)
{
A();
}

您是否在检查错误或处理错误时遇到问题?如果你想知道捕捉它们的信息,请使用donjuedo的建议

有关在发生错误时释放内存的想法,请尝试以下两种方法之一:

1) 对于单向链接列表,请保留一个指向列表标题的特殊指针。在级联自由函数中,从head开始,捕获temp变量中的下一个指针,释放head,使用temp指针移动到列表中的下一个结构,然后重复该过程,直到下一个指针==0


2) 对于双向链接列表(我的首选),您不需要保留指向列表头部的特殊指针。假设您仍然处于尾部,只需将上一个指针捕获到一个临时变量中,释放尾部,使用临时指针向后移动,然后重复此过程,直到上一个指针==0

我认为最简单的方法是创建一个自定义分配器(正如有人在已删除的帖子中所指出的),以跟踪您的所有分配,然后做一个自定义的deallocator,将它们用于所有堆内存需求

如果malloc失败,您可以轻松获得以前分配的块列表

e、 g。 (您需要重做此操作,因为它无效,应进行优化,但显示了原理并仅显示了直观的编译)

typedef结构
{
已分配内存的void*pMemory;/**/
大小\u t size;/*以便更好地调试*/
}记忆块;
#定义MAXBLOCKS 1000
MemoryBlock myheap[MAXBLOCKS];//全球so零:ed
静态整型块=0;
void*myalloc(大小)
{
静态整型块=0;
//您应该检查vs MAXBLOCKS
myheap[block].pMemory=malloc(大小);
myheap[block]。大小=大小;
//检查它是否失败。
if(myheap[block].pMemory==NULL)
{
对于(int i=0;i
您在寻找伪代码类型的答案吗?一点也不。我要求的是一种方法\想法。我不确定为什么我会得到这些否决票。从每个函数返回成功/失败值,但仅在顶层返回
exit
。否决票是因为不太清楚您到底想要什么答案。释放前无需检查指针,如果它为null,则不会发生任何情况并非所有的实现都那么可靠,尤其是嵌入式库。它符合C标准。如果未实现,则是编译器中的错误。否则,它将破坏成吨的遗留代码段。调试辅助工具跟踪分配和取消分配,然后能够在最后或在任何“保守”处理之后提供泄漏报告(应为净零分配)。它们通常以一个链表或哈希表结束,而不是数组。但对于新手练习,我可以接受这个。简言之,在分配的堆中循环查找
免费的
项目在几乎任何实际应用中都会慢得令人无法接受。@DanAllen是的,这当然无效,但我的目的不是解决他的学校作业,只是向他指出一个方向。我知道,我的评论并不是要批评他。我只是在指出你的“玩具”解决方案的用武之地。
#include <stdlib.h>
#include <stdio.h>

int *ptr1;
char *ptr2;
int clean1_registered, clean2_registered;

void clean1(void)
{
    printf("clean1 called\n");
    if (ptr1) {
        free(ptr1);
        ptr1 = NULL;
    }
}

void clean2(void)
{
    printf("clean2 called\n");
    if (ptr2) {
        free(ptr2);
        ptr2 = NULL;
    }
}

void B(void)
{
    ptr2 = malloc(100);
    if (!clean2_registered) {
        atexit(clean2);
    }
}

void A(void)
{
    ptr1 = malloc(100 * sizeof(int));
    if (!clean1_registered) {
        atexit(clean1);
    }
    B();
}

int main(int argc, char **argv)
{
    A();
}
typedef struct
{
  void* pMemory; /* for the allocated memory */
  size_t size;   /* for better debugging */

} MemoryBlock;

#define MAXBLOCKS 1000

MemoryBlock myheap[MAXBLOCKS]; // global so zero:ed
static int block = 0;

void* myalloc(size_t size)
{
   static int block = 0;

   // you should check vs MAXBLOCKS 

   myheap[block].pMemory = malloc(size); 
   myheap[block].size = size;   

   // check if it failed.
   if ( myheap[block].pMemory == NULL )
   {
      for (int i = 0; i < block; ++i)
      {
         myfree(myheap[i].pMemory);
      }
      fprintf( stderr, "out of memory\n");
      exit(EXIT_FAILURE);
   }
   else
   {
     return myheap[block++].pMemory;
   }
}

void myfree(void* p)
{
   for (int i = 0; i < block; ++i)
   {
      if ( p == myheap[i].pMemory )
      {
         free(myheap[i].pMemory);
         myheap[i].pMemory = NULL;
         return; 
      }
   }
}