免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: mickgrady
打印 上一主题 下一主题

二维数组指针,编译器到底为我们处理了多少 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2011-03-15 13:19 |只看该作者
本帖最后由 davelv 于 2011-03-15 13:21 编辑
这里绝对有些说法, 为什么  a 和 *a的值一样。这我们熟知的指针和引用一样吗  不要把大家知道的现象做为解 ...
mickgrady 发表于 2011-03-15 13:13

二维数组 其实准确的讲叫做数组的数组。
也就是说,你对二位数组解引用得到的是一个一维数组。由于它们起始位置相同,所以他们的数值是相同的。
数组不是指针,只是跟指针有比较多的相通之处,如果事事都一样就没有必要取两个名字了。

论坛徽章:
0
12 [报告]
发表于 2011-03-15 13:20 |只看该作者
a是指向一串数组的头, *a的类型是指针, *a的内容就该是从头开始数4个字节。 *a的内容是上面输出的那个地址值 那a[0][0]去哪啦   a[0][0]做为整型也该4个字节。  照这个逻辑 以a地址开始的前四个字节该是 *a这个指针还是a[0][0] ?(当然我们实际上知道是a[0][0],只是逻辑推理不成立,所以我想有些东西编译器是给处理了的,我是想知道是不是有这种处理,有的话是什么规则?)

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
13 [报告]
发表于 2011-03-15 13:22 |只看该作者
a是指向一串数组的头, *a的类型是指针, *a的内容就该是从头开始数4个字节。 *a的内容是上面输出的那个地址 ...
mickgrady 发表于 2011-03-15 13:20



    你再试试三维数组,想想a, *a, **a为什么会一样,还是自己去理解吧

论坛徽章:
1
黑曼巴
日期:2020-02-27 22:54:26
14 [报告]
发表于 2011-03-15 13:24 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
15 [报告]
发表于 2011-03-15 13:26 |只看该作者
本帖最后由 davelv 于 2011-03-15 13:27 编辑

回复 12# mickgrady
按照类型来确定数据,你这里说的类型混乱了。
a[x][x]是二维数组,*a就是一维数组,而不是开始的头4个字节。
数组是数组,指针是指针。不要拿看待指针的眼光看待数组,它们有各自不同的语法基础。
编译器具体该怎么什么可以参考 ISO手册部分章节和额外的Rationale部分。当然这都是指导性文献,具体实现方法各有不同。

论坛徽章:
0
16 [报告]
发表于 2011-03-15 14:41 |只看该作者
**a 取的才是真正的值  之前的都是取的地址

论坛徽章:
0
17 [报告]
发表于 2011-03-15 15:15 |只看该作者
对于指针,类型是我们需要时刻关心的。
楼主如果用gdb调试:
(gdb) p a
(gdb) p *a
(gdb) p **a
(gdb) p a[0]
(gdb) p *a[0]
(gdb) p (a+1)

看看这些的输出想必有更好的认识。
或者
printf("%d\n", *(int *)a);
看看这语句在代码里的输出...

论坛徽章:
0
18 [报告]
发表于 2011-03-15 15:40 |只看该作者
a是二维数组的首地址,*a是a[0]行的地址,**a是第一个元素的值,(a+1)是第二行的地址

论坛徽章:
0
19 [报告]
发表于 2011-03-15 15:59 |只看该作者
楼主可能想知道这个?

*只能作用于数组,指针,和函数
对于函数,没什么好说的
#include <stdio.h>
int main()
{
        (***** /* any times */ *******printf)("hello, * indirection\n");
        return 0;
}

接下来作用于指针或者数组
int *p;
...
int main()
{
    printf("%d\n", *p);
};
p指向的对象是int, 所以*p是左值,其值所指向的地址包含的内容,具体几个字节取决于对象类型
生成如下类似的指令

movl addrp, %eax # not movl $addrp, %eax
movl eax , (%esp)


int a[2][3];

因为 a 指向一个一维数组: *的操作数进行普通的一元转换
所以a(2维数组被转化为指向一维数组的指针)
   (标准里都有
   K&R    A7.1 指针生成
   对于type t[N],  t[0]其值是指向数组中第一个对象的指针,这个应该不难理解
   int a[3], a[0]就是数组    中第一个int的指针, 就是*(a + 0))

a指向一维数组, 所以*a不是左值
(K&R, A7.4 3间接寻址运算符 这小节说明了什么情况下*a是左值,什么情况下不是,我就不抄写了)

因为*a不是左值, *a 的值 == a的值, 在编译时刻就知道了, *a的类型是一维数组
同样 **a就是个左值了


不是每个人写程序都想标准怎么说,通常知道int a[2][2]; *a *a[1]是什么就足够了

论坛徽章:
0
20 [报告]
发表于 2011-03-15 19:29 |只看该作者
建议楼主看一下<C专家编程>
因为你是这样声明的 int a[2][2],所以a是一个一维数组, 这个数组的每一个元素又是一个数组 int [2].
因为a的值为3216495792,所以内存应该是这样的
1                           2                           3                             4
3216495792         3216445796          3216495800          3216495804
a 的值是3216495792可以理解,因为它是内存地址, 那么*a 的值为什么和a的值相同呢? 是因为*a表示a的第一个元素的值(即a[0]). 那么*a又表示什么呢? 因为a[0]它代表的是一个数组, 所以*a就是这个数组的首地址(第一个元素的地址),接下来**a就应该是1了.
a+1表示a[1]的地址.因为a[0], a[1]它们的元素是一个长度为2 的数组,所以a+1的1它实际代表的是8个字节,所以值为3016495800
*(a+1)(即a[1])就是数组的首地址.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP