2009-12-01 2 views
0

У меня есть две функции:с функцией слияния помощь

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); 
    } 
} 

Поскольку они очень похожи, я пытался придумать одну функцию, чтобы справиться с ними обоими. Я уже могу просто использовать указатель, чтобы указывать на правильные данные на бесплатную (т. Е. Указывать либо на str из этой структуры, либо на идентификатор структуры THAT), но я не могу понять, как обойти, с какими типами структура обрабатывается поскольку я не могу просто использовать указатель 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

ответ

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_this или free_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); 
    ... 
} 

Если у вас есть плохие чувства по этому поводу, вы правы. Некоторое небольшое изменение в ЭТОМ может привести к взрыву ЭТО и так далее. Не делай этого.

+0

добавил мои определения структуры выше. – user105033

+0

Я дам, что попытка – user105033

+0

на самом деле это на самом деле не помогает мне, поскольку мне нужно иметь возможность перейти к следующему элементу в списке, который действительно является проблемой здесь, а не освобождением данных. – user105033

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 в качестве первого элемента в структуре и назначить str и id как указатели, которые указывают на мем (где вы таНос память). Это позволяет либо всегда освобождать элемент mem, либо освобождать смещение нулевого значения до void*.

+0

Я думаю, что OP хотел избежать повторного использования кода. – hirschhornsalz

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); 
    } 
} 

Это работает только если «узел» находится в верхней части конструкции, и позволяет только нить один связанный списка с помощью этих структур.

Кроме того, это не позволяет вам освобождать что-либо конкретное к этому типу структуры; для этого вам нужно будет настроить функцию обратного вызова (либо путем передачи ее в свободной, либо в некоторой структуре управления), которая будет вызвана. Вместо этого я бы вместо этого воспользовался функцией «pop», которая удаляет элемент из списка, и чтобы освободить весь список, я бы выскочил с каждого элемента, а затем освободил их по мере необходимости.

Смежные вопросы