注意区分定义与引用形式上的相似与含义上的区分,定义时是指数组的大小空间;引用时是指引用下标标识的元素。
数组越界:
在给数组元素赋值或对数组元素进行引用时,一定要注意下标的值不要超过数组的范围,否则会产生数组越界问题。
因为当数组下标越界时,编译器并不认为它是一个错误,但这往往会带来非常严重的后果。
例如:
定义了一个整型数组a:
inta[10];
数组a的合法下标为0~9。
如果程序要求给a[10]赋值,将可能导致程序出错,甚至系统崩溃。
常用下面的式子确定数组的大小,预防数组越界情况的发生。
假定对于一个整型数组a,它的大小为:
sizeof(a)/sizeof(a[0])
sizeof(a)表示求数组a在内存中所占字节数,使用上面这个式子,可以使数组大小计算在16位机器和32位机器之间移植。
例4-1、4-1
(2)、例4-2、4-3、4-4
二、二维数组
1.二维数组的定义:
二维数组也称为矩阵,需要两个下标才能标识某个元素的位置,通常称第一个下标为行下标,称第二个下标为列下标。
定义二维数组的语法格式为:
类型数组名[常量表达式1][常量表达式2];
定义二维数组的格式与定义一维数组的格式相同,只是必须指定两个常量表达式,第一个常量表达式标识数组的行数,第二个常量表达式标识数组的列数。
例如:
inta[2][3];
上面定义了一个a数组,它在逻辑上的空间形式为2行3列,每一个数组元素都是整型数据,因此a数组的各元素如下:
a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]
//每一维的下标都是从0开始
二维数组中每个元素都是用下列方式标识:
数组名[行下标][列下标]
二维数组在内存中的排列顺序是“先行后列”,即在内存中先存第一行的元素,然后再存第二行的元素。
从数组下标变化来看,先变第二个下标,第一个下标先不变化(即i[0][0],i[0][1],i[0][2]),待第二个下标变到最大值时,才改变第一个下标,第二个下标又从0开始变化。
对于二维数组,可以把它看成是由多个一维数组构成的。
例如上例:
inta[2][3];就可以看成是由两个形如inta[3];的一维数组构成的。
由于二维数组在内存中是线性排列的,引用一维数组和引用二维数组都是引用相应存储地址的内容,因此可以计算出一个二维数组元素在对应一维数组中的顺序号,从而将对二维数组元素的引用转变为对一维数组元素的引用,这个过程称为“降维处理”(经常在向函数传递数组时用到)。
假设有一个mxn的二维数组a,其中第i行第j列元素a[i][j]在数组中的位置公式为:
i*n+j+1
例如有一个3*4的矩阵a:
a[0][0]a[0][1]a[0][2]a[0][3]
a=a[1][0]a[1][1]a[1][2]a[1][3]
a[2][0]a[2][1]a[2][2]a[2][3]
a[2][1]元素在数组中的位置是2*4+1+1=10。
即它在数组中是第10个元素。
对一个a[i][j]元素,在它前面有i行(对a[2][1]来说它前面有两个整行),这i行共有i*n个元素。
在a[i][j]所在行中,a[i][j]前面还有j个元素,因此在数组a中a[i][j]前面共有(i*n+j)个元素。
那么a[i][j]就是第(i*n+j)+1个元素。
如果顺序号从0算起,那么a[i][j]在a数组中的顺序号计算公式为i*n+j。
a[2][1]的顺序号为2*4+1=9。
即按从0算起的话,它的顺序号为9,或者说它前面有9个元素。
2.二维数组初始化:
和一维数组一样,二维数组也能在定义时被初始化,只是要注意必须按照前面所讲的存储顺序列出数组元素的值。
常见有如下一些初始化方式:
(1)分别对各元素赋值,每一行的初始值用一对花括号括起来。
例如:
inta[2][3]={{1,2,3},{4,5,6}};
123
456
将第一对花括号内的三个初始值分别赋给a数组第一行三个元素,第二对花括号内的三个初始值赋给第二行元素。
数组中各元素为:
(2)将各初始值全部连续地写在一个花括号内,在程序编译时会按内存中排列的顺序将各初始值分别赋给数组元素。
例如
inta[2][3]={1,2,3,4,5,6};
数组中各元素为:
123
456
(3)只对数组的部分元素赋值。
例如:
inta[2][3]={1,2,3,4};
数组共有6个元素,但只对前面4个元素赋初值,后面两个未赋初值,其值为0。
数组中各元素为:
123
400
(4)可以在分行赋初值时,只对该行中一部分元素赋初值,例如:
inta[2][3]={{1,2},{1}};
对第一行中的第一、二列元素赋初值,而第三个元素未赋初值。
第二行中只有第一列元素赋初值。
数组中各元素为:
120
100
(5)二维数组定义的其它形式:
若在定义数组时给出了全部数组元素的初值,则数组的第一维下标可以省略,但第二维下标不能省略。
例如:
下面两种定义方式等价:
inta[2][3]={1,2,3,4,5,6};
inta[][3]={1,2,3,4,5,6};
编译器会根据元素的总个数分配空间,每行3列,共6个元素,故该数组行数为6/3=2行。
但上例不能写成:
inta[2][]={1,2,3,4,5,6};
在分行定义时,也可以只对部分元素赋初值而省略第一维的下标。
例如:
inta[][4]={{1,2},{},{3,4,5}}
该数组表示3行4列的整型数组,等价于下面的定义:
inta[3][4]={{1,2,0,0},{0,0,0,0},{3,4,5,0}}
P99练习例4-5,4-6
三、多维数组的定义
类型数组名[常量表达式1][常量表达式2]…[常量表达式n];
由于大于三维的数组基本上不常用,所以在此以三维数组为例介绍多维数组。
例如:
定义一个整型三维数组:
inta[2][3][4];
数组有24个元素,它们在内存中排列顺序跟二维数组类似:
先变化第三个下标,然后变化第二个下标,最后变化第一个下标。
对于三维数组,可以把它看成是由多个二维数组构成的。
依此类推,一个n维数组可以看成是由多个n-1维数组构成的。
多维数组初始化
以三维数组初始化为例:
inta[2][3][4]={{{1,2,3,4},{5,6,7,8},{9,10,11,12}},
{{13,14,15,16},{17,18,19,20},{21,22,23,24}}};
由于第一维的大小为2,可以认为a数组有两个二维数组组成,每个二维数组为3行4列。
因此初始化时,按每个二维数组按行给初值的方法,分别用花括号把各行元素值括起来,并且将三行的初值再用花括号括起来。
例如:
{{1,2,3,4},{5,6,7,8},{9,10,11,12}}是第一个二维数组的初值;
同样,{{13,14,15,16},{17,18,19,20},{21,22,23,24}}是第二个二维数组的初值。
当然也可以不必用这么多的花括号,而把三维数组中全部元素连续写在一个花括号内,按元素在内存中排列顺序依次赋初值。
例如:
staticinta[2][3][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24};
5.3.3省略第一维大小
多维数组也可以省写第一维的大小,以上面定义的三维数组a为例,定义也可改写为:
inta[][3][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24};
系统会根据初值个数,算出第一维的大小为:
24/(3*4)=2。
在分行定义时,也可以只对部分元素赋初值而省略第一维的下标。
例如:
inta[][3][2]={{{1,2},{3},{5}},{{0,7},{8},{10}}};
显然这是一个三维数组,大小为2*3*2。
等价于下面的定义:
inta[2][3][2]={{{1,2},{3,0},{5,0}},{{0,7}