单一功能可以处理两种类型的链表

时间:2013-05-07 19:00:36

标签: c struct linked-list

我有两个链接列表: -

struct Struct_A_s {
int a;
struct  Struct_A_s *next;
}Struct_A;

struct Struct_B_s {
int a;
int b;
int c;
int d;
struct  Struct_B_s *next;
}Struct_B;

我已经有几个在Struct_A上运行的函数。 比如:

“Add_tail(Struct_A *)”,“Remove_tail(Struct_B *)”,“Add_node(Struct_A *,int pos),Add_head等”已经到位。

我的要求是我应该修改现有的函数,以便它们可以在Struct_A和Struct_B上运行。

在C中,有没有办法传递void指针(或类似的东西)并编写一些通用代码来处理Struct_A和Struct_B。 代码大小是一个很大的问题。目前我唯一看到的选项是从头开始为Struct_B重写所有代码(链表操作)。

3 个答案:

答案 0 :(得分:2)

有几种方法可以解决它。我相信其他人比我可能有其他人更有技巧。

  • 选项A:传递一个void指针,然后对数据类型进行某种指示,然后再进行投射。
  • 选项B:将两个指针组合成一个联合并传递它。
  • 选项C:将类型和联合组合成一个结构并传递
  • 选项D:使用一个更加尊重的联盟替代

一些示例代码......

enum DataType { TYPE_1, TYPE_2 };

struct Type1 { ... };
struct Type2 { ... };

union Data
{
    void*         addr;
    struct Type1* type1;
    struct Type2* type2;
}

struct Object
{
    DataType type;
    union Data data;
}

struct Thing
{
    DataType type;
    void* data;
}

void someFunc1( void* data, DataType type )
{
   switch( type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = (struct Type1*)data;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = (struct Type2*)data;
           ...
           break;
       }
   }
}

void someFunc2( union Data* data, DataType type )
{
   switch( type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = data->type1;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = data->type2;
           ...
           break;
       }
   }
}

void someFunc3( struct Object* object )
{
   switch( object->type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = object->data.type1;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = object->data.type2;
           ...
           break;
       }
   }
}


void someFunc4( struct Thing* thing )
{
   switch( thing->type )
   {
       case TYPE_1:
       {
           struct Type1* type1 = (struct Type1*)thing->data;
           ...
           break;
       }
       case TYPE_2:
       {
           struct Type2* type2 = (struct Type2*)thing->data;
           ...
           break;
       }
   }
}

以另一种方式看待......如果你的方法只需要a那么你可以做这样的事情......

void myFunc( int a ) { ... };

void someFunc3( struct Object* object )
{
    myFunc( object->type == TYPE_1 ? object->data.type1->a : object->data.type2->a );
}

更好的是......修改函数以接受对象并仅在底部区分...

void myFunc( struct Object* object )
{
   int* a;

   switch( object->type )
   {
       case TYPE_1:
       {
           a = &object->data.type1->a
           break;
       }
       case TYPE_2:
       {
           a = &object->data.type2->a;
           break;
       }
       default:
       {
           abort();
       }
   }

   // do work with a as though it were passed in as a pointer to int

   if( object->type == TYPE_2 )
   {
      // do additional work with the b, c, d elements, etc.
   }
}

答案 1 :(得分:1)

是的,您可以使用void *,否则请使用Struct_A *Struct_B *。您需要仔细设计API。通常,您最终会像bsearch()qsort()那样使用一个或多个执行结构特定操作的函数指针(在bsearch()和{{1的情况下进行比较) }})。

请注意,遍历链接列表会很困难,因为下一个指针位于结构中的不同偏移处。使用包含下一个指针和实际结构qsort()的固定通用列表结构,您可能会做得更好。

void *

这是'侵入'和'非侵入'列表结构之间的区别。您现有的设计使用侵入式列表结构;修改列表中的结构以包括指针。替代建议的设计是非侵入性的;您可以在不修改结构类型的情况下创建任何结构类型的列表。

答案 2 :(得分:0)

您可以重新定义结构,如下所示。您必须根据类型进行大量的转换,以修改所有早期函数以适用于两者。您需要为两者使用Struct_A *。

struct Struct_A_s {
    int type;
    Struct_A_s *next;
    int a;
}Struct_A;

struct Struct_B_s {
    int type;
    Struct_A *next;
    int a;
    int b;
    int c;
    int d;
}Struct_B;