回 帖 发 新 帖 刷新版面

主题:如果在一个程序中用到不同数据类型的栈,该怎么解决

最近学习当中,有个问题搞不懂,求大神指点。建了个栈,为了重复使用,将数据类型重定义为为typedef char A        但问题来了,程序中要是栈的数据类型为double,这该怎么办,应该不能typedef double A吧,请问有没有取消类型重定义的方法,类型重定义的作用范围是什么,我想过用文件包含来解决,不知道行不行,求大神帮个忙啊,急用,谢谢

回复列表 (共11个回复)

沙发

用心回贴是美德!支持楼主!
-------------------------------
汕头神州数码stszsm.com 江苏钻井csslsb.com 江苏冷风机csslsb.com

板凳

这个个人用到的不多,不太熟悉,不过这么可行么?

#define TYPE_CHAR    //在此定义类型。char or double ,blah blah、、

#if defined TYPE_CHAR  //这段可以用一个.h文件来写吧? 
typedef char A;
#elif  defined TYPE_DOUBLE
typedef double A;
                     //for other types
#endif

3 楼

把问题改改吧,想在同一程序中使用不同数据类型的栈,怎么办?栈是这样定义的
typedef struct{
        char *stack;
        int top;
}SqStack;
它的一系列操作,如入栈,出栈……当然都是char的,但要用到double的栈,又不想将所有的函数重抄一遍,该怎么办,求解决办法,谢谢了

4 楼

这样呢?
#define TYPE_CHAR    //在此定义类型。char or double ,blah blah、、

#if defined TYPE_CHAR  //这段可以用一个.h文件来写吧? 
typedef char A;
#elif  defined TYPE_DOUBLE
typedef double A;
                     //for other types
#endif
typedef struct  _SqStack
{
   A *stack;
   int top;
}SqStack;

5 楼

用指针来引用数据,应该可以勉强实现吧。
typedef void * MyData;
#define MYDATA(x) ((MyData)(x))

typedef struct _MyStack  MyStack;
struct _MyStack
{
};

MyStack * mystack_new ();
MyStack * mystack_push (MyStack *, MyData);
MyData    mystack_pop (MyStack *);

void foo_int (void)
{
  MyStack * stack = mystack_new ();
  int  d1, d2;
  
  mystack_push (stack, MYDATA(1));
  mystack_push (stack, MYDATA(2));
  /* 有些64位编译器不能直接把指针转换成int类型,因为
     int为32位, 而指针位64位 */
  d1 = (int) (unsigned long) mystack_pop (stack);
  d2 = (int) (unsigned long) mystack_pop (stack);
}

void foo_double (void)
{
  double xs[] = {1.0, 2.0, 3.0};
  MyStack * stack = mystack_new ();
  double d1, d2;

  mystack_push (stack, MYDATA(&xs[0]));
  mystack_push (stack, MYDATA(&xs[1]));
  d1 = * (double *) mystack_pop (stack);
  d2 = * (double *) mystack_pop (stack);
}

void foo_string (void)
{
  MyStack * stack = mystack_new ();
  const char * d1, * d2;

  mystack_push (stack, MYDATA("string1"));
  mystack_push (stack, MYDATA("string2"));
  d1 = (const char *) mystack_pop (stack);
  d2 = (const char *) mystack_pop (stack);
}

如果是使用GCC编译的话,全部的栈实现用宏来实现,可能没这么麻烦。不过实现pop时,可能要用到GCC的扩展。
#define mystack_pop(stack, type) \
  ({ \
     type __ret = empty value; \
     if (stack is non-empty) \
       { \
         __ret = top of stack; \
         dec top of stack; \
       } \
     __ret; \
  })
如果使用gcc的__typeof的话,定义宏时不要带类型参数
         如#define mystack_pop(stack) ....

6 楼


windy0will兄:好久没见了啊,已经毕业了么?有没有找工作啊?

7 楼

还没毕业,还在实习,不过马上就结束实习了。最近看书和上网的时间都很少。

8 楼

windy0will,Nice to see you!

9 楼

[quote]windy0will,Nice to see you![/quote]
Nice to see you, too.

记得刚来论坛时,各位前辈给我很大的帮助。我觉得那段时间进步得很快。
真的很怀念那段时光。
谢谢强强前辈和其他前辈的指导,

10 楼

1、用文件包含的办法,可以解决。
2、如果是C++,建议用模板来做。(C++自己也提供了stack的模板)
模板不用说,C++的教材一般都写得很清楚。下面详细说说文件包含的具体做法。

其实文件包含的做法与C++的模板,在思路上很类似。
先写一个头文件,叫做stack_template.h,内容如下:

[quote]#ifndef STACK_ELEMENT_TYPE
#error "使用本文件前,必须先定义STACK_ELEMENT_TYPE"
#endif

#ifndef STACK_TYPE
#error "使用本文件前,必须先定义STACK_TYPE"
#endif

#include <stdlib.h>

typedef struct
{
    STACK_ELEMENT_TYPE* elements;
    int top;
    int max;
} STACK_TYPE;

/* 注意:
 * 1. 每个操作的宏,都要用#ifndef扩起,否则如果多次使用这个文件,编译器就会报告告警甚至错误
 * 2. C语言的malloc返回值是void*,可以直接赋值给(stack)->elements。但是C++不行,因为C++的类型检查更加严格。
 *    C++可以在STACK_INIT这个宏里面再加入一个参数来表示类型,但是不推荐。C++推荐直接用模板。
 **/
#ifndef STACK_INIT
#define STACK_INIT(stack, maxSize) \
    ((stack).elements = malloc(maxSize * sizeof(((stack).elements)[0])), (stack).top = 0, (stack).max = maxSize)
#endif

#ifndef STACK_DESTROY
#define STACK_DESTROY(stack) \
    (free((stack).elements), (stack).elements = NULL, (stack).top = 0, (stack).max = 0)
#endif

#ifndef STACK_PUSH
#define STACK_PUSH(stack, value) \
    (((stack).elements)[(stack).top++] = (value))
#endif

#ifndef STACK_POP
#define STACK_POP(stack, value) \
    ((value) = ((stack).elements)[--(stack).top])
#endif[/quote]
注意:不要使用常见的#ifndef来防止重复include,因为这个文件本身就应该可以被反复的include

使用示例:
[quote]#define STACK_ELEMENT_TYPE  char
#define STACK_TYPE          CharStack
#include "stack_template.h"
#undef STACK_ELEMENT_TYPE
#undef STACK_TYPE

#define STACK_ELEMENT_TYPE  double
#define STACK_TYPE          DoubleStack
#include "stack_template.h"
#undef STACK_ELEMENT_TYPE
#undef STACK_TYPE

#include <stdio.h>

int main()
{
    CharStack cs;
    DoubleStack ds;
    int i;

    STACK_INIT(cs, 10);
    if (cs.elements == NULL)
    {
        return -1;
    }

    for (i = 0; i < 10; ++i)
    {
        STACK_PUSH(cs, (char)(i * 10));
    }

    for (i = 0; i < 10; ++i)
    {
        char c;
        STACK_POP(cs, c);
        printf("%d\n", c);
    }

    STACK_DESTROY(cs);

    STACK_INIT(ds, 10);
    if (ds.elements == NULL)
    {
        return -1;
    }

    for (i = 0; i < 10; ++i)
    {
        STACK_PUSH(ds, (double)(i * 10));
    }

    for (i = 0; i < 10; ++i)
    {
        double d;
        STACK_POP(ds, d);
        printf("%f\n", d);
    }

    STACK_DESTROY(ds);

    return 0;
}[/quote]

附加说明:
因为这里的"stack_template.h"没有防止重复include的功能,如果是在大型工程中使用,多有不便。为此可以继续封装。例如,建立一个头文件叫做"stack_of_char.h",内容如下:
[quote]#ifndef STACK_OF_CHAR_H_INCLUDED
#define STACK_OF_CHAR_H_INCLUDED

#define STACK_ELEMENT_TYPE  char
#define STACK_TYPE          CharStack
#include "stack_template.h"
#undef STACK_ELEMENT_TYPE
#undef STACK_TYPE

#endif[/quote]

这样以后就使用"stack_of_char.h",而不直接使用"stack_template.h",就不必担心重复include而导致的编译错误了。
当然也可以不用"stack_of_char.h",这样需要每次使用"stack_template.h"时都用#ifdef扩起。效果是一样的,也比较麻烦,但好处是文件的数目会减少。这个可以自行取舍。

我来回复

您尚未登录,请登录后再回复。点此登录或注册