关于多维数组,指针,及函数参数你所必须知道的一切

1.多维数组的数据类型:

首先,数组是数组,指针是指针,数组名不是指针。

不解?正常。不少C语言老师常常告诉学生:“数组名就是指向数组首元素的指针。”这句话只说对了一半,数组名的确可以当作指针使用,在不少的场合,数组名会被隐式地转换为指针(这种转换叫做退化,另一种退化发生在函数到函数指针的转换中)。但是数组不是指针,对于一个数组,int a[5],它的类型是int [5],能退化为int*类型,数组int b[5][4],它的类型是int [5][4],能退化为int (*)[4]类型,也就是说,它们能被隐式地转换为将它们看作一维数组时的首元素的指针。

2.多维数组的指针

既然数组有自己的数据类型(上段已说明,它们不是指针!),那么,像其他的数据类型(例如整型,浮点型)一样,它们也有自己的指针--数组指针。作为指针本身,它们的值都是固定的32位地址值,而根据其所指向的不同数据类型,在自增,求差等算数运算中,它们表现出不同的行为。例如int a[5]的指针类型是int (*)[5],它的值是数组a的首元素地址,而a++使该地址偏移了sizeof(int) * 5 = 20,而int b[5][4]的指针类型是int (*)[5][4],它的值是数组b的首元素地址,而b++使该地址值偏移了sizeof(int) * 5 * 4 = 80。

请注意,由于都是指向首元素的地址,所以&a[0]和&a从指针的值上来说是一样的(但是它们的指针等级不同,故导致了偏移运算的行为不同),同理&b,&b[0][0]的指针值也是一样的。又因为上文说到,数组名可以隐式转换为将数组当作一维数组时的首元素指针,所以a必然与&a[0]相等,而b必然与&b[0][0]相等,将他们的数据类型做一个强制转换,可以证明这一点。

此外,二维数组可以看成一维数组的数组,所以b[0]的数据类型是int [4],是个4个元素的一维数组,又因为b[0]可以隐式转换为其首元素的地址,所以b[0]在数值上与b也是相等的!下面的代码证明了以上的说法:

#include <iostream>

using namespace std;
int main(int argc, char *argv[])
{
    int b[5][4];
    cout << (int(&b) == int(b) &&
        int(b) == int(&b[0][0]) && int(b) == int(b[0])) << endl;
    return 0;
}

3.多维数组作为函数参数

多维数组作为函数参数时,将会抹去第一维的信息,例如int a[5]作为参数时,它将退化为int a[],由于数组大小丢失,所以用int*作为形参也未尝不可,这也是“数组名即指针”这一谬误的源头。当int b[5][4]作为参数时,它将退化为int b[][4],或者int (*)[4],高维数组可以此类推。

4.指针数组与多维数组

上文讲的都是多维数组,他们虽然名叫多维,实际上在内存中它们的地址是连续的,即是以一维数组的形式存在的。而指针数组就不一样,虽然它与多维数组都可以进行形如“b[i][j]”的操作,但是指针数组的数据的内存分配没有任何规律,完全由用户控制,所以 对于int* c[10],它的数组名可以隐式的转换为&(*int)即**int类型使用。所以main函数的第二个参数argv的形参类型,可以写成char*[],也可以写成char**。

posted @ 2013-10-27 21:24  何磊  阅读(545)  评论(0编辑  收藏  举报