我们定义一个函数,就是为了使用它,但是在进行参数传递的时候需要传递指针相关的数据的时候我们需要注意两点,一个是传指针,另外一个是解引用,这两点缺一不可,传指针很容易理解,就是在进行实参传递的时候,在形参列表里面写上指针的数据类型以及指针名就好了。那解引用是什么呢?我们一起先来复习一下。
解引用,说的通俗一些就是一种联系,我们来看一个演示图:
在这张图里,左边是代码,右边是代码对应的关系图。我们首先定义了两个变量a和b,分别赋值10和20,然后定义了一个指针变量整型的指针变量,用来存放a的地址,a的地址为1000,所以p变量里面存放的数字就是1000,这里面的红色数字都表示的是变量的地址,因为将p里面保存了a的地址,所以p就和a建立了一种联系,图中用虚线 表示出来的就是这 种关系,因为p和a建立了某种联系,此时再通过解引用也就是间接访问符 * 访问到了 a变量,将*p赋值成了100,同理也就是相当于将a赋值成了100,这也是为什么将它称为间接访问符的原因,就是间接的访问到了a,将它的值赋值成了100.
我们说p是一个指针变量,那么既然是个变量,它也是有地址的,我们同理也可以使用一个变量用来保存p这个指针的因为p已经具有了一次解引用的能力了,而再定义一个变量来保存p的地址的话也具有一次解引用的能力,所以称为二级指针,同理也有三级,四级指针等等,但是二级指针已经够难的了,所以我们不再讨论那么多的指针了。
再看上面的代码,定义了一个二级指针pp(这里的pp只是一个代号,并没有什么特殊的意义,可以是p1,p2……),用来保存p的地址,先对pp进行一次的解引用,访问p这个变量将p的值赋值为a的地址,将p又和a联系,在将a的值赋值为1000,这里进行了两次的解引用。
看懂了以上简单的例子,我们再来看一个例子,这个例子讲的是对两个数的交换。
交换函数是非常简单的,如果要写简单的可能是一行代码就可以写完,但是为了更全面的理解指针的传递与解引用,我们还是来写一段稍微复杂一些的代码。
void Swap_err1(int a,int b)
{
int tmp = a;
a = b;
b = tmp;
}
void Swap_err2(int *p1,int *p2)
{
int *tmp = p1;
p1 = p2;
p2 = tmp;
}
//野指针:没有访问权限的地址(指针)
void Swap_err3(int *p1,int *p2)
{
int *tmp;//野指针,悬挂指针
*tmp = *p1;//error
*p1 = *p2;
*p2 = *tmp;
}
void Swap(int *p1,int *p2)
{
int tmp;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10;
int b = 20;
printf("%d,%d\n",a,b);
Swap(&a,&b);
printf("%d,%d\n",a,b);
return 0;
}
其中err1函数就是第一种错误的函数,这里的函数即没有传指针,也没有解引用,所以这个函数里面的改变对主函数里面的数字 并没有什么影响,所以并不能进行两个数据的交换功能。
而第二个错误的交换函数err2,在形参里面虽然进行了指针的传递,指针就是地址,也就是将地址传递过去了,然后进行了交换,并没有进行解引用,当然也不能交换数据了。
第三个错误则是错误的使用了解引用,在函数体里面定义了一个 int * tmp,一开始并没有对它进行初始化,所以会给它分配一个随机值,也就是一个随机的地址,这个时候如果进行解引用的话又会访问tmp这个变量,但是它已经指向了其他位未知的地址,这个被称为野指针,也就是真实存在的地址但是并没有访问的权限,最后会直接崩溃,所以这样也不能进行数据交换。
错了这么多,最后一个肯定是对的啦。
最后再强调一遍哦,一个函数的改变要影响另外一个函数,我们一定要具备两点:传指针和解引用。