数据类型独立堆栈 - C编程

时间:2011-02-21 10:57:27

标签: c types stack

C中的堆栈通常依赖于用于声明它们的数据类型。例如,

int arr[5]; //creates an integer array of size 5 for stack use
char arr[5]; //creates a character array of size 5 for stack use

既限于分别保存整数和字符数据类型,又假定程序员知道在运行时期间生成了什么数据。如果我想要一个可以容纳任何数据类型的堆栈怎么办?

我最初想过将它作为一个联盟来实现,但这种方法不仅困难而且有缺陷。还有其他建议吗?

5 个答案:

答案 0 :(得分:4)

我会使用这样的结构:

struct THolder
{
   int dataType; // this is a value representing the type
   void *val; // this is the value 
};

然后使用THolder数组来存储您的值。

答案 1 :(得分:2)

这实际上只是Pablo Santa Cruz回答的一个变种,但我觉得它看起来更整洁:

typedef enum { integer, real, other } type_t;

typedef struct {
    type_t type;
    union {
        int normal_int;     /* valid when type == integer */
        double large_float; /* valid when type == real */
        void * other;       /* valid when type == other */
    } content;
} stack_data_t;

你仍然需要用某种方式来明确设置每个元素中存储的数据类型,没有简单的方法。

您可以依靠依赖于编译器的 typeof 关键字来查看预处理器魔术,以自动执行此操作,但这可能不会做任何事情,但会破坏可移植性。

答案 2 :(得分:1)

有些人建议void*成员。除了该解决方案之外,我还想提供一种替代方案(假设您的堆栈是堆分配结构的链接列表):

struct stack_node
{
   struct stack_node *next;
   char data[];
};

data[]是C99构造。 data必须是最后一个成员;这利用了我们可以在结构地址之后填充任意数量的事实。如果您使用的是非C99编译器,则可能需要执行一些粗略的技巧,例如将其声明为data[0]

然后你可以这样做:

struct stack_node*
allocate_stack_node(size_t extra_size)
{
   return malloc(sizeof(struct stack_node) + extra_size);
}

/* In some other function... */

struct stack_node *ptr = allocate_stack_node(sizeof(int));

int *p = (int*)ptr->data;

如果这看起来很丑陋和hacky,那就是......但是这里的优点是你仍然可以获得通用的好处,而不会引入更多的间接性(因此ptr->data的访问时间比void*稍快一些{{1}指向与结构不同的位置。)

更新:我还想指出,如果您的机器对int的{​​{1}}的对齐要求不同于char,则我提供的代码示例可能会出现问题。这是一个说明性的例子; YMMV。

答案 3 :(得分:0)

您可以使用宏和“容器”类型将“类型”从每个元素减少到整个容器。 (下面的C99代码)

#define GENERIC_STACK(name, type, typeid, elements) \
  struct name##_stack { \
    unsigned int TypeID; \
    type Data[elements]; \
  } name = { .TypeID = typeid }

当然,您的“TypeID”必须允许您期望的所有可能的约定类型;如果您打算使用整个结构或其他用户定义的类型,则可能会出现问题。

我意识到每个变量都有一个唯一命名的结构类型是奇数,可能没用... oops。

答案 4 :(得分:0)

我创建了一个适用于任何数据类型的库:

    List new_list(int,int);

创建新列表,例如:

    List list=new_list(TYPE_INT,sizeof(int));
    //This will create an list of integers
    Error append(List*,void*);

将一个元素附加到列表中。 *如果你想存储指向列表的指针,请追加两个指针作为参数,不要通过指针传递指针

例如:

    //using the int list from above

      int a=5;
      Error err;
      err=append(&list,&a)

      //for an list of pointers
      List listptr=new_list(TYPE_CUSTOM,sizeof(int*));
      int num=7;
      int *ptr=#

      append(&listptr,ptr);


      //for list of structs
      struct Foo
      {
        int num;
        float *ptr;
      };

      List list=new_list(TYPE_CUSTOM,sizeof(struct Foo));
      struct Foo x;
      x.num=9;
      x.ptr=NULL;

      append(&list,&x);

错误get(List *,int);

获取指定索引的数据。当被叫列表的当前指针将指向数据时。

例如:

    List list=new_list(TYPE_INT,sizeof(int));

    int i;
    for(i=1;i<=10;i++)
      append(&list,&i);

    //This will print the element at index 2
    get(&list,2);
    printf("%d",*(int*)list.current);

错误弹出(List *,int);

来自指定索引的弹出和元素

例如:

      List list=new_list(TYPE_INT,sizeof(int));

      int i;
      for(i=1;i<=10;i++)
        append(&list,&i);

      //element in the index 2 will be deleted, 
      //the current pointer will point to a location that has a copy of the data  

      pop(&list,2);
      printf("%d",*(int*)list.current);

      //To use the list as stack, pop at index list.len-1
      pop(&list,list.len-1);

      //To use the list as queue, pop at index 0
      pop(&list,0);

错误合并(列表,列表);

合并两个相同类型的列表。如果类型不同,将在它返回的Error对象中返回错误消息;

例如:

     //Merge two elements of type int
     //List 2 will come after list 1
     Error err;
     err=merge(&list1,&list2);
    Iterator get_iterator(List*);

获取列表的迭代器。初始化时将有一个指向列表第一个元素的指针。

例如:

    Iterator ite=get_iterator(&list);
    Error next(Iterator*);

获取列表的下一个元素。

例如:

//如何迭代整数列表

      Iterator itr;
      for(itr=get_iterator(&list);  ite.content!=NULL;  next(ite))
        printf("%d",*(int*)ite.content);

https://github.com/malayh/C-List