数组必备
一、一维数组
1.1 一维数组的创建
数组是一组相同类型元素的集合。
数组的创建方式:
type_t arr-name[const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小
数组创建实例:
char arr1[3];
int arr2[10];
float arr3[5];
double arr4[20];
注:C99标准之前,数组创建,[ ]中只能给一个常量,不能使用变量。在C99标准中引入了变长数组的概念(不过部分编译器并不支持变长数组),数组的大小可以使用变量指定,但是变长数组不能初始化。
1.2 一维数组的初始化
数组的初始化是指,在创建数组的同时赋给数组一些合理的初始值。
数组初始化实例:
int arr1[3] = {1,2,3}; //完全初始化
int arr2[10] = {6,6,6}; //不完全初始化,剩余元素默认为 0
int arr3[] = {1,2,3,4};
char arr4[] = {"perfect"};
//数组创建时未指定大小就初始化,数组元素个数根据初始化内容而定
注:[ ] 下标引用操作符,用于访问数组的操作符。数组使用下标来访问,数组下标从 0 开始。
计算数组的大小:
int arr[10] = {0};
int sz = sizeof(arr)/sizeof(arr[0]);
1.3 一维数组在内存中的存储
下面我们探究一下数组在内存中的存储:
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
由图可看出:一维数组在内存中时连续存放的。
此外还可发现:随着数组下标的增长,元素的地址也在增长。
二、二维数组
2.1 二维数组的创建
二维数组创建:
int arr[X][Y]; //X为行,Y为列 (X、Y不是变量)
int arr1[3][4];
char arr2[2][3];
double arr3[5][7];
//二维数组只创建不初始化时,行和列的大小都不能省略
//即 int arr[][4]; 是错误的
2.2 二维数组的初始化
二维数组的初始化:
int arr[3][4] = {1,2,3,4}; //未完全初始化的部分默认为 0
int arr[3][4] = {{1,2},{3,4}};
int arr[][4] = {{2,3},{4,5}};
//二维数组如果有初始化,行可以省略,列不能省略
二维数组的使用也是通过下标访问来实现的。
2.3 二维数组在内存中的存储
对于二维数组的使用,我们可以把数组按下面的形式来思考:
但实际上与探究一维数组同理,我们可以发现二维数组在内存中也是连续存储的。
三、数组名及作为函数参数
一段写出错误的代码引出下文:
//在32位机器上
void sort(int arr[])
{
int sz = sizeof(arr) / sizeof(arr[0]);
//这里的 sz 的值不是 5 了,而是 1
//而放在main函数中 sz 的值就是 5,why?
......
}
int main()
{
int arr[5] = {1,2,3,4,5};
sort(arr);
......
return 0;
}
这就牵扯到了数组名的含义和数组作为参数的意义。
3.1 数组名的含义
数组名是首元素地址。
除了下面两种情况:
sizeof(数组名) 和 &数组名 中的数组名 代表整个数组。
1、sizeof(数组名),计算整个数组的大小。
2、&数组名,取出的是整个数组的地址。
3.2 数组作为函数参数
数组作为函数参数有两种写法:
数组传参,形参形式写成数组或指针都行
//假设参数为int类型
function(int arr[])
//虽然参数可以写成数组形式,但本质上数组参数传递的是数组首元素
//第二种写法反映本质 应用指针接收
function(int* arr)
所以上面的代码 sort函数中的sizeof(arr)计算的是一个指针的大小,sizeof(arr[0]) 计算的是数组首元素大小,故sz为1(32位机器上);而main函数中的sizeof(arr)计算的是整个数组的大小。
3.3 数组的类型
数组也是有类型的:去掉数组名的剩余部分就是数组类型。
//如:
int arr[10];
数组名为arr,类型为int [10]
四、数组越界访问
数组的下标是有范围限制的。
数组的下标是从 0 开始,如果数组有 n 个元素,最后一个元素的下标就是n-1,所以数组下标如果小于 0,或大于 n-1,就是数组越界访问了。
C语言本身不做数组下标的越界检查,编译器也不一定报错,但其实这是一个隐含的错误,一个不小心就会爆掉你的程序。