2009-12-01 113 views
0

我有两个功能:c函数合并帮助

void free_this(THIS *this) 
{ 
    THIS *this_tmp; 
    while (this_tmp = this) 
    { 
     if (this->str) 
      free(this->str); 
     this = this_tmp->next; 
     free(this_tmp); 
    } 
} 

void free_that(THAT *that) 
{ 
    THAT *that_tmp; 
    while (that_tmp = that) 
    { 
     if (that->id) 
      free(that->id); 
     that = that_tmp->next; 
     free(that_tmp); 
    } 
} 

因为他们都非常相似,我试图想出一个函数来处理他们。我已经可以使用一个指针指向正确的数据以释放(例如指向THIS结构中的任何一个str或THAT结构的id),但我无法弄清楚如何解决正在处理的结构类型因为我无法使用void指针,因为void *没有名为'NEXT'的成员。

任何想法?

也许我应该把两个结构THIS和THAT合成一个结果呢?他们是:

typedef struct this { 
    struct this *next; 
    char *str; 
} THIS; 

typedef struct that { 
    struct that *next; 
    char *id; 
    unsigned short result; 
    OTHERTHING *optr; 
} THAT; 

我可能可能使用offsetof函数以某种方式获取下一个元素?

+2

如果您使用的是C++编译器,那么这就是C++模板派上用场的地方。 – DaMacc 2009-12-01 17:06:36

回答

2

你可以用void *和field偏移来实现自由函数。未经测试:

void free_either(void *either, size_t other_offset, size_t next_offset) 
{ 
    void *either_tmp; 
    while (either_tmp = either) 
    { 
     free((char *)either + other_offset); 

     either_tmp = (char *)either + next_offset; 
     free(either); 
    } 
} 

free_either(this,offsetof(THIS,str),offsetof(THIS,next)); 
free_either(that,offsetof(THAT,id),offsetof(THAT,next)); 

然后,您可以创建宏,以取代旧free_thisfree_that功能。

1

取决于这个和那个的确切结构。如果它们非常相似,特别是如果str和id具有相同的偏移量,则可以将它们合并到一个对象中。

structure THIS { 
    void* str; 
    ... 
}; 

structure THIS { 
    void* id;  /* is at the same offset as str */ 
    ... 
}; 

union THAS { 
    structure THIS this; 
    structure THAT that; 
    void* pointer; /* at the same offset as str and id */ 
}; 

/* and use it like */ 
void free_thas(THAS* thas) { 
    free(thas->pointer); 
    ... 
} 

如果你对此有不好的感觉,那么你是对的。 THIS的一些小变化可能会导致爆炸等。不要这样做。

+0

在上面添加了我的结构定义。 – user105033 2009-12-01 16:51:41

+0

我会试试 – user105033 2009-12-01 16:52:52

+0

实际上这并不能真正帮助我,因为我需要能够到达列表中的下一个元素,这是真正的问题,而不是释放数据。 – user105033 2009-12-01 17:39:49

0

有更多奇特的方式来做你想做的事 - 但下面的例子就足够了。

void free_that(void *mem, int type) 
{ 
    switch(type) { 
     case THIS_FLAG: { 
     THIS *this = (THIS*)mem; 

     for(this; this->str != NULL; this = this->next) 
      (void)free(this->str); 

     break; 
     } 

     case THAT_FLAG: { 
     THAT *that = (THAT*)mem; 

     for(that; that->id != NULL; that = that->next) 
      (void)free(that->id); 
     } 

     default: { 
     (void)free(mem); 
     } 
    } 

    return; 
} 

更奇特的方式将是一个void *mem添加为结构的第一个元素,并指定strid为指向MEM(你malloc的内存)指针。这样做可以让您始终释放mem元素或将零点偏移量释放到void*

+0

我认为OP希望避免重复使用代码。 – hirschhornsalz 2009-12-01 16:54:13

1

这里有两种不同的单向链接列表类型。你可以解决这个问题只创建一个单一类型:

typedef struct node { 
    struct node *next; 
    void *data; 
} NODE; 

,并有data点到任何一个char*(或只是一个char)或从THAT三个数据字段的另一个结构。当然你必须记得free()你的free_node()函数中的数据。

1

还有一种方法是通过一些原始继承:

struct node { 
    struct node *next; 
} 

struct this { 
    struct node mynode; 
    ... 
} 

struct that { 
    struct node mynode; 
    ... 
} 

free_any(struct node *this) 
{ 
    struct node *this_tmp; 
    while (this_tmp = this) 
    { 
     this = this_tmp->next; 
     free(this_tmp); 
    } 
} 

这只能当“节点”是在结构的顶部,并只允许你通过螺纹这些结构一个链表。

另外,这不允许你释放特定于该类型结构的任何东西;要做到这一点,你必须设置一个回调函数(通过传递它在自由或在一些控制结构),将被调用。我可能会实现一个“弹出”功能,从列表中删除元素,并释放整个列表,我会弹出每个元素,然后根据需要释放它们。