晚上好哇!数组下篇正式开章,欢迎各位来宾(手动滑稽)。
这一篇我写成了一环套一环的递归格式,哈哈哈,说人话就是先解决最后的小问题,在回头解决开头的问题,不知道这种方式跟直接写哪种效果更好一点,有建议的话留言哈!
目录
1.数组的传参:
在写很多函数的时候,我们都会把数组作为实参进行传递
如下图,我们要使用函数计算数组开辟的空间大小,该功能用Quantity自定义函数实现。
通常,我们使用数组传参时常常用一个数组来接收,如上图使用int arr[]来接收,该形参[]中的数据是省略的,说白了,int数据用int类型来接收,char数据用char类型来接收,数组数据是用数组类型来进行接收——即 int []其实是数组的类型,而arr是该类型的变量名。
(问题1:)
那么我们这样写是正确的吗?我们试着运行一下,如果它是对的,那么很显然结果应该为10;
(问题2: )
结果是1,显而易见这种写法是错误的, 那到底是为什么呢,难道没有发生临时拷贝将数组内容拷贝吗?
2.数组名
在解决这个问题之前,我们先来看一下数组名究竟是什么
在图中,打印发现arr的地址和&arr[0]竟然完全相同,并且我们还可以对arr解引用得到数组首元素。
因此,我们可以得出结论,arr(即数组名)其实就是数组首元素的地址,没错,arr它其实是一个地址。
(问题3: )
那么问题又来了:
如果arr是数组首元素的地址,那么sizeof(arr)/sizeo(arr[0])为什么可以用来计算数组的元素个数呢?
(问题4: )
sizeof(arr)/sizeo(arr[0]) 我们将其解释为: sizeof(arr)是整个数组的大小,sizeof(arr[0])是数组第一个元素的大小,也就是单位元素的大小,总大小除于单位元素的大小,结果自然就是数组的个数了,但arr不是首元素地址吗?
2.1.数组名的特殊情况
事实上,arr并不是总代表着首元素地址,它有着两个特殊情况。
第一种就是当arr数组名单独出现在sizeof中的时候,这时候arr代表的是整个数组
第二种是当对arr进行取地址时,即&arr,此时arr也代表了整个数组
那我们现在不如来看一下&arr的地址
(问题5: )
咦,三个地址值完全相同,难道&arr不是整个数组的地址,而是首元素地址?
其实并不然,&arr确实是整个数组的地址,它们的值虽然相同,但它们有着完全不同的意义。
3.地址的取出
对于&操作符来说,它的作用是取出地址,但它取的只是一个地址,而一个地址不过是一个字节的大小,但如上图,int类型的a明明是是有4个字节的,这4个字节一定占据了4个连续的地址空间。
因此,对于&来说,它所取的地址只是数字层面上最小的一个地址,也就是说,它只取出了a的最小地址。
(问题6: )
那既然它只取出了一个字节的地址,也就是说p指向a的最小地址,而不是a的所有地址,那又为什么可以通过该地址对a进行访问和更改呢?
这就体现了类型的重要性,当使用*符号时,会根据&a,也就是从a的最小地址开始,连续访问共sizeof(int)个地址空间,也就是说,因为a是int类型,所以在*时,从a的最小地址开始连续读取了a的总地址,并据此对a进行更改。
4.拓展
此时当对整型(int)指针变量p进行加减操作时,所加减的字节大小其实就是sizeof(int)的大小,即p+1,则地址增加4个字节
5.return递归返回
那我们现在返回&arr
对于此时的arr来说,它代表的是整个数组,也就是说,每次对&arr+1,地址都会增加该数组的字节大小,而对arr[0]或arr来说,其+1增加的只是其元素类型,即int(4个字节)的大小
可以看到&arr+1后恰好增加了数组的大小(12个字节的大小)。
因此它们只是数值层面的相等。
现在我们回到最开始的问题上,当我们传递实参arr时,传递的其实就是数组首元素的地址,我们将此称之为数组的降维,因此形参接收的不过就是数组首元素的地址,此时sizeof(arr)所计算的是一个地址类型的大小,而任何一个地址变量都是4个字节的大小,因此sizeof(arr)/sizeof(arr[0]),其实就是4/4==1。
因此我们在计算数组元素的时候,总是把计算写在主函数中,而不是放在调用的自定义函数里面。
因为数组和指针在某方面的相似性,本篇渗透了一些指针的相关知识,但由于我们在初始篇中对指针进行过一定的了解,所以并不是十分晦涩,当然是在觉得乱的话也不必强求,对于数组的传参降维问题和其与指针的关系我会在后面的指针篇进行详谈。
本篇大家只要明白数组传参会发生降维,降成指针(地址),即可
一波小游戏即将来临!!!!
下一篇 -------> 三子棋小游戏
晚安噢!