2009-12-01 115 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); 
    } 
} 

這隻能當「節點」是在結構的頂部,並只允許你通過螺紋這些結構一個鏈表。

另外,這不允許你釋放特定於該類型結構的任何東西;要做到這一點,你必須設置一個回調函數(通過傳遞它在自由或在一些控制結構),將被調用。我可能會實現一個「彈出」功能,從列表中刪除元素,並釋放整個列表,我會彈出每個元素,然後根據需要釋放它們。