写了一个静态栈的程序,但是在不同的调用中,出现的结果完全不一样。
编译器是,操作系统是Ubuntu9.04,CPU是AMD4400,但是装的是32位的操作系统。
$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
下面是静态栈的源程序:
/*file link_stack.h*/
#ifndef __LINK_STACK_H
#define __LINK_STACK_H
#define TRUE 1
#define FALSE 0
#define STACK_INIT_SIZE 50
#define STACK_INCREASE 10
typedef int type;
typedef struct node{
type* top;
type* base;
int size;
}stack;
stack* stack_init(stack* p);
int stack_is_exist(stack* p);
stack* stack_destroy(stack* p);
int stack_is_empty(stack* p);
int stack_length(stack* p);
int stack_get_top(stack* p);
stack* stack_push(stack* p, type data);
stack* stack_pop(stack* p, type *data);
int stack_print(stack* p);
#endif
/*file link_stack.c*/
/*这是一个静态链表栈*/
#include
#include
#include "link_stack.h"
/*由于top保存的是栈的最上面一个元素之上的指针,所以在压栈时top++,出栈时--top*/
stack* stack_init(stack* p){
p->base = (type *)malloc(STACK_INIT_SIZE * sizeof(type));
if (!p->base){
printf("malloc error./n");
exit(1);
}
p->top = p->base;
p->size = STACK_INIT_SIZE;
return p;
}
int stack_is_exist(stack* p){
if (p == NULL)
return FALSE;
else
return TRUE;
}
stack* stack_destroy(stack* p){
if (!stack_is_exist(p))
return FALSE;
free(p->base);
return NULL;
}
int stack_is_empty(stack* p){
if (!stack_is_exist(p))
return FALSE;
if(p->base == p->top)
return TRUE;
else
return FALSE;
}
int stack_length(stack* p){
if (!stack_is_exist(p))
return FALSE;
if (stack_is_empty(p)){
printf("stack is empty./n");
exit(1);
}
return p->top - p->base;
}
type stack_get_top(stack* p){
if (stack_is_empty(p)){
printf("stack is empty./n");
exit(1);
}
return *(p->top - 1);
}
stack* stack_push(stack* p, type data){
if (!stack_is_exist(p))
return FALSE;
if (p->top - p->base >= p->size){
p->base = (type*)realloc(p->base, (p->size + STACK_INCREASE) * sizeof(type));
if (!p->base){
printf("realloc error./n");
exit(1);
}
}
*((p->top)++) = data;
return p;
}
stack* stack_pop(stack* p, type *data){
if (!stack_is_exist(p))
return FALSE;
*data = *((--p->top));
return p;
}
int stack_print(stack* p){
int i;
printf("All data ");
for (i = 0; i < stack_length(p); i++)
printf("%3d ", *(p->base + i));
printf("/n");
return 0;
}
下面的源代码test.c用
$gcc link_stack.c test.c
编译正确,但是加上-O1 -O2或者-O3时就会出现运行时的段错误
/*file test.c*/
#include
#include
#include "link_stack.h"
/*gcc lnk_stack.c test.c*/
int main(int argc, char *argv[]){
stack* p;
int i;
type data;
p = stack_init(p);
for (i = 0; i < 6; i++){
p = stack_push(p, 3 * i);
}
stack_print(p);
p = stack_pop(p, &data);
printf("data %d/n", data);
stack_print(p);
data = stack_get_top(p);
printf("data %d/n", data);
return 0;
}
下面的源代码convert.c用
$gcc link_stack.c convert.c
编译时就会出现段错误,加上-O1 -O2或者-O3时也会出现运行时的段错误
/*file convert.c*/
#include
#include
#include "link_stack.h"
int main(int argc, char* argv[]){
stack* p;
type data, e;
int bit;
printf("Enter the data you wan to convert:");
scanf("%d", &data);
printf("Enter the bit:");
scanf("%d", &bit);
p = stack_init(p);
while(data){
p = stack_push(p, data % bit);
data /= bit;
}
while (!stack_is_empty(p)){
p = stack_pop(p, &e);
printf("%d", e);
}
stack_destroy(p);
printf("/nFinished/n");
return 0;
}
对于convert.c这个函数。
就算在main函数中初始化stack* p = NULL,然后调用stack_init(p),也会出段错误。
问题看来是stack_init函数不能正确执行,具体原因还弄不清楚。
对于段错误来说,通常 是由于读写了不访读写的内存地址。
实际上,在convert.c和test.c的main函数中,stack* p的写法有问题,因为这个指针属于野指针,没有一个内存区域。
应写成
stack m, *p;
p = &m;
这也是涉及的指针的所有程序书写时必须注意的一点,不能上来就直接定义一个指针,必须确保这个指针指向一个数据类型 。
一重指针
int a, *p;
p = &a;
两重指针
int a, *p, **q;
p = &a;
q = &p;
第二条语句*p =a 连接着q与a,如果去掉,中间就会断链,出现野指针。
后面的stack_init 的p->base才有一个空间供它存malloc的首地址,如果不声名stack m; p->base就不知道存什么位置,
最后理所当然的是段错误了。
后面补充一点,如果你在一个自定义函数里使用malloc,然后拿到main函数里去调用,不出错的方法有两种:
1. 入口参数用两重指针,指向你想保存内存起始地址的一个指针变量。
2. 把malloc的内存起始地址做为返回值。
这两种方法也是C语言的函数参数传递的两种方法。如果不用这两种中的一种,那么自定义函数调用结束之后,malloc的空
间会被收回。到最后会出现段错误。