鱼C论坛

 找回密码
 立即注册
查看: 2441|回复: 7

S1E24第5题,看过答案了,但还是有问题!

[复制链接]
发表于 2019-12-10 21:28:32 | 显示全部楼层 |阅读模式
5鱼币
先看原题代码:
#include <stdio.h>

int main()
{
        int array[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        int (*p)[3] = (int (*)[3])&array;

        printf("%d\n", p[2][2]);

        return 0;
}

上机测试,输出结果为9,答案解释关键的一句: int (*p)[3] = (int (*)[3])&array;  等号右边强制将 array 这个一维数组重新划分成 3 * 3 的二维数组,然后用数组指针指向它。

这里我还是不理解, (int (*)[3])是怎样把强制将 array 这个一维数组重新划分成 3 * 3 的二维数组的?

如果说解释是:&array代表一个9个元素的一位数组整体的地址,所以前面的[3]把这个一位数组三等分了?但后面说用数组指针指向它,也就是p指向的是一个二维数组,那么p的值是二维数组的地址还是二维数组第一个一维元素的地址?

正常来讲,我们定义一个指向2维数组的指针写法是:
int (*p)[3][3] = &array;(此处array是一个3*3二维数组的名字)

然后用数组的方式表达最后一个元素应该是p[0][2][2],但原题目中的输出是p[2][2],这说明原题中的P指向的是二维数组的第一个一维元素的地址,而不是指向这个二维数组。

感觉这里还是有点混乱,跪求大神指点,越详细越好,谢谢!

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-12-10 21:42:58 | 显示全部楼层
首先你要理解什么叫强制转换
如:
char c;
(int) c; 就把c强制转换成了int类型

这里也一样,array[9] 是一个1维数组, 那么array &array 都是数组首元素的地址,也是数组的地址。

(int (*)[3])&array 和 (int (*)[3])array 都是将这个地址强制转换为 数组指针,而这个数组指针在这里的说法就是  (3 * 3 的二维数组,然后用数组指针指向它。) 也就是二维数组指针
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-12-10 22:36:31 | 显示全部楼层
本帖最后由 jackz007 于 2019-12-11 00:32 编辑
  1. int (*p)[3] = (int (*)[3])&array;
复制代码

        这是强制类型转换,等号左边的 p 是一个指向末维为 3 的二维整型数组的指针,在等号右边,array 本来是一个一维整型数组,只是为了迎合等号左边 p 的类型,所以,才在 array 前面添加了强制类型转换符,成为 (int (*)[3]) & array,这样,可以把 & array 视为一个 3 x 3 的二维数组,一、二维数组元素之间索引的对应关系为:
  1.            二维数组                         一维数组
  2. & array[0][0] ~ & array[0][2]  对应于 array[0] ~ array[2]
  3. & array[1][0] ~ & array[1][2]  对应于 array[3] ~ array[5]
  4. & array[2][0] ~ & array[2][2]  对应于 array[6] ~ array[8]
复制代码

        所以,不管数组在形式上是一维的还是多维的,归结到本质全都是一维的。所谓的 "数组划分",其实并不会对数组本身进行任何物理上的改变,只是为了便于访问,对数组的索引方式进行了一种逻辑上的重新规划而已。如果通过指针访问,就更加简单:
  1. p[i][j]     或    * (* (p + i) + j)      对应于     array[i * 3 + j]  
复制代码

        当然,这样访问更加简单粗暴:
  1. p[0][k]     或    * (* p + k)           对应于     array[k]
复制代码
   
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-12-11 08:55:46 | 显示全部楼层
ba21 发表于 2019-12-10 21:42
首先你要理解什么叫强制转换
如:
char c;

你说的我大概都清楚,但对于强制转换的规则还存在疑惑,比如我们强制转换一个int类型数据为char类型,那系统会怎么操作,是不是把int数据的某一个字节(第一个字节)内容保留,作为char的数据值?你说的(int (*)[3])&array 和 (int (*)[3])array 的确是将地址强制转换为数组指针,但关键是将哪部分内容转换为(看作)什么形式的内容,(int (*)[3])&array 和 (int (*)[3])array 两个作用的对象不同,结果应该是不一样的吧,前面的是整个数组,而后面的是第一个元素的地址,,不过我刚才上机试了一下,貌似没发现什么区别。。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-12-11 09:10:25 | 显示全部楼层
jackz007 发表于 2019-12-10 22:36
这是强制类型转换,等号左边的 p 是一个指向末维为 3 的二维整型数组的指针,在等号右边,array  ...

所以(int (*)[3])&array 和 (int (*)[3])array实际上是没区别的?只是个形式?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-12-11 09:24:25 From FishC Mobile | 显示全部楼层
本帖最后由 jackz007 于 2019-12-11 09:45 编辑
dequantianhe 发表于 2019-12-11 09:10
所以(int (*)[3])&array 和 (int (*)[3])array实际上是没区别的?只是个形式?


         是的,但是,你不可以把等号右边的 '&' 去掉,如果去掉的话,等号两边的逻辑关系就不对称了,编译器会拒绝的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-12-11 10:11:18 | 显示全部楼层
jackz007 发表于 2019-12-11 09:24
是的,但是,你不可以把等号右边的 '&' 去掉,如果去掉的话,等号两边的逻辑关系就不对称了, ...

额,我上机试了,可以去掉&的,没影响,不过我通过多次调试,发现在自己真正的疑惑所在,开始我一直以为(int (*)[3])&array 定义后,p指向的依旧是array数组的整体,其实不是,array是被看作了3*3的数组,但实际上P指向的只是元素1、2、3的首地址,解开这个疑惑,就都讲得通了,我抓紧再总结下,看究竟是我哪里之前掌握的不牢靠。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-12-17 17:13:55 | 显示全部楼层
本帖最后由 fishcyky 于 2019-12-17 17:27 编辑

&array 是得到数组中每个元素的地址,
(int (*)[3]&array 就可以写成
(int (*)[3]){1的地址,2的地址,3的地址,... , 9的地址}
这是是一个数组指针,指针指向了一个有3个地址元素的数组,然后元素划分就等分了,我试了试将元素改成8个,指向的值就是随机的了。但是将指向改成p[2][1]就没有问题。
这可能跟分配有关了。。

然后这就相当于int (*p)[3] 这个数组指针指向的是这个(int (*)[3]){1的地址,2的地址,3的地址,... , 9的地址}有3个地址元素数组指针了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-19 05:42

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表