相信很多c语言的初学者在刚刚面对指针时的窘迫,确实指针是c语言的精华,从开始时强记指针就是地址,到现在的,我认为如果计算机中的数据看作均看作对象,指针就用来指引着这些对象,通过指针可以用来对这些对象进行修改。
值传递和地址传递是一个非常容易犯错的地方,给大家带来一个
#include<stdio.h>
int fun(int a,int *b){
a=100;
*b=200;
printf(“形参a的地址为%p,形参b的地址为%p\n”,&a,b);
}
int main(){
int a=10,b=20;
printf(“a=%d\t 实参a的地址为:%p \tb=%d 实参b的地址为%p\n”,a,&a,b,&b);
fun(a,&b);
printf(“a=%d,b=%d”,a,b);
}
通过实验结果可以看到,局部变量a传递的是值,b传递的是地址,对于值传递被调函数对形参的操作并不能改变主调函数中实参的值,地址传递可以改变,我们从内存的角度看一个,实际上值传递被调函数相当于重新定义了一个变量存储实参a的值他们的是两个完全不同变量,地址不一样在内存中的位置也不一样,只是把主函数中a的值拷贝了,试想他们是两个完全不同的东西如何能够通过形参a改变实参a的值,被调函数结束后形参a被释放,也与实参a无关了,实参a住的房子,会在主函数执行完释放
而地址传递时把变量b的地址传递到形参里去了,他们的地址时一样的住在同一间房子里,我们知道内存是由存储单元构成,*b相当于打开内存单元,向里面放入200这个值,在主函数结束之前200都将在这个房子里面,所以主函数中b的值已近被覆盖
#include<stdio.h>
int c[5]={5,6,7,8,9};
int print(int a[],int n,int a1[]){
printf(“a=”);
for(int i=0;i<n;i++){
printf("%d\t",a[i]);
}
printf("\n");
printf(“a1=”);
for(int i=0;i<n;i++){
printf("%d\t",a1[i]);
}
printf("\n\n\n");
}
int fun(int **a,int n,int a1[]){
/*int c[5]={6,7,8,9,10};
*a=c; //原因是返回局部变量的地址 */
*a=c;
a1=c;
}
int main(){
int b[5]={1,2,3,4,5};
int *a,*a1;
a=b;
a1=b;
print(a,5,a1);
printf(“a=%p\ta1=%p\n”,a,a1);
fun(&a,5,a1);
printf(“a=%p\ta1=%p\n”,a,a1);
print(a,5,a1);
}
上面传递的一级指针,这里传递的是二级指针,二级指针里保存的是一级指针的地址,一级指针指向数组b,然后传递一级指针的地址,在被调函数中是二级指针a指向数组c,主函数中a的指向也就变了,如果不是,而a1传递的也是地址,只是一级指针的地址,一级指针的地址只能改变数组b中的值,而二级指针改变的是a的指向a的地址也改变了,所以你要改变变量的(值)就得传递它的地址,
注意在被调函数中用一段代码是我注释了的,如果int c[5]={1,2,3,4,5}定义成立局部变量就是有问题的,当函数返回时,c的内存空间会从栈中释放,这时a就称为野指针了,编译器不会报错,但这是不允许的,不要返回局部变量的地址,也是很多人一不小心就会范的错误,而且如果经验不足不易看出,传递和传递值都只是相对而言的,取决的时你想改变的是什么,在第二例子里,b里的值可以被形参a1所改变,但是实参a1的指向确实改变不了,愿因是传递的是一级地址,就只能改边低一级的变量,二级指针可以改变一级指针的指向(也就是值),同理三级指针可以改变二级指针的值,一级指针可以改边变量的值。