在gcc 4.7环境下写了一个简单的链表表示栈的结构,如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct Lnode{
int data;
struct Lnode *next;
}Lnode;
//初始化链栈
void initStack(Lnode *ln){
ln=(Lnode *)malloc(sizeof(Lnode));
if(ln == NULL){
printf("error");
}
ln->next=NULL;
}
//判断链栈是否为空
int StackEmpty(Lnode *ln){
return (ln->next==NULL?1:0);
}
//进栈
void push(Lnode *ln,int x){
Lnode *p;
p=(Lnode *)malloc(sizeof(Lnode));
if(p ==NULL){
printf("ERROR");
exit(0);
}
p->next=NULL;
p->data=x;
p->next=ln->next;
ln->next=p;
}
//出栈
int pop(Lnode *ln,int *x){
Lnode *p=ln->next;
if(p ==NULL){
return 0;
}
*x=p->data;
ln->next=p->next;
free(p);
return 1;
}
void printStack(Lnode *ln){
Lnode *p=ln->next;
while((p->next)!=NULL){
printf("%d\n",p->data);
p=p->next;
}
}
int main(void){
Lnode ln;
int x;
initStack(&ln);
push(&ln,2);
push(&ln,3);
push(&ln,4);
push(&ln,5);
pop(&ln,&x);
printf("出栈元素为:%d\n",x);
printStack(&ln);
return 0;
}
但是在执行initStack函数的ln->next=NULL之后变量的值并没有指向应该的0x0,而是0x39.
如图:
这个问题很严重,导致程序后面执行循环时指针访问到不确定的位置报错
是什么原因呢
我运行起来没问题哦!
void initStack(Lnode *ln){
这里不对,你用一个指针,只能说函数内外共享这个指针指向的存储地址
但是,如果你在函数内让它指向一个新的地址(malloc那里),那么不会反应到调用者形参(main的ln上)
正确的做法是使用指针的指针,这样才能把分配的新指针带出来。
修改后的代码
// Q694867.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
typedef struct Lnode{
int data;
struct Lnode *next;
}Lnode;
//初始化链栈
void initStack(Lnode **ln){
*ln=(Lnode *)malloc(sizeof(Lnode));
if(*ln == NULL){
printf("error");
}
(*ln)->next=NULL;
}
//判断链栈是否为空
int StackEmpty(Lnode *ln){
return (ln->next==NULL?1:0);
}
//进栈
void push(Lnode *ln,int x){
Lnode *p;
p=(Lnode *)malloc(sizeof(Lnode));
if(p ==NULL){
printf("ERROR");
exit(0);
}
p->next=NULL;
p->data=x;
p->next=ln->next;
ln->next=p;
}
//出栈
int pop(Lnode *ln,int *x){
Lnode *p=ln->next;
if(p ==NULL){
return 0;
}
*x=p->data;
ln->next=p->next;
free(p);
return 1;
}
void printStack(Lnode *ln){
Lnode *p=ln->next;
while((p->next)!=NULL){
printf("%d\n",p->data);
p=p->next;
}
}
int main(void){
Lnode * ln;
int x;
initStack(&ln);
push(ln,2);
push(ln,3);
push(ln,4);
push(ln,5);
pop(ln,&x);
printf("popped element is: %d\n",x);
printStack(ln);
return 0;
}
还有一种改法,根本不需要初始化和分配空间,因为堆栈上的ln实际上就是了
int main(void){
Lnode ln;
ln.next = NULL;
int x;
//initStack(&ln);
push(&ln,2);
push(&ln,3);
push(&ln,4);
push(&ln,5);
pop(&ln,&x);
printf("popped element is: %d\n",x);
printStack(&ln);
return 0;
}
看这个图,调用初始化前后,next都是0x39,说明没有反应到ln上
再看使用了指针的指针的情况
此时next就是0了。
指针类型也是一个变量,当指针类型作为形参做值传递时,会发生拷贝行为,所以initStack()中的Lnode* ln与mian()中的&ln是两个变量,不信可以分别打印出两者的地址查看是否一致;
修改方式是参数采用指针传递即Lnode** ln。
典型的指针使用不严谨, Lnode ln;和 ln=(Lnode *)malloc(sizeof(Lnode));这两行代码让你的传进去的In和初始化栈函数执行后的In不是同一块内存。