您的位置:首页 > 编程语言 > C语言/C++

C语言指针参数陷阱

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

#include<stdio.h>

#include<stdlib.h>

/*这里构造一个结构体,用来表示链表的一个节点*/

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<stdio.h>

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<stdio.h>

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一样,都指向那个未知地址,我的程序并没有操作那个未知地址的权限,所以,两个热乎的野指针诞生了

在调试的过程中,每次都可以进行到第二次循环,我以为是循环体中出了什么问题,在贴吧帮吧友解决问题的时候看到了上面那个例子,然后才明白了指针在函数调用方面的这些小道道,这个问题本质上是一个野指针问题,其实在灵魂上,还是由于我对指针作为函数参数的特点不理解导致的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息