在看《深入浅出MFC》的时候,遇到了如题的问题,去网上查了下,原来如此
原帖地址http://topic.csdn.net/u/20090825/21/6d302f2e-4ba2-4aca-987b-afe1a5ef84f6.html
现摘录几个比较好的回答
先看问题:
在数组中:如a[3][4]
我通过下面一段程序发现:通常说a实质是数组的地址,那么:
int a[3][4];
cout < <&a < cout < cout < cout < 结果:
0012ff40
0012ff40
48
48
发现,对a取地址竟然能得到了数组的地址。地址的地址????这作何解释呢?
同时:发现a的地址占用48个字节,这有作何解释?希望大家帮忙解答
答:
1.
问题一:有一句比较拗口的话,你对数组名取地址当然取到的是数组的地址,而不幸的是c又规定数组名的值就是数组地址
问题二:sizeof是关键字,不是函数,数组名在sizeof的时候不退化为指针,所以sizeof的是整个数组的大小,3*4*4 = 48
2.
0x22ff40
0x22ff40
4
48
在我的编译器上得到了如此的结果(GCC 4.4.0,vc2008,icl 11.1)足以证明第二个问题是编译器决定的,标准没有强制规定。如果强制规定了,那么,正确的结果应该是我的结果。
3.
a是int[3][4]类型
&a是int*[3][4]类型
会输出48就是自然而然的事情了
数组名和指针会有混淆分析的错觉,但是编译器看到指针 会取出里面的内容 然后在根据这个内容取地址,需要两次访问
看到数组名 则可以直接知道地址 只要一次访问内存就可以了
4.
cout<
cout<
也可以在调试的时候看看下面那个窗口 会显示a和&a的类型 不过早期的编译器(vc6)好像对&a显示有误 和后来的版本不一致
5.
对于数组a[3][4],都会说是2维数组a,那么&a当然是取数组的地址,这个有什么可怀疑的,而a本身又是数组的首地址,所以&a和a的值是一样的,而sizeof的区别就看编译器是把你当成指针来处理还是当成数组来处理,这点借鉴一下4楼的说法,可能&a会被有些编译器当成一个指针
另外说一下你在7楼的问题
sizeof的是内存空间大小,而不是地址大小
地址的长度都是4,也就是指针在内存中占用的空间,话说解释到这我也有点无奈了
6.
引用 10 楼 operatingtuzi 的回复:
a是int[3][4]类型
&a是int*[3][4]类型
会输出48就是自然而然的事情了
数组名和指针会有混淆分析的错觉,但是编译器看到指针 会取出里面的内容 然后在根据这个内容取地址,需要两次访问
看到数组名 则可以直接知道地址 只要一次访问内存就可以了
&a不是int*[3][4]类型
&a是int (*)[3][4]类型
7.
引用 16 楼 ly309431053 的回复:
上面对第一问题解释:cout < <&a < cout < 第二问题解释:cout <
不好意思,我的第二问题说错了,cout < sizeof(&a)得到的是一个指针变量的字节数,相当于sizeof(int*),而不是a所指的内
存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。
我在vs2008下调试一下你的问题,字节数是4
8.
#include"iostream.h" void main() { int a[3][4]; cout <<&a <
9.
我认为你问的问题属于编译系统不遵循标准的范畴.
证明如下:
(1).权威的圣经 < >英文第4版上有这样一句定义 address-of operator 的话:Takes a single argument that must be an lvalue.即它的操作数必须是 lvalue.
(2).在 VC++6.0 上编译如下程序,会提示语法错误:
int main( void )
{
int a[10] = { 0 };
int b[10] = { 0 };
a = b;
return 0;
}
编译系统提示语法错误:error C2106: '=' : left operand must be l-value
即VC++6.0认为 left operand 不是 l-value,既然它认为 a 不是 lvalue,那么对 &a 又不提示语法错误,所以可以证明你问的这个问题属于编译系统不遵循标准的范畴.
最后结论: 对于数组a来说 ,a的地址和&a是一样的,而且 sizeof(a)为该数组在内存中实际的大小,sizeof(&a) 为4
转篇文章
一、多维数组地址的表示方法
设有整型二维数组a[3][4]如下:
0 1 2 3
4 5 6 7
8 9 10 11
设数组a的首地址为1000,各下标变量的首地址及其值如图所示。
在前面曾经介绍过, C语言允许把一个二维数组分解为多个一维数组来处理。因此数组a可分解为三个一维数组,即a[0],a[1],a[2]。每一个一维数组又含有四个元素。例如a[0]数组,含有a[0][0],a[0][1],a[0][2],a[0][3]四个元素。 数组及数组元素的地址表示如下:a是二维数组名,也是二维数组0行的首地址,等于1000。a[0]是第一个一维数组的数组名和首地址,因此也为1000。*(a+0)或*a是与a[0]等效的, 它表示一维数组a[0]0 号元素的首地址。 也为1000。&a[0][0]是二维数组a的0行0列元素首地址,同样是1000。因此,a,a[0],*(a+0),*a,&a[0][0]是相等的。同理,a+1是二维数组1行的首地址,等于1008。a[1]是第二个一维数组的数组名和首地址,因此也为1008。 &a[1][0]是二维数组a的1行0列元素地址,也是1008。因此a+1,a[1],*(a+1),&a[1][0]是等同的。 由此可得出:a+i,a[i],*(a+i),&a[i][0]是等同的。 此外,&a[i]和a[i]也是等同的。因为在二维数组中不能把&a[i]理解为元素a[i]的地址,不存在元素a[i]。
C语言规定,它是一种地址计算方法,表示数组a第i行首地址。由此,我们得出:a[i],&a[i],*(a+i)和a+i也都是等同的。另外,a[0]也可以看成是a[0]+0是一维数组a[0]的0号元素的首地址, 而a[0]+1则是a[0]的1号元素首地址,由此可得出a[i]+j则是一维数组a[i]的j号元素首地址,它等于&a[i][j]。由a[i]=*(a+i)得a[i]+j=*(a+i)+j,由于*(a+i)+j是二维数组a的i行j列元素的首地址。该元素的值等于*(*(a+i)+j)。
[Explain]
#define PF "%d,%d,%d,%d,%d,/n"
main(){
static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
printf(PF,a,*a,a[0],&a[0],&a[0][0]);
printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
printf("%d,%d/n",a[1]+1,*(a+1)+1);
printf("%d,%d/n",*(a[1]+1),*(*(a+1)+1));
}
二、多维数组的指针变量
把二维数组a 分解为一维数组a[0],a[1],a[2]之后,设p为指向二维数组的指针变量。可定义为: int (*p)[4] 它表示p是一个指针变量,它指向二维数组a 或指向第一个一维数组a[0],其值等于a,a[0],或&a[0][0]等。而p+i则指向一维数组a[i]。从前面的分析可得出*(p+i)+j是二维数组i行j 列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值。
二维数组指针变量说明的一般形式为: 类型说明符 (*指针变量名)[长度] 其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型。 “长度”表示二维数组分解为多个一维数组时, 一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指针数组(本章后面介绍),意义就完全不同了。