一、二级指针做形参,一级指针的地址做实参(整形)
#include<stdio.h>
void A(int** t)
{
int x = 3;
printf("A:t: %x\n\n", t);
printf("A:&t: %x\n\n", &t);
printf("A:*t: %x\n\n", *t);
printf("A:&(*t): %x\n\n", &(*t));
printf("A:**t: %x\n\n", **t);
printf("A:&(**t): %x\n\n", &(**t));
*t = &x;
printf("在函数中t中的地址为%x\n\n", *t);
printf("在函数中t中值为%x\n\n", **t);
}
int main() {
int e = 9;
int* p = &e; //此处p为实参
printf("main:&e: %x\n\n", &e);
printf("main:p: %x\n\n", p);
printf("main:&p: %x\n\n", &p);
printf("main:*p: %x\n\n", *p);
printf("main:&(*p): %x\n\n", &(*p));
A(&p);
printf("main:p中的地址为: %x\n\n", p);
printf("main:p中的值: %x\n\n", *p);
system("pause");
return 0;
}
int *p=&e,等价于int p;p=&e;指针变量p,指向了int型数据。即p的值为f7fba8;
但是p的地址与其指向的地址是不同的。
&p=f7fb9c;
p其实是地址f7fba8内的数值9;
指针指向的其实是地址,并不是数值,只有在给指向的地址分配了内存,赋值了以后才会有特定的值,而分配内存有两种方式,一种是在堆上molloc和new,一种是在栈上分配内存,声明变量。因此在没有给指向的地址分配内存或者没有给指针指定指向的地址的时候,需要令int p=NULL,避免野指针。
A(&p);是 将p的地址作为值传递给*t,
注意,当指针作为形参的时候,实参是地址,当引用作为形参的时候,实参是变量,“形指实址”,“形引实变”
对于实参传过来的值是int **t=&p;
即等价于int t;t=&p;
而p的值是其指向的地址f7fba8;
t=(&p)=p;
t=(&p)=*p
因此分析t,即分析p;
转换成了一级指针;
因此,可以在A()中通过**t改变e的值,也可以通过t改变p的值,即改变p的指向;
A(&p);是 将p的地址作为值传递给**t,
实际上,我们常用的说法是指针t指向了指针p,指针的指针,为二级指针;
有一点一定要非常清楚,对于int *p=&e;而言,我们常说的,指针p指向了e;其说法不严谨,严格来说,指针指向的只能是地址;类似的在单片机领域的寄存器,每个寄存器都有其确定的地址,地址里面放的才是数值,因此有个说法是,指针是酒店的前台,会告诉你酒店每个房间的门牌号,房间里才是住人的地方,指针本身不住人。
二、形参和实参都是一级指针
前述的指针是实参为一级指针的地址,形参为二级指针;
试想,若形参和实参都是一级指针会怎么样?
#include<stdio.h>
void A(int* t)
{
int x = 3;
//t = &x;
printf("A: t: %x\n\n", t);
printf("A:&t: %x\n\n", &t);
printf("A:*t: %x\n\n", *t);
printf("A:&(*t): %x\n\n", &(*t));
*t = x;
}
int main() {
int e = 9;
int* p = &e; //此处p为实参
printf("main:&e: %x\n\n", &e);
printf("main:p: %x\n\n", p);
printf("main:&p: %x\n\n", &p);
printf("main:*p: %x\n\n", *p);
printf("main:&(*p): %x\n\n", &(*p));
A(p);
printf("main:&p: %x\n\n", p);
printf("main:*p: %x\n\n", *p);
system("pause");
return 0;
}
可以看到当将 //t = &x;注释掉,在接口函数里面可以改变e的值,
当不注释掉的时候为:
可以看到*p即e的值没有改变,&p的值即e的地址也没有改变,这是因为,即使在接口函数中改变了p的值即t = &x;但是p是作为变量的。
在函数中直接改变指针变量中地址所指向的内容,会改变函数外面指针所指向变量的值。但是在函数中改变指针变量的值,不会改变函数外面指针变量的值。