数组
- 数组是相同数据类型变量的有序集合
- 数组作为整体需要一个合法的命名(数组名)
- 数组中的变量没有独立命名,只有在数组中的编号
- 数组中变量的个数是固定不变的(数组大小固定)
数组的内存布局
- 数组在计算机底层是一片连续的内存,用于存储数组元素
- 数组的大小字节数可以用 sizeof 获取(单位:字节)
计算数组的大小
- type Name[] = {V0, V1, V2, …, Vn,} // 共 n 个元素
- sizeof(Name) / sizeof(Name[0]); // 计算结果为 n
注意
- 数组名只能当作左值使用(可以看作是常量)
- 只能使用整形常量对数组大小进行定义
- 某些编译器可能支持,是因为编译器本身作了优化,c语言本身是不支持的
- 只能使用整形值作为下标访问数组元素
1 | int size = 8; |
数组的类型
1 | // 这是两个不同类型的数组 |
上述操作中,按理说是不符合类型的赋值规则的,因为不同类型之间进行输入传递是有可能出现问题的;
在上述赋值操作中,仅仅改变了 a 数组中的前五个变量,这与赋值操作的定义相违背(赋值操作指的是改变所保存的内容,这个改变是完全的改变);
因此从严格意义上来说是有问题的,但并没有影响程序的运行;
二维数组
- 二维数组能且仅能让编译器自动确定第一维的大小
- 第二维大小必须显示给定,即:数组元素的类型必须正确合法
- 第一维大小自动确定的方法:(初始值个数 除以 第二维大小)向上取整
1 | int a[][3] = {1, 2, 3, 4, 5}; |
当你声明一个二维数组时,如
int arr[M][N];
,这里:
M
是外层数组的大小,即这个二维数组包含多少个一维数组。N
是内层数组(即每个一维数组)的大小,也就是每个一维数组中有多少个元素。为什么需要指定第二维的大小?
- 内存分配:编译器需要知道如何为二维数组分配足够的连续内存空间。通过指定
N
,编译器可以计算出整个二维数组需要多少字节的内存(M * N * sizeof(int)
对于int
类型的二维数组)。如果N
没有被指定,编译器就无法确定每个内部数组的确切大小,进而无法计算整个二维数组所需的总内存量。- 索引计算:在 C 语言中,二维数组的索引是通过
arr[i][j]
这样的形式来访问的。当你知道N
的值时,编译器可以很容易地计算出j
索引对应的元素在内存中的偏移量(即j
乘以每个内部数组的大小,即N * sizeof(int)
)。如果N
没有被指定,这种索引计算就无法进行。- 类型检查:在编译时,指定
N
还允许编译器对数组索引进行类型检查,确保索引不会超出数组的边界。