主题:如果在一个程序中用到不同数据类型的栈,该怎么解决
卡卡罗特as
[专家分:0] 发布于 2012-04-17 22:03:00
最近学习当中,有个问题搞不懂,求大神指点。建了个栈,为了重复使用,将数据类型重定义为为typedef char A 但问题来了,程序中要是栈的数据类型为double,这该怎么办,应该不能typedef double A吧,请问有没有取消类型重定义的方法,类型重定义的作用范围是什么,我想过用文件包含来解决,不知道行不行,求大神帮个忙啊,急用,谢谢
最后更新于:2012-04-18 15:57:00
回复列表 (共11个回复)
沙发
csslsb [专家分:0] 发布于 2012-04-17 22:12:00
用心回贴是美德!支持楼主!
-------------------------------
汕头神州数码stszsm.com 江苏钻井csslsb.com 江苏冷风机csslsb.com
板凳
fragileeye [专家分:1990] 发布于 2012-04-17 22:54:00
这个个人用到的不多,不太熟悉,不过这么可行么?
#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 楼
卡卡罗特as [专家分:0] 发布于 2012-04-18 16:05:00
把问题改改吧,想在同一程序中使用不同数据类型的栈,怎么办?栈是这样定义的
typedef struct{
char *stack;
int top;
}SqStack;
它的一系列操作,如入栈,出栈……当然都是char的,但要用到double的栈,又不想将所有的函数重抄一遍,该怎么办,求解决办法,谢谢了
4 楼
fragileeye [专家分:1990] 发布于 2012-04-18 16:17:00
这样呢?
#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 楼
windy0will [专家分:2300] 发布于 2012-04-18 17:01:00
用指针来引用数据,应该可以勉强实现吧。
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 楼
fragileeye [专家分:1990] 发布于 2012-04-18 17:32:00
windy0will兄:好久没见了啊,已经毕业了么?有没有找工作啊?
7 楼
windy0will [专家分:2300] 发布于 2012-04-19 17:40:00
还没毕业,还在实习,不过马上就结束实习了。最近看书和上网的时间都很少。
8 楼
强强 [专家分:4740] 发布于 2012-04-20 16:28:00
windy0will,Nice to see you!
9 楼
windy0will [专家分:2300] 发布于 2012-04-20 19:11:00
[quote]windy0will,Nice to see you![/quote]
Nice to see you, too.
记得刚来论坛时,各位前辈给我很大的帮助。我觉得那段时间进步得很快。
真的很怀念那段时光。
谢谢强强前辈和其他前辈的指导,
10 楼
eastcowboy [专家分:25370] 发布于 2012-04-22 18:03:00
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扩起。效果是一样的,也比较麻烦,但好处是文件的数目会减少。这个可以自行取舍。
我来回复