提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
数组是一组相同类型元素的集合,是一种自定义类型。本期我要分享我对于数组在内存中的布局,数组名,数组传参方面的了解。
提示:以下是本篇文章正文内容,下面案例可供参考
一、数组在内存中的布局
我们要知道数组在内存中是线性连续且递增的。
下面我将以一维数组,二维数组为例。
一维数组
如下:
(int型在内存中占4个字节)
int main()
{
int arr[10] = { 0 };
for (int i = 0; i < 10; i++)
{
printf("arr[%d]=%p\n", i, &arr[i]);
}
return 0;
}
其在内存中线性连续且递增存放。
二维数组
如下:
int main()
{
int arr[3][4] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("arr[%d][%d]=%p\n", i, j, &arr[i][j]);
}
}
return 0;
}
一般我们将二维数组画成矩阵的形式是方便我们理解,但要知道二维数组在内存中也是线性连续且递增存放的。并且画成上图所示也可以更好的画出三维数组等。
以arr[ 3 ] [ 3 ] [ 4 ]为列
如下:
二、数组名
假设我们定义一个整形数组:int arr[4]。其中arr是数组名,int 是数组元素的类型。
对于数组名大部分情况都表示数组首元素的地址,只有在sizeof()中单独使用或**&符号引用时表示整个数组。如下:
我们知道对于指针+1的步长大小是其指向类型的大小,所以对于p+1,地址移动4个字节,对于pa+1,地址移动16个字节。而p指向的类型是int,大小是4,pa指向的类型是int [4],大小是16。所以可以表明&数组名**代表整个数组。
sizeof(表达式) 所求的大小是表达式类型的字节个数。
sizeof(arr)是3,表达式类型是char [3],大小是3。sizeof(arr+1)是4,表达式类型是char*(表示数组第二个元素的地址)(32位平台),大小是4。
所以可以表示sizeof()中单独使用表示的是整个数组的大小。
到此数组名的介绍也就完成了,对于一维数组,数组名非常明料,但对于二维数组呢?
如下:
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0]+1));
printf("%d\n", sizeof(a+1));
printf("%d\n", sizeof(a[3]));
printf("%d\n", sizeof(*a));
return 0;
}
上述代码的结果是什么呢?
为什么是这个结果?
首先我们要有所有的数组都是 “ 一维数组 ”(并不是真的)的认识。
如下:
所以有了上面这层认识,对于上面的结果,我们就可以清楚的理解。
如下:
三,数组传参
当数组作为函数参数来传递时,其会发生降维。降维成指向内部元素类型的指针。
但是为什么要发生降维?
我们要知道函数的调用是要完成形参的实例化,如果数组传参时不进行降维,而是直接进行拷贝数组内部数据,其会加大函数调用的成本,而要是降维成指针时,函数调用的成本会减小,效率提升。如当数组内部有10000个元素时,如果数组传参不进行降维成指针,就要拷贝10000个元素,函数调用的成本和效率就会减少。
所以数组传参时会发生降维,就是为了提高函数调用的效率。
当我们理解了数组传参时,会发生降维,那么我们也就可以解释为什么数组作为形参时,第一维可以省略,其它维不可以省略。
其本质就是数组传参,会降维成指向其内部元素类型的指针。
如下:
对于一维数组
其形参类型是int*
对于二维数组:
其内部元素的类型是int [4],所以数组传参,形参的类型是int (*)[4]。
当我们将第二维改变,编译器会发出警告,甚至错误。
其根本原因就是,对于数组而言,数组下标也是数组类型的一部分。
所以我们才发现数组传参时,只有第一维可以省略,其它维不可省略。
总结
以上就是我对于C中数组的一些认识。如果哪里有错误,请各位大佬及时指出。多谢多谢!!!