数组的引入
在前面的几章中我们学习了基本类型(int、char、float、double)以及指针的基类型和函数返回值类型的相关内容。利用基本类型来定义变量时,所定义的变量只能保存一个相对应类型的数据,而无法实现一次保存多个数据的功能,一次C语言提供了另一种类型来实现此功能,这就是构造类型。
构造类型是指由基本类型按照一定的规则组成的类型。它包括数组、结构体类型和共用体类型。
数组是一组具有相同类型的数据的集合,例如{1,2,3,4}。集合内的数据成为数组元素。
数组元素的存储:定义一个数组之后,系统首先为数组分配一片连续的内存空间(空间名为数组名,例如a),空间的大小等于数组元素的个数*存储单元长度,然后每个数组元素依次存入到相应大小的内存单元中。
数组元素名:共有的数组名和不同的下标构成的名字,例如a[0]、a[1]等。
数组的分类:根据数组元素下标的个数,数组可以分为一维数组(例如a[10])、二维数组(例如:b[2][3])和多维数组(c[2][3][4])。
数组的定义格式
1、一维数组的定义形式 类型名 数组名[常量表达式] 例如:int a[5];
注意:常量表达式的值又称为数组长度,该值必须是正的整型常量或者符号常量或者是常量表达式,一定不能包含变量(数组不支持动态分配内存)。
数组a[5]:长度为5,共分配5*4=20Byte的内存空间。数组元素名分别为a[0]、a[1]、a[2]、a[3]和a[4]。一定不会出现数组元素名a[5]。下标是从“0”开始到“数组长度-1”结束。
二维数组的定义形式 类型名 数组名[常量表达式1][常量表达式2]
例如:int a[2][3];是由2行3列共6个数组元素构成的数组。
数组a[m][n]可以看作是:二维数组是由m个一维数组构成的,每个一维数组内又包含n个数组元素。
二维数组元素的存储:按照先行后列的顺序依次存储各个元素。
数组的赋值
1、一维数组的赋值
第一种情况:定义的同时进行赋值
以集合的形式给数组赋值。例如:int a[4]={1,2,3,4};
赋值时,集合内的数组元素个数可以小于数组长度。例如:int a[4]={1,2};系统依次将1赋给a[0],2赋给a[1],a[2]、a[3]的值自动为零。不能跳过前面的元素给后面元素赋值。
[]内的常量表达式可以省略,此时数组的长度为数组元素的个数。如:int a[]={1,2,3};
第二种情况:先定义,后赋值。
定义时,常量表达式一定不能省略;赋值时,集合内的数组元素个数不能大于数组长度。例如:int a[5]; a[5]={1,2,3,4,5};或者a[5]={1};
2、二维数组的赋值
第一种情况:定义的同时进行赋值
以集合的形式赋值。如:int a[2][3]={{1,2,3},{4,5,6}};
集合中的一维数组的个数可以小于行数;数组元素的个数也可以小于列数。
可以省略内层{},赋值时仍然遵循先行后列的原则。
可以省略行数,但是一定不能省略列数。例如:int a[][3]={1,2,3,4,5};
第二种情况:先定义,后赋值。 例如:int a[2][3];a[2][3]={1,2,3,4,5};
数组元素的引用。其引用方式与变量的引用方式相同。注意:引用时不要越界。
一维数组与指针
1、数组元素的地址与数组元素的指针
一个变量在内存中有属于自己的内存空间和内存地址,可以利用一个指针来指向此变量。一个数组包含若干个数组元素,每一个数组元素也占有相应的内存空间,也具有内存地址,因此,也可以将一个指针指向数组内的任一个数组元素。
数组元素的指针就是数组元素的地址。
例如:int b,a[5]={1,2,3,4,5};
int *p;
p=&a[0];//指针指向数组的第一个元素
b=*p;//等价于b=a[0];
b=*(++p);//通过移动指针变量p来访问数组的其它元素。
C语言规定数组名代表数组中的第一个元素的地址。 即:a-&a[0]=0,a与&a[0]等价。
数组名a不代表整个数组,它只是一个地址常量,代表数组的首地址,始终指向数组的第一个元素,不能对a进行赋值运算,例如a++;a+=1等运算都是错误的。
p=&a[0]的等价式:p=a; 可以对指针变量p进行赋值运算。
2、通过指针引用数组元素
若指针变量p已指向数组中的某个数组元素,则p+1指向数组的下一个元素,而不是指向下一个字节。可以利用公式来求移动的字节数:p+i=p+i*d。
若p=a(或者p=&a[0]),则有:
(1)、p+i(或a+i)就是a[i]的地址。即:a+i等价于&a[i].
(2)、*(p+i)或*(a+i)就