C语言指针与二维数组求解

假设a是一个二维数组,a【0】是第一个一维数组名和地址。*(a+0)和*a都表示这个一维数组第一个元素的内容;而&a【0】和a【0】好像不等价啊?书上说*(a+0)、*a、&a【0】和a【0】是等价的。求解释

先请看看下面的小题:
 int main ( )
{
char a[2][3]={ {1,2,3} , {4,5,6} } ;
char (*p) [3];
p=a;
printf (“%d , %d , %d , %d ,%d ”, a , &a, *a, **a, *(*(p+1) + 2));
   return 0;
}
   请问输出该是多少?貌似很简单的一个题目,却不觉得让人看得有点头大。如果您已能很清晰地理解本题的话,那就无需再浪费您的时间了,请继续飘过吧…如果觉得有点疑惑的话,且听我细细道来。如果哪里说错了还请指正。
   先讨论下这个问题:char *pC; 假设此时pC里面的值是0x00012,如果pC++,那么pC会是多少呢?很显然是0x00013对吧。如果是int *pInt;也假设pInt 的值是0x00012,那么pInt++后的值就应该是0x00016了吧......关于这个问题你可以简单的理解为是由于地址对齐的缘故!说了这么多,我只想说,如果想看看某个指针指向的空间占多少字节,可以用这个方法。接下来用这个方法解释下面这些问题。

   且看第一句,这句很显然没问题,是人都知道这不过是定义了一个二维数组,两行三列,并且分别给它们赋值而已。大家一看就知道,a就是这个数组的首地址,这个每本书每个老师都是这样说的,虽然不知道为什么……

   第二句嘛,咋一看有点像个数组,可是括号里面却有个*p。好像比较少见。不急,大家可以联想到:char * p [3] ; 有眼睛的一看就可以看得出来,这只不过把括号给去掉了。好吧,我就看上面没有括号的那句,很显然,这句绝大多数人看一眼就知道这其实就是个指针数组,也就是:(char *) p[3] ; 跟普通的数组没啥区别,只不过这个数组里面每个成员都是个char *类型的字符指针。对没错,可是加了个括号呢?char (*p) [3]又表示什么呢?好,如果你开始觉得有点模糊了,那么你很正常,因为我刚开始也是这样的。再看看下面这两句:typedef char p_Char[3]; p_Char *p; 这句中的p表示什么呢?也许你还不是很清晰,但你应该可以确定是个某种类型的指针。如果你对这里的typedef的用法不太了解的话,那么也许你应该去百度一下关于typedef的用法,这里就不说了,我只告诉你此处的p跟上面的char (*p)[3] 是完全一样的效果。也就是说此处并不是定义数组,而只是个指针,而这个指针指向的变量不是普通的char,而是一个有三个元素的数组。你可以试试看sizeof(p)的值是多少,结果应该是4吧,会是个数组吗?你还可以输出一下p和p++的值,看看它们相差多少?应该是3吧!

   这第三句就更简单了,一个简单的赋值语句,把二级指针a(也就是二维数组的首地址)赋值给p(也是个二级指针)。

   第四句就是个输出语句,我们直接看后面的参数,a的值应该是数组的首地址吧,&a好像没这种用法,你有见过吗?如果你怀疑编译器会报错的话,你大可一试,至少我在VC6.0上面可以通过。a本身就是个地址,再取地址会是什么呢?也许你是这样想,不奇怪,我也这样想。再看看*a这个也可以理解,a是个地址嘛,*a也就是a这个地址里面的值咯。好像说的也没错。

   好吧,上面对那个小程序的一点分析只不过是个引子,接下来才是我真正要说的。我们来想想学了C语言后,一共有多少种数据类型呢?从int、short、long、double、char、char*、到char a[3],到int aa[5],再到struct a{ int a, char c; } aa ;我们可以看到可以共可分为三种,第一是最基本的类型,比如:int、short、char等......第二是在最基本的类型上扩充而来的,也就是数组,由多个相同类型组成的,第三种则是由不同的类型组成的,也就是结构体。

   我们再来看看如下情况:int a; char b[5]; struct a aa; 至于这是什么,也许你应该去看看谭浩强的C语言。那a、b、aa、的值分别是什么呢?当然这里并不关心它的真正值,只是想说明它们分别表示什么!很显然,a的值就是编译器在堆栈里面分配的4个字节空间里面的内容,aa也类似,但是b呢?b本应该也表示这5个字节里面所表示的内容,也就是说b本应该代表从b[0]到b[4]这几个空间里面的内容,但是需要注意的是因为它是数组,所以实际上编译器给出了单独的例外处理:当某处引用数组名字的时候并不代表数组里面的所有内容,而是代表了该数组的首地址。这说明:当我们用数组名字的时候要注意,一般情况,把它理解为地址,如果是形如“& 数组名”则还可把数组名看做数组整体内容。我们可以跟上面的a和aa对比一下,对于普通的a很显然,当引用a的时候我们就理所当然的以为是该空间里面所包含的内容,当我们引用结构体变量名的时候我们也理所当然的把他当做该结构体所占空间里面的内容,对于数组,按照我们刚才的那种思维逻辑,数组名其实也是代表这个数组里面真正包含的内容,而不是其首地址。是的我们本应该这样理解。但实际情况则不同,编译器不会这样做。这就是为什么我们老师苦口婆心不厌其烦地告诉我们数组名就是首地址的缘故了。所以回到刚开始那个问题,用我们上面的话说,&a中的a可以表示的是整个数组内容,所以取其地址还是数组地址,当然此时的a也可以理解成地址,但由于a是个二维数组,也就是个二级指针,那么&a就应该是个三级指针了。所以如果要把&a赋值给某个指针变量的话,那它应该是形如char (*p)[2][3]类型的变量了; *a表示的是什么呢?这个问题也很让人纠结......是表示数组的第一个元素的值吗?你可以试试,本题结果还是地址。为什么呢?接下来才是本文要说明的核心。

   相信大家都知道,一个一维数组的数组名是个一级指针,而二维数组的名就是个二级指针,三维数组的名字就是三级指针......以此类推。我是不知道您是怎么理解二级指针和三级指针的,在我看来,所谓二级指针其实也是个指针,只不过它指向的空间必须是个一级指针,而该一级指针指向的空间就是真正要指向的那个变量地址。也就是说一维数组名是个一级指针,那么对于char C[2]={1,2}; 因为C是个一级指针,所以&C就应该是二级指针了。C可以赋值给char *p类型的变量,而&C却只能赋值给char (*p)[2];类型的指针,注意此处的p也是个二级指针。这时你可以用上面的方法试试C+1和C的值相差多少个字节?应该是大2吧!*C的值就应该是数组的第一个元素的值了。对于二维数组char C[2][3]= { {1,2,3 },{4,5,6 } };C是个二级指针,你也可以试看看C+1和C究竟差了多少个字节?应该是6吧!既然C是个二级指针也就是说*C是个一级指针,虽然指向的地址和C指向的地址是同一个,但是此时表达的意义就大不一样了。C是个二级指针,而且它指向的范围是从1~6,而*C是个一级指针,范围从1~3,你可以试试(*C+1)和*C相差多少?应该是3吧!。那**C呢?很显然一级指针指向的空间就不会是地址了,而应该是地址里面的内容了,也就是1。对于三维、四维等情况都是类似的,以此类推.....

   最后我们来看看 *( *(p+1) +2 )的值会是多少?首先p是个指针,里面存放的地址是一个char[3]类型的地址,而p又被赋值了a,所以p+1就应该指向下一个char[3]类型的地址,也就是指向了a数组的第二行首地址,*(p+1)很显然就是指数组a的第二行里面的内容,根据刚才的分析,如果是数组的话,一个表示数组整体内容的其实就是用其首地址来表示,所以*(p+1)表示的是数组a的第二行的首地址,然后*(p+1) +2 表示的就是第二行的第二个地址,最后*(*(p+1) + 2)表示的就是第二行的第二个地址所存放的内容,也就是6。

   貌似我把一个很简单的问题说了很多,接下来我要问问几个问题看看你究竟理解了我说的没有,请看下题:
对一维数组:char C[3];,请问如何定义一个指针变量P0,使得这句:P0=C;能通过编译?如何定义一个指针变量P1,使得P1=&C能通过?*C表示什么?
对二维数组:Char C[2][3];如何定义一个指针变量P0使得P0=C;能通过编译?如何定义指针变量P1使得可以P1=&C; *C表示什么?**C又表示什么?这些有啥区别和联系?
后面的我就不多说了,如果你能很清晰的理解这些东西,那么你就懂了,否则那就请把本文再从头看一遍吧!

   以上只不过是个人的小孔之见,如果您不同意,欢迎指正,谢谢!

参考资料:http://zhidao.baidu.com/team/view/Linux%E5%86%85%E6%A0%B8

温馨提示:答案为网友推荐,仅供参考
第1个回答  2012-12-22
假设a是一个二维数组,

一、a【0】是第一个一维数组名,数组名 就是该数组的 首地址!
二、*(a+0)和*a都表示这个一维数组第一个元素的内容; 这句话有问题,应该是:都表示这个 二维数组 第一个元素的内容!
三、&a【0】和a【0】好像不等价啊? 关于数组名和&数组名书上有明确的介绍与说明:a==&a==a[0]==&a[0]这是规定!!细节请看教科书。
四、书上说*(a+0)、*a、&a【0】和a【0】是等价的! 是的,就是这样

前面说了a==a[0]==&a[0]这是规定
*a == *(a+0) 这是个简单的运算,应该好理解吧

其实二维(多维亦同之)数组,可以看成其元素是数组的一维数组!好好理解这句话!
a是(二维)数组首地址(即a的值是数组首地址),*a是数组元素, 而这个数组元素又是个数组B,所以*a的值就是数组B的首地址,而B与a的开始位置是相同的,故*a的值与a值是相同的!
简单打个比方,二维数组好比是一栋楼,分三个单元,每单元6层,即:a[3][6];
一单元一层即是整栋楼的第一户,也是该单元的第一户。本回答被提问者和网友采纳
第2个回答  2012-12-22
a【0】是地址,也是第0行的首地址,而&a【0】则是第0行首地址的地址,可以理解成第二层地址。a是整个数组的首地址,也是第0行的首地址,英寸a 和啊【0】是等价。*(a+0)其实就是*a,所以也相同了。如果说&a【0】【0】和a【0】是等价的那就没问题,说&a【0】和a【0】是等价的,我认为是不对的。
第3个回答  2012-12-22
&a[0]表示的是a[0]的地址
相似回答