那么什么时候数组&指针是相同的呢?
在c语言的标准中有如下说明:
1:表达式中的数组名被编译器当作一个指向该数组的第一个元素的指针。
2:下标总是于指针的偏移量相同。
3:在函数的声明中,数组名被编译器当作指向这个数组的第一个元素的指针。
对于第一点比如:
int a[10],*p,i=2;
有几种访问a[i]的方式,作用是一样的。
[1]:p=a;p[i];
[2]:p=a;*(p+i);
[3]:p=a+1;*p;
由此♂得出,对数组下标的引用总是可以写成“一个指向数组首地址的指针&偏
移量的和”
对于第三点的理由很简单,数组可能很大,如果作为形参也用传值的方式的话没
那么时间&空间上面来说是实在过不去的。
多维数组
♂知道一维数组的名字就是一个指针常量。那么多维数组也差不多。唯一的区别
就是,多位数组第一维实际上指向的是另外一个数组。
例如:
int max[3][4];
那么,max实际上是一个指向10个int元素的指针。
max+1就是指向max的下一行的10个元素。
*(max+1)也是一个指针,也许有点难理解,那么这么看吧.max[1]是什么?是一个
数组,那么这个数组名max【1】不就是一个指针么?数组名的值是个常量指针。
它指向数组的第一个元素。max[1]=*(max+1);
例子:
#include<iostream>
using namespace std;
int main()
{
int a[3][2]={1,1,3,5,4,7};
cout<<a<<" "<<*(a+1)<<" "<<&a<<" "<<a[0]<<endl;
system("pause");
}
可以看出上面的观点。*(a+1)仍然是一个指针,指向当前行的首元素。
那么自然,*(max+1)+5;就是指向当前行的第6个元素了。
现在*(*(max+1)+5)才是对int的解引用,访问了那个整型变量。
指向数组的指针
int vector[10],*vp=vector;//合法,指针指向数组首元素。
int vector[3][10],*vp=vector;//不合法,在这里,vp是一个指向整型的指针,
但是vector却是一个指向整型数组的指针,在这里类型不匹配。
正确的声明应该是
int (*vp)[10]=vector;//按照在《怎么读一个很长的声明中》说得,这个应该读
成:vp是一个指向有10个整型元素的指针。ok 类型匹配了。这个时候vp指向
vector的第一行。
也许这不能满足你的要求,你希望有一个指针能遍历这个数组的所有元素,而不
是现在只能一行一行的取值。
那么这两个可以满足:
int *p=&vector[0][0];
int *p=vector[0];
作为函参数的多维数组
上面说过了,数组作为函数参数是作为指针传递的。多维数组也是一样。但是区
别在于多维数组的每个元素本身是另外一个数组,编译器需要知道它的维数。
例如:
int vector[3][4];
这个二维数组传递给函数的时候要这么写。
void fun(int (*p)[4]);
or
void fun(int p[][4]);
其中第二维是必须的,因为编译器需要知道这个维长度才能对下标求值。
关于二维数组传参常犯的错误就是
void fun(int **p);
看出来了么?这个指针根本没有任何关于维数的声明,所以数错误的。
--参考书籍《c&指针》《c专家编程》
上面第1和第3点错误,只要说到数组名是指针,全错。
“多位数组第一维实际上指向的是另外一个数组。”这句话也错,C实现的是数组的数组,不是多维数组,多维数组与数组的数组有本质的区别,多维数组根本就不是“第一维实际上指向的是另外一个数组”,这句话用在数组的数组上才是正确的。
C专家编程上面的错误已经在你身上表现出来了。
悠然自得 —— 2005年08月27日 @11:13 pm
在c&c++中 多维数组就是被看作数组的数组的,不知道悠然自得兄说是“本质的区别”是什么那?
sun —— 2005年08月27日 @11:47 pm
c语言迫于本身的语言特性,没有实现多维数组,而是用数组的数组当作多维数组。由于数组的数组与多维数组的内存映象和使用方式都是相同的,使得许多C程序员对这两种数组的区别模糊不清。
数组的数组与多维数组的主要区别,就在于数组的数组各维之间的内在关系是一种鲜明的层级关系。对于数组int a[7][8][9],如果要访问元素a[4][5][6],它的地址就得这样获得:先通过*(a+4)求出第一维第5个数组的地址,然后计算第二维第6个数组的地址*(*(a+4)+5),最后才能得出a[4][5][6]元素的地址:*(*(a+4)+5)+6。这个过程是需要层层解析的。
而真正的多维数组并没有这么多“束缚”,由于各维之间不是层级关系,元素a[4][5][6]的偏移量可以这样直接获得:(4×8x9+5×9+6)xsizeof(int),再加上数组的首地址就是元素a[4][5][6]的地址了。
但是,c语言的数组能够这样用首地址加上(4×8x9+5×9+6)xsizeof(int)的形式来访问元素吗?显然是不行的。根本原因就在于C语言的地址不但有类型,还有层级关系。就是这种层级关系造成了C语言只能用数组的数组当作多维数组。如果C语言非得要实现真正的多维数组,那么地址与指针的概念就得重新改写了。
悠然自得 —— 2005年08月30日 @9:00 am
to 悠然自得
看了你写的东西。虽然翻遍了手头的参考书《c专家编程》,
《c&指针》,《高质量程序设计指南》,深入理解计算机系统……等等,都支持我在上面写的那些,可是我依然觉得你说得似乎更有道理一点,或者是我的理解能力还没有达到,关于这些个问题我想到图书馆作更深一步的探究。
顺便,请推荐几本相关资料好么?
再次感谢。
sun —— 2005年08月30日 @1:02 pm
引用:
“但是,c语言的数组能够这样用首地址加上(4×8x9+5×9+6)xsizeof(int)的形式来访问元素吗?显然是不行的。”
为什么不可以呢?
我试了一下,在tc2.0下,a[4][5][6]的地址与&a[0][0][0]+(4×8x9+5×9+6)的值是一样的
yzx_1983 —— 2005年08月31日 @10:25 am
晕了,高手赶紧出来澄清一下
yellow —— 2005年08月31日 @2:13 pm
这个地址值当然是一样的,不一样就不对了。
&a[0][0][0]并不是数组的首地址,a才是数组的首地址,虽然a这个值跟&a[0][0][0]这个地址值是相同的,但两者意义是不同的,类型也不同的。&a[0][0][0]仅仅表示a[0][0][0]这个元素的地址。
在C数组里面有很多这种地址值相同而意义不同类型不同的概念,我现在这么说你有可能无法理解。请你在往后的日子里留意一下我的blog,URL是http://blog.csdn.net/megaboy。我在blog里谈了关于数组与指针的十个专题,前面几个贴子的内容是从我的blog里节选出来的,现在这个blog还剩一点没有写完,里面的文章我还没有发布出来。你自己留意一下吧。
悠然自得 —— 2005年09月01日 @11:00 am
呵呵,希望早日看到您blog的大作^_^
在此之前先说说我的理解:
&a[0][0][0]应该是一个带类型的地址吧,用它来进行加减运算总是以一个int的长度为单位,而a作为一个三维数组的首地址,对它进行加减运算就会是以8*9*sizeof(int)为单位了。不知道您是不是这个意思呢?
yzx_1983 —— 2005年09月01日 @11:09 am