在C语言中,多维数组的元素存储顺序是按照最右边的下标率先变化的原则,称为行主序。例如:a[3][6]
元素的下标值分别为:0,0 0,1 0,2 0,3 0,4 0,5 1,0 1,1 1,2 1,3 1,4 1,5 2,0 2,1 2,2 2,3 2,4 2,5
数组名
一维数组名的值是一个指针常量,它的类型是“指向元素类型的指针”,它指向数组的第一个元素,多维数组也差不多,唯一的区别是多维数组第1维的元素实际上是另一个数组。
如:
int matrix[3][10]
可以看作是一个一维数组,包含3个元素,每隔元素恰好是包含10个整型元素的数组。
下标
下标引用实际上只是间接访问表达式的一种伪装形式,上例中
matrix:它的类型是指向包含10个整型元素的数组的指针,它的值是:
它指向包含10个整型元素的第1个子数组。
表达式:matrix+1,也是指向包含10个整型元素的数组的指针,它指向matrix的下一行:
表达式:*(matrix+1)标识了一个包含10个整型元素的子数组。数组名的值就是个常量指针,它指向数组的第1个元素,它的类型是指向整型的指针,即:
表达式:*(matrix+1)+ 5,前一个表达式是指向整型值的指针,所以5这个值根据整型的长度进行调整,整个表达式的结果是一个指针,它指向的位置比原先的位置向后移动了5个整型元素。即:
对其执行间接访问操作:*(*(matrix+1)+ 5),它所访问的就是图中哪个整个整型元素。
我们可以把表达式*(matrix+1)改写为matrix[1],matrix[1]选定一个子数组,所以它的类型是一个指向整型的指针。而对于上面的表达式*(*(matrix+1)+ 5)可以写成:*(matrix[1]+5),当然也可以直接写成matrix[1][5]。
指向数组的指针下面的定义:
int vector[10],*vp=vector;
int matrix[3][10],*mp=matrix;
第一个声明是合法的,它为一个整型数组分配内存,并把vp声明为一个指向整型的指针,并把它初始化为指向vector数组的第一个元素,vector和vp具有相同的类型:指向整型的指针。
第二个声明是违法的,它创建了matrix 数组,并把mp声明为一个指向整型的指针,但是mp的初始化是不正确的,因为matrix并不是一个指向整型的指针,而是一个指向整型数组的指针,应该声明为:
int (*p)[10]matrix;
下面的形式:
int(*p)[]=matrix;
若是想在指针上进行任何的指针操作,应该避免这种形式的声明,p仍然是一个指向整型数组的指针,但是数组的长度未知,当某个整数与这种类型的指针进行计算时,它的值将根据空数组的长度进行调整。有可能导致错误。
作为参数的多维数组作为函数参数的多维数组名的传递方式和一维数组名相同,实际传递的是指向数组第1个元素的指针,但是两种的区别在于,多维数组的每个元素本身是另外一个数组,编译器需要知道它的维数,以便为函数形参的下标表达式求值:
对于一维数组
int vector[10];
...
func1(vector);
参数vector的类型是指向整型的指针,所以func1的原型可以是:
void func1(int* vec);
void func1(int vec[]);
作用于vec上的指针运算把整型的长度作为调整长度。
对于矩阵:
int matrix[3][10];
...
func2(matrix);
这里,参数matrix的类型是指向包含10个整型元素的数组的指针,func2的原型定义形式:
void func2(int (*mat)[10]);
void func2(int mat[][]);
这里的关键在于编译器必须知道第2个及以后的各维的长度才能对下标求值,因此原型声明中必须给出这些维度,第一维的长度并不重要,因为计算下标时用不到它。把原型定义成:
void func2(int** mat);
是不正确的,因为mat在这里表示指向整型指针的指针,它和指向数组的指针并不是一回事。
初始化以二维数组为例:
初始化形式为;
数据类型 数组名[整常量表达式][ 整常量表达式]={ 初始化数据 };
在{ }中给出各数组元素的初值,各初值之间用逗号分开。把{ }中的初值依次赋给各数组元素。
分行进行初始化:
int a[2][3]={{1,2,3},{4,5,6}};
在{ }内部再用{ }把各行分开,第一对{ }中的初值1,2,3是0行的3个元素的初值。第二对{ }中的初值4,5,6是1行的3个元素的初值。
不分行的初始化:
int a[2][3]={ 1,2,,4,5,6};
把{ }中的数据依次赋给a数组各元素(按行赋值)。
为部分数组元素初始化:
int a[2][3]={{1,2},{4}};
第一行只有2个初值,按顺序分别赋给a[0][0]和a[0][1];第二行的初值4赋给a[1][0]。
省略第一维:
int a[ ][3]={ 1,2,3,4,5,6};
可以省略第一维的定义,但不能省略第二维的定义。系统根据初始化的数据个数和第2维的长度可以确定第一维的长度。
a数组的第一维的定义被省略,初始化数据共6个,第二维的长度为3,即每行3个数,所以a数组的第一维是2。
一般,省略第一维的定义时,第一维的大小按如下规则确定:
初值个数能被第二维整除,所得的商就是第一维的大小;若不能整除,则第一维的大小为商再加1。例如:
int a[ ][3]={ 1,2,3,4}
等价于:
int a[2][3]={ 1,2,3,4};
若分行初始化,也可以省略第一维的定义。下列的数组定义中有两对{ },已经表示a数组有两行。
int a[ ][3]={{1,2},{4}};