2013-07-19 31 views
2

如果我有几个链接结构用C,如:是否有可能一般免费链表的记忆用C

struct structA { 
    int a; 
    int b; 
    struct structA *next; 
} 

struct structB { 
    char a; 
    int b; 
    struct structB *next; 
} 

,我动态分配内存是这样的:

struct structA *mystructA = (struct structA*) malloc(sizeof(struct structA)); 
mystructA->next = (struct structA*) malloc(sizeof(struct structA)); 

struct structB *mystructB = (struct structB*) malloc(sizeof(struct structB)); 
mystructB->next = (struct structB*) malloc(sizeof(struct structB)); 

做我总是必须为像这样的每种结构类型释放它:

struct structA *p, *pNext; 
for (p = mystructA; p != NULL; p = pNext) { 
    pNext = p->next; 
    free(p); 
} 

struct structB *p, *pNext; 
for (p = mystructB; p != NULL; p = pNext) { 
    pNext = p->next; 
    free(p); 
} 

或者是否有任何通用解决方案?我假设没有其他解决方案,因为free()过程必须知道有多少个字节必须被释放。但也许我错了,有人可以更好地教我。

+0

你必须一个接一个地释放结构。 – 2013-07-19 12:58:38

回答

5

的标准方法是给使“列表部分”的第一个元素的结构的,并让每一个衍生结构共享这个相同的前缀。由于第一个元素保证放置在零点偏移处,所以这个工作很有用。 例片段:

#include <stdlib.h> 
#include <string.h> 

struct list { 
    struct list *next; 
    }; 
struct structA { 
    struct list list; 
    int a; 
    int b; 
    }; 

struct structB { 
    struct list list; 
    char a; 
    int b; 
    }; 

void *create_any(size_t size) 
{ 
    struct list *this; 
    this = malloc (size); 
    if (!this) return this; 
    memset(this, 0, size); 
    this->next = NULL; 
    return this; 
} 


void free_all_any(struct list **lp) { 
    struct list *tmp; 
    while ((tmp = *lp)) { *lp = tmp->next; free(tmp); } 
} 
#define CREATE_A() create_any(sizeof(struct structA)) 
#define CREATE_B() create_any(sizeof(struct structB)) 
#define FREE_A(pp) free_any((struct list **) pp) 
#define FREE_B(pp) free_any((struct list **) pp) 

int main(void) 
{ 
struct structA *ap; 
struct structB *bp; 

ap = CREATE_A(); 
bp = CREATE_B(); 

// some code here ... 

FREE_A(&ap); 
FREE_B(&bp); 

return 0; 
} 

这是或多或少在Linux内核所使用的方法,但是更大量预处理神奇用于那里。 (显然,那里没有malloc)

+0

为什么你定义宏,为什么你调用memset()'? – arminb

+0

主要作为例证。宏隐藏了模型和sizeof。 memset只是将完整的对象设置为零。(NULL不一定表示为全零,因此无论如何都必须单独完成) – wildplasser

+0

好吧,现在一切都清楚了,谢谢!非常好的通用解决方案,但可能在第一次看起来很混乱(因为宏和memset()':-) – arminb

2

由于free()接受指针void *structAstructB都具有相同的大小,可以通过这两个指针类型。

然而,这并不是最优雅的。你应该考虑以下问题:

为什么你有两个不同的结构与相同的成员?

为什么你没有通用列表项目类型,如下列:

struct list_node { 
    void *data; 
    struct list_node *next; 
} 
+2

他们有不同的成员,也不一样的大小,仔细看看我提供的代码。 structA有2个'int's; structB有1个字符,1个int – arminb

2

其实,这是一个非常有趣的问题。该部分是真实的,你必须free()每个struct型独立,因为他们已经malloc()单独-ed,并且每个存储块已经为该type.Also明确分配,在某些系统上charint有不同的存储大小,但你可以尝试像Phillip提供的解决方案。欲了解更多信息,请阅读doom memory engine。在旁注中,please don't cast malloc() in C。有趣的是,一旦程序终止,操作系统将回收内存,所以如果你只在程序结束时释放结构,当你不再需要它们时,可能不需要它们

+0

“操作系统将回收内存”只是要小心这个声明 - 它不是*要求*操作系统这样做,但它是不太可能不会。 –

+0

同意,但主流操作系统的Windows和Linux的,所以我说:) –