拓展阅读:二维数组与sizeof

发布于:2023-01-07 ⋅ 阅读:(624) ⋅ 点赞:(0)

前言:本人为C语言初学者,学识尚浅,研究程度存在很大的局限性,眼界很窄。以下所有观点仅代表个人见解和思路,各位游刃有余的前辈可以给予批评和指正!各位与鄙人同路的学子可相互探讨、发表看法,交换观点!

这是关于上一篇:初学C语言:sizeof 和 strlen 你真的了解吗?的拓展,关于二维数组和 sizeof 的深度解析,如果你能够理解上一篇的内容,这一篇的内容会对你有很大帮助。当然,并不是说你不能直接看这一篇,如果你有深厚的基础且真正了解它们,这一篇也应该不在话下。

目录

1.sizeof(arr);

2.sizeof(arr[0][0]);

3.sizeof(arr[0]);

4.sizeof(arr[0] + 1);

5.sizeof(*(arr[0] + 1));

6.sizeof(arr + 1);

7.sizeof(*(arr + 1));

8.sizeof(&a[0] + 1);

9.sizeof(*(&a[0] + 1));

10.sizeof(*arr);

11.sizeof(a[3]);

数组如下:

int arr[3][4] = {0};

1.sizeof(arr);

int ret = sizeof(arr);

首先,我想关于数组名的两点需要被再次强调:(1)sizeof 中,单独存在的数组名将会计算的是整个数组的大小   (2)&数组名,取出的是整个数组的地址

所以这里单独存在的数组名被计算了整个数组的大小,即为:3行 * 4列 * 4byte = 48byte

2.sizeof(arr[0][0]);

int ret = sizeof(arr[0][0]);

arr[0][0] 即取出第一行第一列的值,为0,即为int类型,所以其大小为:4byte

3.sizeof(arr[0]);

int ret = sizeof(arr[0]);

arr[0] 实则是二维数组中一维数组的数组名,所以计算的应该是整个一维数组的大小,即:             4个 * 4byte = 16byte

或许有人说,arr[0] 不是等价于 *(arr + 0) 吗?故想把以上代码转换成:sizeof(*(arr + 0));      但是这里能转换吗?很简单的道理,我们都知道 arr 数组名在除特殊两种情况外,等价于 &arr[0]    但是 sizeof(arr); 确实是其特殊情况之一,那么 sizeof(arr); 并不等价于 sizeof(&arr[0]); 吧!所以     sizeof(arr[0]); 肯定也不能等价于 sizeof(*(arr + 0)); 啊!这里不要过度思考了!(这里其实是我自己的胡思乱想...)

4.sizeof(arr[0] + 1);

int ret = sizeof(arr[0] + 1);

这里刚好与上一点对应,这里涉及到了运算,所以 arr[0] 本是表示整个一维数组,但现在作为一维数组的首元素地址使用,即表示:&arr[0][0],加上 1 即表示第一行第二列的元素的地址嘛!所以它最终得到的是一个地址,即第一行第一列元素的地址,为:8byte

5.sizeof(*(arr[0] + 1));

int ret = sizeof(*(a[0] + 1));

首先,我们要明白先算的应该是:arr[0]  + 1; 而因为 a[0] 参与了运算,所以变成了第一行第一列的地址,即变成了:&arr[0][0] + 1; 加 1 即表示第一行第二列的地址:&arr[0][1],又对其进行解引用:*&arr[0][1],所以最终获得的是:arr[0][1],即取出了第一行第二列的值,为int类型,所以其大小为4byte

6.sizeof(arr + 1);

int ret = sizeof(arr + 1);

arr 本来作为数组名,但参与了运算,则表示数组首元素地址,又因为其是二维数组,所以 arr 这里表示的是一位数组的地址,即:&arr[0]; 这里的加 1 即让地址指向了第二行,变为了:&arr[1] 而已,但说到底还是地址,所以为:8byte

7.sizeof(*(arr + 1));

int ret = sizeof(*(arr + 1));

分析同6,只是多了一步解引用,到最后便变成了:*&arr[1]; * 和 & 抵消,神奇的事情发生了,最后剩下了:arr[1]; 这是神马,这是数组名啊,所以到头来,它还是变成了数组名,变成了那个特例,计算了整个一维数组的大小,为:4个 * 4byte = 16byte

8.sizeof(&a[0] + 1);

int ret = sizeof(&a[0] + 1);

a[0] 本来作为一维数组的数组名,但 &a[0] 涉及到一种特殊情况,即取出的是整个一维数组的地址,整个数组的地址加 1,最终得到的是第二行的一维数组的地址,即:&a[1]; 所以,无论怎样,它都是一个地址,占:8byte

9.sizeof(*(&a[0] + 1));

int ret = sizeof(*(&a[0] + 1));

分析同8,只是多了一步解引用,到最后便变成了:*&arr[1]; 同理,* 和 & 会抵消掉,所以最后成了:arr[1]; 又是数组名,所以计算的自然又是一维数组的大小,即:4个 * 4byte = 16byte

10.sizeof(*arr);

int ret = sizeof(*arr);

arr 本来是二维数组数组名,和解引用结合即参与了运算,所以这里的 arr 被视为首元素地址,即第一行,一维数组的地址,所以可以整个转换为:*(&arr[0]); 即:arr[0]; 又是一维数组数组名,所以又是:4个 * 4byte = 16byte

11.sizeof(a[3]);

int ret = sizeof(a[3]);

好,好!傻了吧。这里执意对数组越界访问会怎样?

我们都知道,这里应该是计算第四行的一维数组大小,但是这个数组就三行,哪来的第四行!这里又不得不说一说这个 sizeof 的独到之处,不妨先用以下代码来见证一下:

short a = 2;
printf("%d\n", sizeof(a = 5 + 2));
printf("%d\n", a);

可以看到,sizeof 的输出结果取决于a,而a的值又没有被改变。

说明 sizeof 内部表达式并没有参与运算,只是推算了运算后的类型属性应该是 short 类型。同理,对于 arr[3],也只是推算出其类型属性是 int[4],所以可以计算出其大小为:16byte,而并没有真正的去运算,即并没有越界访问。

END


网站公告

今日签到

点亮在社区的每一天
去签到