目录
一,一维数组
数组是一组相同元素的集合
1,数组的创建
typedef arr_name[const_n] ;
typedef : 表示数组元素的类型 ,普通变量可以使用的类型,数组都可以使用
arr_name : 表示数组名(自定义)
const_n : 是一个常量表达式,用来指定数组的大小
如: int arr[10]
数组元素的类型是int ,数组名是 arr ,数组大小是10,可以存放十个元素
注:创建数组时 [ ] 里要给一个常量表达式才可以,虽然有的标准中可以使用变长数组(VLA),有的编译器还是会报错误的。
2,数组的初始化
1,完全初始化
初始化时,每个元素都赋上值,如:
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 } ;
2, 不完全初始化
初始化时,只对个别元素,或者前面几个元素初始化
int arr2[10] = { 1,2,3,4,5 } ;
3,指定初始化器初始化(新特性)
提示:数组下标从0开始,下标引用时[4]表示数组第五个元素,[1]表示数组第二个元素 。
//指定初始化数组的某一个元素
int a[10] = { [5] = 6} ;
//把 arr[5] 初始话为 6
//对days数组使用初始化器初始化
int days[12] = { 31 , 28 ,[4] = 31 ,30,31,[1]=29} ;
//输出结果 31,29,0,0,31,30,31,0,0,0,0,0
由此可以看到,前面已经被初始化的元素可以被后面使用初始化器修改,[4] 被初始化后直接从继续开始输出话,这就说明了指定初始化器的两个重要特性。
3.1 特性
1 ,如果指定初始化器后面有更多的值,如该代码片段中[4] =31,30 ,31 。那么后面 的值将会初始化指定元素后面的值。也就是说 days[5]被初始化为30,days[6]被初 始化为31。
2,如果再次初始化指定的元素,那么最后初始化的值将会取代之前的初始化,如:
[1]在前面被初始化为28,但是后面使用初始化器初始化为29,那么days[1]的值就 改取代成 29。
注: 1. 使用不完全初始化,没有被初始化的元素会被初始化为0。
2.初始化时,初始化列表里面的项数多余数组可存放元素个数,编译器会直接报错。
3.初始化时,数组的大小没有给定,那么后面初始化的元素个数就是该数组的大小
如: int a[] = { 1,2,3,4,5,6,7 }; 这个数组大小是 7
4.使用指定初始化器初始化时,数组的大小没有指定,编译器会把数组的大小设置为足够装 得下初始化的值。
二,一维数组的使用
通过下标引用操作符( []) ,访问数组的每个元素;应注意数组的下标是从0开始的到n-1。
也可以通过引用下标对选中元素进行赋值。
1,指定数组的大小
前面说了数组的大小都是由常量表达式来声明的,接下来介绍一下给定大小。
[]里的值必须大于0,且为整数。
int n = 5;
float a1[5]; //可以
float a2[5*2+1]; //可以
//sizeof()表达式被视为整型常量
float a3[sizeof(int)+1]; //可以
float a4[(int)2.5]; //可以,2.5被强制类型转换为整型2
float a5[-4]; //不可以 数组大小必须大于0
float a6[0]; //不可以 数组大小必须大于0
float a7[2.5]; //不可以 数组大小必须为整数
float a8[m]; //VLA c99之前不允许
2,数组的边界
在使用数组时,要防止数组的下标超出边界,必须要保证下标是有效的值,如:
int arr[20] ;
定义一个可以存放20个整型元素的数组,那么它的下标就是 0-19的范围。超出这个范围比如说是使用 -1,或者20 当做下标,就会造成越界访问,使程序异常终止。
3,给数组元素赋值
声明数组后,可以借助数组下标给数组元素赋值,如:
int arr[10];//定义一个十个元素的数组
int i =0 ;
//利用循环给数组赋值
for(i=0 ;i<10 ;i++)
{
arr[i] = i ;
}
这种赋值方式是依次进行的,也可以单独赋值:
arr[5] = 6 ;
赋值和使用时都要注意的一点就是,下标从0 开始,最大不要超过n-1。
二,二维数组
用图来简单描述一维数组和二维数组的区别。
所以二维数组是建立在一维数组的基础上的。
1,二维数组的创建
int arr[行][列] ;
int arr[3][4] ;//一个三行四列的二维数组
2,二维数组的初始化
//创建一个3行4列的二维数组
int arr[3][4] = {1,2,3,4} ;
int arr1[3][4] = {
{1,2},
{4,5}
} ;
//这样也是一种方式 ,没初始化的部分被初始化为0
int arr2[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
//二维数组中的行是可以省略的,列不可以
初始化时时一行一行开始的,第一行的值被初始化为1,2,3,4 ; 没有初始化的部分,与一维数组一样会被初始维0。
当二维数组中的行省略时,会根据一列有多少来判断有多少行。
如上述代码断 arr2[][4] ,会根据一行四个来初始化,也就是会初始化三行。
3,二维数组的使用
我们知道一维数组的使用可以引用下标操作,下标是从0开始的,那同样在使用二维数组时,我们也可以使用下标,注意 行和列的下标都是从0开始的 。
我们可以通过下标引用来初始化二维数组:
int i =0 ,j =0 ;
int arr[3][4] ;
for(i =0 ; i <3 ;i++)
{
for(j=0 ; j<4 ;j++)
{
arr[i][j] = i ;
}
}
三,变长数组
前面说过,不管是一位数组还是二维数组,数组的大小都需要是一个确定的大于0的整数值,即便是已经被赋值的变量都不可以,但是C99标准新增了变长数组(VLA)允许使用变量表示数组大小。
int n =5;
int arr[n] ;//表示一个存放五个int类型元素的数组
不过我们要注意,变长数组的 ‘变’不是指可以修改已创建的数组的大小,而是在创建数组时,可以用一个变量指定数组的大小 。
在使用变长数组时要注意编译器支不支持c99标准,否则会报错。
四,复合字面量
字面量是除符号常量外的常量,代表数组内容;
int arr[5] = { 1,2,3,4,5} ;//这是一个普通的整型数组
int [5] {1,2,3,4,5} ;//这是一个复合字面量
//也可以说是匿名数组,去掉声明中的数组名, int [5]是复合字面量的类型
同数组初始化相同,复合字面量在初始化时也可以省略大小,编译器会根据实际初始化值的个数进行判断,如:
(int []){1,2,3,4,5} ; //内含五个字符的复合字面量
复合字面量的类型名代表首元素的地址,也可以使用指针记录复合字面量的地址:
int *p ;
p = (int [2]){10,20} ;
使用复合字面量时应注意:
1:复合字面量是匿名的,所以不能先创建再使用,必须在创建的同时使用它。
2:复合字面量只是临时的一种手段,具有块作用域,离开了定义复合字面量的块,不一定能保 证还会存在。
总结与补充
1:数组是可以通过下标来访问的,下标是从0开始的。
2:数组的大小可以通过计算得到 。
int arr[10];
int sz = sizeof(arr) / sizeof(arr[0]) ;
3: 通常来说数组名是数组首元素的地址,但是有两个例外:
(1) sizeof(数组名) :这里的数组名表示的是整个数组,计算的是整个数组的大小,单位字 节。
(2) &数组名 : 取出的是整个数组的地址。
4:不管是一维数组还是二维数组在内存中都是连续存放的
(1)一维数组:在内存中连续存放,每增加一位,增加一个类型大小(比如 int 类型就是 增加4)。
随着数组下标的增长,地址也是由低到高变化的。
(2)二维数组 :在内存中也是连续存放的,行之间连续,跨行之间也是连续的。
(第一行的最后一个元素的地址与第二行首元素的地址是连续的)。