每日壁纸分享(出处: 极简壁纸_海量电脑桌面壁纸美图_4K超高清_最潮壁纸网站)
前言
在开始阅读本文之前,我们需要先了解一个知识点:数组名 == 该数组首元素地址 ,这对我们后文的推进至关重要,不过在文章开头我们会稍微证实一下。
目录
一,数组名的理解
在C语言中,数组名 == 数组首元素地址,只有在两个情况下除外:
1:当使用sizeof计算数组所占内存大小时,此时sizeof(arr)中,arr 代表的是整个数组,如下:
2:当对数组名取地址时,如:&arr ,此时 &arr 是一个数组指针,而首元素地址&arr[0] 是一个整型指针,如下:
当我对这两个同时取地址并打印出来时,可以发现&arr 和 &arr[0] 的地址是一样,这是因为数组内的元素都是连续存放的,当指针想要访问一个数组时,只需要知道该数组第一个元素的地址即可遍历该数组,故该数组用首元素地址表示并无不恰当之处,所以我们就可以理解&arr 的地址 和 &arr[0] 为什么相同。
但是当我们同时对 &arr 和 &arr[0] 做 +1 时,两者却展现出了差异性,这是因为两者数据类型不同。我们知道,当对一个地址进行加减 n (整数)时,实际是对该地址前进或者后退 n 个该地址所指向空间类型的大小。通俗地说,如:int * p ,此时 p 是整型指针类型,那么 p+1 就是在 p 所指向的地址上向高地址推进 4 字节。(因为 int 所占内存空间大小为4字节)
在本段代码中,因为数组 arr 是整型数组,所以每个元素都是整型类型,那么 &arr[0] 就是 int * 类型,当 &arr[0] + 1 时,就是向高地址跳过4字节;
而 &arr 是对整个数组取地址,此时它的类型就是 int (*)[10] 类型,也就是十个整型类型的空间,故当 &arr + 1 时,实际上就是向高地址跳过40字节。
除了以上两种情形之外,所有的数组名都表示的时首元素的地址。
二,使用指针访问数组
在了解过数组名后,我们还需要深入了解一下指针访问数组的方式。接下来我会使用一个简单的代码进行举例,如下:
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
在我们没有学习指针之前,我们遍历数组每个元素应当就是如上写法。但是学习指针了之后,我们便可以理解这种形式下的底层逻辑。
我们先试着使用指针访问,如下:
输出结果:
这里我们使用的是 *(p+i)来遍历数组,即是通过首元素地址跳过 i 个字节来实现。当 i=0
时,p+0 == p,p向前跳过0个字节,也就是首元素的地址,再对其解引用,;当 i=1 时, p+i == p+1,p向前跳过4个字节,此时指向下标为1的元素,也就是arr[1],再对其解引用...以此类推从而实现遍历数组所有元素。
又因为我们已知 p == arr == 数组首元素地址,那么*p == *arr,那么就可以这样写:
可以看到正常输出。
在没有学习指针时候,我们用 arr[i] 来对数组每个元素进行访问,其实arr[i] == *(arr + i),前者只是形式上的写法,当使用前者的写法时,编译器照样会将其按照后者去实现。由此我们也可以推出:arr[i] == *(arr + i) == *(p + i)== p[i] 。如下:
可以看到依旧正常输出,那么我们就可以得到规律:首元素地址+[下标] ————> 即可访问数组元素
再往前推一下,我给大家讲点有意思的或是颠覆大家认知的。因为加法是支持交换律的,所以
*(arr + i) == *(i+ arr),又因为 *(arr + i)== arr[i], 所以 arr[i] == i[arr] == p[i] == i[p] ,如下
当然我只是演示一下有这种写法,并不推荐大家这样去写,因为可读性比较差。
三,一维数组传参的本质
在前文中已经给大家铺垫了数组名的理解与使用指针访问数组的方式,接下来就可以更好地去理解本章的内容。
我们之前学过的一维数组传参的形式大概如下:
void print(int arr[])
{
//....
}
int main()
{
int arr [10] = {1,2,3,4,5,6,7,8,9,0};
print(arr);
return 0;
}
即是函数形参部分是由数组的格式来接收的,那么数组传参是传过来一整个数组吗?
我们可以在函数中使用sizeof计算数组元素的个数,如下:
此时发现输出的结果竟然是1,这就要学习数组传参的本质了,前文我们学习了:数组名是数组⾸元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组⾸元素的地址。
那么为什么传的数组首元素的地址,形参却要用数组的形式去接受呢?或许这是为了让人们能更好地去理解传参,毕竟认为传的是数组,那么接收的也应该是数组。
既然已知数组传参传递的首元素地址,那么我们就可以用指针变量进行接收,如下:
在讲到数组传参又不得不提到为何传参仅仅只需要传递首元素地址即可访问整个数组了,前文中曾经讲过,因为数组中的元素在内存中都是按下标由地址从低到高连续存放的,那么我们只需要知道首元素的地址,即可通过不断+1,+1遍历整个数组。代码示例如下:
void test(int* p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ",*(p+i));
}
return;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
test(arr, sz);
return 0;
}
上面代码我是通过p+i 来实现遍历数组每个元素的,因为i++,所以就不需要去修改p的地址。
本次知识分享就到此结束了,谢谢观看!