1.传值调用与传址调用
在我们之前学习函数的时候,我们用到了一个交换函数,但是呢?并没有完成交换。
我们得出了一个结论;函数传参,形参是实参的一份临时拷贝,修改形参并不会影响实参。
这个就是传值调用,只是传递值给函数。
但是,当我们学习了指针之后,知道了可以通过地址来间接访问到该变量的值,那我们就可以通过传递地址的方式,在函数中通过地址来访问到实参,并进行交换。
这种传递地址的方式就被称为:传址调用。
通过传值调用与传值调用,我们在写代码的时候,我们如果需要实参来计算值的时候就可以用传值调用,如果要修改实参就用传址调用。
数组名的理解:
在前一篇我们用指针来访问数组的时候,我们写到了一个int*p = &arr[0];我们也说过,数组名就是首元素的地址。这里是否正确呢?
我们通过上述的代码可以看到上面打印的两行地址是一模一样的,所以我们可以得出,数组名是首元素的地址是正确的。
那既然数组名是首元素的地址,那我们可不可以用指针来访问数组的时候,用int*p = &arr呢?
我们通过代码可以得出,上述提出的问题不可行。因为&arr+1的话是跳过一个数组。
所以我们&数组名,这里的数组名表示的是整个数组,取出的是整个数组的地址(整个数组的地址与数组首元素的地址是由区别的)。
当然在sizeof里面也是
输出的结果是20,如果数组名是首元素的地址的话,那么应该在32位机器上计算的是4,在64位机器上应该是8。
其实这里的sizeof(数组名),sizeof中单独放数组名的话,,这里的数组名指的是整个数组,计算的是整个数组的大小。
我们综上所诉:可以得出
数组名是数组首元素的地址,但是有两个例外,一个是sizeof(数组名),一个是&数组名。
一维数组传参的本质:
之前在函数的学习中,实现过,代码如下
我们传参传的是数组名,我们知道数组名是首元素的地址,我们就可以用指针的方式
在上面的两个代码中,我们发现了我们都是直接求出数组长度然后传给函数,那我们可以不可以直接在函数里面求数组长度呢?
我们发现最后只打印了一个1,这时为什么呢?
通过调试我们看到sz出现了问题。
最后我们得出,在函数里面是无法求出数组元素个数的。
二级指针:
我们说求出一个变量地址存放在指针变量里面,那么指针变量也是变量啊,它也有地址,那我们把它的地址存放在哪里呢?
这时我们就需要用到二级指针了。
通过代码结合图形,我们可以这样理解,p存储的就是a的地址,pp就是存储的p的地址。
我们可以这样理解二级指针。
指针数组:
指针数组,这个就引起我们的思考了,它到底是数组呢?还是指针呢?
我们可以这样理解,整型数组是存放整型的数组,字符数组是存放字符的数组,那么指针数组就是存放指针的数组了。
指针数组的每个元素都是地址,又可以指向一块区域。
图形理解
代码理解
用指针数组模拟二维数组:
在之前我们学习数组的时候没有讲到二维数组,我们在这里简单讲一下
二维数组其实就是把一位数组做为数组的元素。
二维数组的创建:
上述的代码中,3表示有3行,5表示有5列
int 表示数组类型,arr表示数组的名字(这个可以根据自己需要起名字)。
二维数组的初始化:和一维数组一样,在大括号中初始化
但是我们要注意,二维数组初始化,行可以省略,但是列不能省略。
二维数组在内存中的存储方式
我们可以得出二维数组同一维数组一样在内存中是连续存放的。
讲完了二维数组,我们接下来用指针数组来模拟一下二维数组
虽然说指针数组可以模拟出二维数组的效果,但是它并非完全是二维数组,因为二维数组在内存中是连续存放的,而模拟出来的数组在内存中存储并不连续。