二维数组加sizeof的知识如果基础不扎实,上面的代码恐怕很难区分,这篇文章就深度解析一下有关问题
我们在分析之前,要提及一些基础的前提知识
前提知识:
一:
&数组名 和 sizeof(数组名)这两个例外中,数组名代表整个数组
除此之外所有的数组名都是表示首元素的地址
二:
我们直观以为的二维数组储存方式
实际计算机二维数组储存方式
也就是说:它们之间的地址是连续的!
三:
公式: *(数组名+自然数)== 数组名[自然数]
例如:
*(arr+1)==arr[1]
四:
地址的大小分环境,如果在x86(也就是32位环境下),大小为4个字节
如果在x64(也就是64位环境下),大小为8个字节
五:
sizeof()的()中的不参与编译运算
小练习
分析之前我们先来尝试思考一些简单一点的问题,避免一上来分析题目犯迷糊,容易绕晕
int arr[3][4]
第一类:
sizeof(arr)
sizeof(arr[0])
sizeof(arr[0][0])
很简单吧,首先上面这三个都符合前提知识的第一条,所以这些数组名都代表整个数组
arr代表的是整个二维数组,所以sizeof(arr)就代表整个二维数组的大小,就是3*4*4=48字节(因为int类型大小为4个字节)
arr[0]代表的是在二维数组中,第一行的一维数组,所以sizeof(arr[0])也就是整个第一行的大小,就是4*4=16字节
arr[0][0]代表的是在二维数组中,第一行的一维数组中的第一个元素,所以sizeof(arr[0][0])就代表该元素的大小,就是4个字节
第二类:
sizeof(arr+1)
sizeof(&arr+1)
在这一类中,sizeof(arr+1)格式为sizeof(数组名+1),而不为sizeof(数组名),所以这里的arr不属于两个例外,即不是代表整个数组,而是首元素地址
又因为二维数组的首元素地址为arr[0],所以此时arr就相当于第一行的一维数组的起始地址,所以arr+1为第二行的一维数组的起始地址,因为是地址,所以大小为4或者8字节
如果有点迷糊的话,可以这么简单理解:
二维数组分为三个层次
最高层次:二维数组
中间层次:一维数组
最低层次:一维数组的元素
而首元素地址就相当于降一级(也就是不符合sizeof(数组名)和&(数组名)格式的降级)
二维数组的首元素地址就为第一行的一维数组的起始地址
一维数组的首元素地址就为第一个元素的地址
然后sizeof(&arr+1)格式为sizeof(&(数组名)+1),虽然不符合sizeof(数组名)的格式,但是符合&(数组名)的格式,所以这里的arr代表整个二维数组,二维数组加1就相当于跳过整个二维数组,来到最后一行的一维数组的最后一个元素后面的那个地址,因为是地址,所以大小为4或者8字节
分析题目
1. sizeof(a),符合格式sizeof(数组名),所以这里的a代表整个二维数组,所以为3*4*4=48字节
(起始a为最高层次)
2. sizeof(a[0][0]),这里a[0][0]代表二维数组中第一行的一维数组的第一个元素,所以为4个字节
(起始a[0][0]为最低层次)
3. sizeof(a[0]),符合格式sizeof(数组名),所以这里a[0]代表二维数组中第一行的整个一维数组,所以为4*4=16字节
(起始a[0]为中间层次)
4. sizeof(a[0]+1),这里a[0]+1不符合sizeof(数组名)的格式,所以这里的a[0]代表二维数组中第一行一维数组的首元素地址,又因为我们说过首元素地址相当于降一级,所以a[0]代表了二维数组中第一行一维数组的第一个元素的起始地址,a[0]+1就是第一行的一维数组的第二个元素的地址,因为是地址,所以为4或者8字节
(起始a[0]为中间层次,首元素降级变为最低层次)
5. sizeof( * (a[0]+1) ),根据前提知识的第三条的公式可知, * (a[0]+1) == a[0][1],代表二维数组中第一行的一维数组的第二个元素,所以为4个字节
(起始a[0]为中间层次,首元素降级变为最低层次)
6. sizeof(a+1),不符合sizeof(数组名)的格式,所以这里的a代表二维数组的首元素地址,又因为我们说过首元素地址相当于降一级,所以a代表了二维数组中第一行的一维数组的起始地址,则a+1代表二维数组中第二行的一维数组的起始地址,所以为4或者8字节
(起始a为最高层次,首元素降级变为中间层次)
7. sizeof( *(a+1) ),根据前提知识的第三条的公式可知,*(a+1) == a[1],代表二维数组中第二行的整个一维数组,所以大小为4*4=16字节
(起始a为最高层次,首元素降级变为中间层次)
8. sizeof( &a[0]+1 ),符合&(数组名)的格式,所以这里的a[0]代表二维数组中第一行的整个一维数组,&a[0]就为二维数组中第一行的一维数组的起始地址,&a[0]+1代表二维数组中第二行的一维数组的起始地址,因为是地址,所以为4或者8个字节
(起始a[0]为中间层次,因为符合&(数组名),所以没有降级,还是中间层次)
9. sizeof( *(&a[0]+1 )),(&a[0]+1 )与上面分析一样,所以解引用后表示二维数组中第二行的整个一维数组,所以为4*4=16字节
(起始a[0]为中间层次,因为符合&(数组名),所以没有降级,还是中间层次)
10. sizeof(*a),不符合sizeof(数组名)的格式,所以这里的a代表二维数组的首元素地址,又因为我们说过首元素地址相当于降一级,所以a代表了二维数组中第一行的一维数组的起始地址,解引用后表示二维数组中第一行的整个一维数组,所以为4*4=16字节
(起始a为最高层次,首元素降级变为中间层次)
11. sizeof(a[3]),虽然二维数组为a[3][4],不存在a[3],但是我们前提知识的第五条说过,()中的不参与编译运算,所以我们编译运行时也不会报错,计算机可以通过我们定义的二维数组类型推断出长度,符合sizeof(数组名)的格式,所以a[3]代表二维数组中第四行的整个一维数组,所以为4*4=16字节
(起始a[0]为中间层次)