C语言指针参数陷阱

本人是一个刚开始学数据结构的大二学生,最近在学习链表的时候出现了一些小问题,一下是这个问题的详细分析,虽然是很简单,很可笑的一个小问题,却也值得深究


#include
#include

/*这里构造一个结构体,用来表示链表的一个节点*/
typedef struct ysf{
int no,psw;
struct ysf *next;
}YSF,PYSF;


/*创建一个节点*/
void comp(PYSF *p,int i){
int pswd;
p=(YSF *)malloc(sizeof(YSF));
p->no = i;
printf("please input a password:");
scanf("%d",&pswd);
p->psw = pswd;
}


int main(){

int i;
PYSF *p,*q;
YSF L;
for(i=1;i<=7;i++){
comp(p,i);
if(i==1){
L.next = p;
q=p;
}
else{
q->next = p;
q=p;
}
}
p->next = NULL;
printlist(p,L);
return 0;
}


为什么系统会报错呢,我们来看一看这个错误信息,段错误(核心已转储),这个错误相当于windows下的内存溢出,即访问了不该访问的内存区域,为什么会这样,我们来细细分解一下


在这之前,现举个例子

#include

void fun(int *a,int *b){

int *c;

c=a; a=b; b=c;

}

int main(){

int x=3,y=5,*p=&3,*q=&5;

fun(p,q);

printf("%d,%d",*p,*q);

fun(&x,&y);

printf("%d,%d",*p,*q);

return 0;

}


这里输出的结果应该是多少呢,相信很多人会和我第一次看到它一样,感觉完全懵逼了,不要急,我们一个一个分析


第一个fun里面,传进去的是p和q的地址,错误的思想是觉得函数会通过指针直接操作,很遗憾我开始也是这么想的,然而并不是这样。把指针作为形参传进一个函数,相当于把实参的指针指向了形参所指的内存空间,即将a和b指向了x和y,函数内的操作只不过是把a和b换了,p和q是不受影响的。而第二个也是只改变a和b的指向,x和y的地址没有变,p和q的指向也没有变。


那么有人就要问了,既然如此,那么指针有何意义?指针不是号称不需要返回值就可以改变原函数中的值么,别急,是这样的


#include

void fun(int *a,int *b){

int c;

c= *a; *a = *b; *b = c;

}

int main(){

int x=3,y=5,*p=&x,*q=&y;

fun(p,q);

printf("%d,%d",*p,*q);

}

这时候输出的就是5,3了


拐个弯我们再回到一开始的问题,我的程序错在哪里了呢?原来我用como(PYSF *p)函数申请了一块内存空间,并用这里的形参p指向了它,然而实参p是在主函数中定义的,定义之后没有进行初始化,所以它指向了内存上一个任意的地址,函数comp运行结束之后从内存栈区退栈,形参p也随之被释放,然而实参q还是指向那个未知的地址。


到这里一切都是没问题的,然而接下来发生的事情就诡异了。我把实参p赋给了头节点L的指针域,然后把q也指向p指向的这个地址,到这里还是没有问题的,但它们的行为已经脱离了我的控制。接下来进入第二次循环,这时候问题出现了,我要把下一个节点的地址(假设它存在,其实p一直是指向那个未知地址的,并没有指向什么节点,那个节点早已迷失在内存空间)赋给q的指针域,前面说了,q和p一样,都指向那个未知地址,我的程序并没有操作那个未知地址的权限,所以,两个热乎的野指针诞生了


在调试的过程中,每次都可以进行到第二次循环,我以为是循环体中出了什么问题,在贴吧帮吧友解决问题的时候看到了上面那个例子,然后才明白了指针在函数调用方面的这些小道道,这个问题本质上是一个野指针问题,其实在灵魂上,还是由于我对指针作为函数参数的特点不理解导致的

你可能感兴趣的:(c/c++)