关于C语言中对数组取址的问题,详见补充:

问题简化一下:定义一个数组INT8U a[4];
然后对它进行强制转换(看官们不用考虑大小端的问题啊),有三种写法:
1,*(INT32U *)a;
2,*(INT32U *)(&a[0]);
3,*(INT32U *)(&a);
请问第3种写法是否正确?我认为是错误的,但是为什么编译和实际运行都没有问题?如果是正确的,该如何理解?

对于一个数组来说,数组名是一个地址常量
并不是说是一个地址常量就没有地址(也就是存储常量的存储单元)
当程序没有被调入内存时候,是由三部分代码组成的,依次是二进制代码区(text segment),已经被初始化的静态或者全局变量区(data segment),没有被初始化的静态或者全局变量区(bss segment),常量都是存放在data segment区
当程序被调入内存之后,就在三部分的基础上又被分配了堆区和栈区,栈区用来存放临时变量,参数和返回值等临时的变量
就相当于我们定义char *a="12345",我们都知道这里的“a”是main()中定义的一个指向字符串“12345”的指针,那么“12345”是存放在哪里的呢,就是存放在data segment区的,而“a”变量本身确实存放在程序调入内存后被自动分配的栈区
强制转换的本质上是不改变存储单元中的01代码组合的,只是告诉编译器这个单元的数据将要被作为什么数据处理,例如一个指针变量占据4字节,一个int变量也是四个字节,我们就可以把int强制转换成指针的,需要的时候再把指针转换成int,输出int型结果时是不发生变化的
在这个题目中,“a”是一个数组名,也就是一个地址常量,这个常量存放在data segment区,“&a”取了“a”的地址,也就是一个指向“a”的指针,所以第三个语句是把指向“a”的指针进行了强制转换,第一个语句直接转换的“a”,第二个语句强制转换指向“a[0]”的指针
温馨提示:答案为网友推荐,仅供参考
第1个回答  2014-10-09
数组与指针的问题,必须弄清楚指针的类型这一概念,一维数组int a[5]; 数组名a相当于一个指针,他的类型是“指向int的指针“ ,a与&a[0]是等价的, 而&a; 的类型则是“指向一维数组的指针“,这个一维数组有5个元素,a与&a的地址值是相同的,但他们的类型完全不同,类型决定了再进行计算时进行怎样的操作,比如a+1,指针只偏移1个int大小的单位,但&a+1就会偏移一个含有5个元素的一维数组的单位,也就是偏移5个int这么远。二维数组也是同样的道理,比如int a[3][4]; 其中a与&a[0]相同表示的是一个指针,他的类型是“指向一维数组的指针”这个一维数组有4个元素,同理&a表示的是“指向二维数组的指针”,这个二维数组的形式是[3][4],而a[0]与&a[0][0]相同,表示的是“指向int的指针“,但是,a, &a, a[0]他们的地址是相同的,唯 一区别在于类型不同,类型不对就决定对其指针进行运算时,其计算的方式就会有很大不同。对于数组与指针,指针的类型就显得相当重要,这是一般的教材里面从未提到的。具体更详细的内容请参阅本人所作《C++指针与数组专题》有详细介绍,怎样理解二维及多维数组与指针的关系。
第2个回答  推荐于2018-04-19
(a) 是一维数组首地址,
(&a[0]) 还是一唯数组首地址 与(a)等价
(&a) 二唯数组首地址,其一唯的宽度就是数组a的元素个数
首地址值是相同的,而你都做了强制转换,所以看不出差别
如果用以下方法,就可以看出差别了
printf("%x ", (void *)(a+1) ); //==&a[1]
printf("%x ", (void *)(&a[0]+1) ); //==&a[1]
printf("%x ", (void *)(&a+1) ); //==&a[sizeof(a)+1]追问

你好,再请教一下,我定义的是一维数组,如何理解(&a)变成二唯数组首地址了呢?是编译器的默认处理吗?

追答

a本来就只是一个数组的首地址,不是指针变量,但相当于一唯指针,对它取地址,系统会让为是把这个数组整体当一个元素而得到的指针,这指针首地址没变,而做+1等地址运算时,是直接以整个数组为元素向后移指针的,这种行为就说明它是比这个a多一唯层了
应当是编译器处理的规则,,更且体的归纳如下:
int i; i只是一个0唯的(只有一个元素)
int *p=&i; 此时p可以算是比i多一唯层,也就是可以当作一唯数组,指向0唯元素
int **p2 = &p; 看得出p是或相当于一唯数,而&p却是又多一唯层,属于二唯,指向1唯元素
int ***p3 =&p2; 很明显,对二唯指针取地址得到的是三唯的指针....指向二唯元素
......
数组名和指针的区别在于,数组名是const型指针,不能对指针本身赋值,不能改变指针本身
除此之外两者有区别吗,没有,所以,对于 int a[4]; a是一唯的指针(常量), &a当然是成了二唯的指针类型了

本回答被提问者和网友采纳
第3个回答  2012-01-13
不好意思,刚才回答太轻率了。

请看如下程序:

#include "stdio.h"
void main()
{
int a[4];
// int *p=&a;
int (*q)[4]=&a;
int *s=a;
printf("%d %d\n",a,&a);
}
这个程序可以说明,a是int *类型,而&a是指向int [4]数组的指针。所以a和&a是类型不一样,但值是一样的。

所以,你的问题中,a,&a[0]和&a,虽然类型不完全一样,但就数值来说是一样的,在统一强制类型转换为(INT32U *)后,当然就成一样的了。追问

你好,你提到“&a是指向int [4]数组的指针”,我不大理解啊,应该是"&a[0]是指向int [4]数组的指针"才对吧?我的困扰正是在此。

追答

a[0]是数组a中的元素,类型是int,取&后的类型当然是一级指针int *
a是长度为4的int数组,&a的类型是指向长度为4的int数组的指针,即int (*)[4]

第4个回答  2012-01-13
[root@localhost test]# gcc -g jh_te.c
[root@localhost test]# ./a.out
a:1234
a---:3212929955
a---:3212929955
b:875770417
c:875770417
[root@localhost test]#
[root@localhost test]#
[root@localhost test]#
[root@localhost test]#
[root@localhost test]#
[root@localhost test]#
[root@localhost test]#
[root@localhost test]# cat jh_te.c
#include<stdio.h>
int main()
{
char a[5]={'1','2','3','4', 0};
printf("a:%s\n", a);
printf("a---:%u\n", &a);
printf("a---:%u\n", a);
int b = *(int *)(&a);
int c = *(int *)(a);
printf("b:%d\n", b);
printf("c:%d\n", c);
}
==========================这是我写的测试代码,看起来的确,a和&a是没区别的。
一下是我的推测:
&这个操作符号的意义是:取地址,但是如果操作的对象本身已经是一个地址变量了,就不会产生作用。
相同的情况也发生在函数名上,
比如:
void func_t();
func_t这个变量其实是一个地址,即函数的入口,看如下代码:
void *p = func_t;
这样我们通过p就能调用func_t这个函数,其实
void *p = &func_t;
也是一个作用,上述两句代码本身没有实质差别。
由此我推测:如果&的操作对象本身已经是一个地址,&就不会再起什么作用了。
=================================================================
再进一步的测试:
假如是char a[4];
&a 和a还是有区别的,但是你这里恶心在a[4]大小是4,如果你改一个别的大小,比如:a[5],最直观的区别就是:
sizeof(&a)=4,sizeof(a)=5.
同时如果你写if(&a == a)这样的代码,(其实他们的值是一样的哦)
编译时会有错误,说这两个量类型不统一。
所以:
a虽然是一个指针,但是还不是最纯粹的指针,它指向数组的首地址的同时,是一个指向特定类型的指针,比如char,就是它的移动单元是以数组大小为单位的,移动单位是1个字节。
&a则是纯粹的指针了,也是指向数组的首地址,但是它的移动单位就是4字节。追问

不好意思,再请教一下,定义a[5]的话为什么sizeof(&a)=4?应该也是5了啊。