一、多维数组的概念
多维数组可以看作是数组 的数组。即主数组的元素依然是一个数组。
二维数组的声明: float rain[5][12];这声明了一个有5个元素的数组rain,至于每个元素的情况,查看声明其余部分,可以看到每一个元素的类型是float[12],即每一个元素本身是一个内含12个float类型的数据。
二维数组的初始化:①.类似于一维数组 float rain[5][12] = {1,2,3,4,5,6};
②:float rain[5][12] = {
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3}
};
二维数组的赋值: 二维数组需要使用两个嵌套的for循环,一个循环处理数组的第一个下标,另一个循环处理数组的第二个下标。
二、指针和多维数组
2.1指针和数组的关系:
int zippo[4][2];
数组名 zippo的数组首元素的地址,所以 zippo = &zippo[0];
zippo[0]本身是一个内含两个整数的数组,所以zippo[0]= &zippo[0][0];
zippo = &zippo[0]= &&zippo[0][0];
*zippo = zippo[0]=&zippo[0][0];
**zippo = * (zippo[0])= zippo[0][0].
指针或地址加1,其值会增加对应类型大小的数值。zippo 和zippo[0]不同,zippo指向对象占用两个int大小,而zippo指向对象只占用一个int大小。zippo+1和zippo[0]+1的值不同。
2.2指向多维数组的指针
如何声明一个指针变量pz指向一个二维数组(如,zippo)?
int (*pz) [2]; // pz指向一个内含两个int类型值的数组 (每一个元素内含两个int 类型的数值)
pz = zippo;
虽然pz是一个指针,不是数组名,但是也可以使用pz[2][1]这样的写法。可以使用数组表示法或指针表示法来表示一个数组元素,既可以使用数组名,也可以使用指针名:
zippo[m][n]=pz[m][n]=*(*(pz+m)+n)
2.3指针的兼容性
在一维数组中,我们知道不能把指向int类型的指针赋值给指向double类型的指针,再多维数组中依然有这样的问题。
例如:int * pt, int ** pc int(*pa)[2] int (*pb)[3]; int ar_1[3][2] int ar_1[2][3]
以下赋值操作:
pt = &ar_1[0][0]; //均指向int类型
pt = ar_2[0]; //均指向int类型
pt = ar_1; // 错,pt指向int类型,ar_1指向一个内含3个int类型元素的数组。
pa = ar_1; //均指向一个内含2个int类型的数组;
pa = ar_2; // 错 pa指向一个内含2个int类型的数组,ar_2指向一个内含3个int类型的数组
pb = ar_2; //均指向一个内含3个int类型的数组;
pc = &pt; //均指向一个指针
*pc = ar_1[0]; //均指向一个int的指针
pc = ar_1; //错 ,pc指向指针,ar_1指向数组,类型不同。
注意:在一维数组const使用方法里讲到,可以把非const数据赋值给一个指向const的指针,这种方法仅限于一级解(只有指针变量,没有指向指针的变量)引用,如果有大于一级解引用,这时运行的结果是未定义的(乱码、垃圾值之类)。
2.4函数和多维数组
如果要编写处理二维数组的函数,首先要正确的理解指针才能写出声明函数的形参。在函数体中,通常使用数组表示法进行相关操作。
如果要写一个处理junk[3][4]的数组的函数
函数的声明:void somefunction ( int (* pt)[4])
void somefunction(int pt [][4] )--------------------------只有pt在描述函数形参时才能这样书写
void somefunction(int pt [][] )-------------错误,编译器会把数组表示法转化为指针表示法,如果不知道第二个下标参数,编译器就会只知道地址,不知道一个元素的大小,如果第二个方括号是空的,编译器就不知道怎样处理,所以第二个方括号数字必须存在。
常用的函数声明更是这样 void somefunction(int pt [][4],int rows ),这样就可以处理任一行数的列数相同的数组。
对于多维数组而言,只有最左边的方括号里的数字可以省略,并且如果后边有第二个参数,即便第一个方括号写上数字,也会被忽略。
三、变长数组
概念:变长数组中的“变”不是指可以修改已创建数组的大小,而是指在创建数组时,可以使用变量指定数组的维度,一旦创建了变长数组,数组大小保持不变。
原因:在学习使用函数处理二维数组时,要求数组第二个下标必须相同,否则就要重新编写函数,所以就有了变长数组的由来。
变长数组的声明: int sum2d(int rows,iint cols,int ar[rows][cols]); //顺序不能变
int sum2d(int ,int ,int ar[*][*]); //可以省略原型中的变量名,但是必须用星号代替省略的维度。
以变长数组作为形参的函数不仅可以处理传统C数组,也可以处理变长数组。
是否可以在声明数组时使用const常量?
C99/C11标准允许在声明变长数组时使用const常量,数组的定义必须是生命在块中的自动存储类别数组。(const常量释放内存是,数组也会被释放)
四、复合字面量
由来:对于一个接受int变量的函数,我们既可以传入一个int 变量,也可以直接传入一个整型常量,如4,5等。那么对于数组,我们要怎么传入一个类似于常量的数组呢?复合字面量就解决了这个问题。
对于数组,复合字面量类似于数组初始化列表,复合字面量会创建一个匿名数组(没有名字),因此复合字面量必须在创建时就要使用。
int diva[2]= {10,20}; (int[2]){10,20};-------复合字面量
典型用法:
total 1 = sum(pt1,2);
total 3 = sum( (int [6]) {4,5,6,7,8,9}, 6 );
其他用法:提前定义指针,在创建复合字面量时将指针指向该复合字面量,然后就可以通过指针访问这个匿名变量。
int *pt1;
pt1 = (int[2]){10,20}; *pt1 = 10; pt1[1]=20;
注意:复合字面量是提供临时需要值得一种手段,定义在最内层的花括号里。