C语言:(5.初级数组)
一、什么是数组?
- 数组是一组相同类型元素构成的集合。
Type Name[Size];
| 组成部分 | 含义 | 示例 |
|---|---|---|
| Type | 每个元素的类型 | int, char, double |
| Name | 数组的名字 | arr, brr |
| Size | 元素个数 | 10, 20 |
- 数组的每一个成员:
Name[0]到Name[Size-1]
计算机中所有序号从0开始!
int arr[5]; printf("%d\n", sizeof(arr)); // 20(5个int × 4字节)二、数组的分类
| 分类 | 语法 | 说明 | 内存大小(假设int 4字节) |
|---|---|---|---|
| 一维数组 | int arr[10] | 10个int | 40字节 |
| 二维数组 | int arr[3][4] | 3个int[4] | 48字节 |
| 三维数组 | int arr[2][3][4] | 2个int[3][4] | 96字节 |
- 一维数组内存布局(起始地址1000):
| 成员 | 字节范围 | 地址 |
|---|---|---|
| arr[0] | 1-4 | 1000-1003 |
| arr[1] | 5-8 | 1004-1007 |
| arr[2] | 9-12 | 1008-1011 |
| arr[3] | 13-16 | 1012-1015 |
| arr[4] | 17-20 | 1016-1019 |
三、数组的三种初始化
1.初始化一:直接定义并初始化
int arr[5] = {1, 2, 3, 4, 5}; int arr2[] = {1, 2, 3, 4, 5}; // Size可以省略 int arr3[10] = {1, 2, 3}; // 后面7个自动补0 int arr4[10] = {}; // 全部为02.初始化二:先定义后赋值
int brr[5]; brr[0] = 1; brr[1] = 2; brr[2] = 3; brr[3] = 4; brr[4] = 5;// 循环赋值 int crr[5]; for (int i = 0; i < 5; i++) { crr[i] = i + 1; }注意:这种初始化方式Size不可以省略!
3.初始化三:从键盘获取
int drr[5]; printf("请输入5个整数:"); for (int i = 0; i < 5; i++) { scanf("%d", &drr[i]); }注意:Size也不可以省略!
四、二维数组
- 二维数组是“由一组相同的数组类型构成的集合”。
内存布局(行优先存储):
arr[0][0] arr[0][1] arr[0][2] arr[0][3] arr[1][0] arr[1][1] ... 1 2 3 4 5 6 ...
- 二维数组的三种初始化:
// 初始化一 int arr[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; // 初始化二 int brr[3][4]; int temp = 1; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { brr[i][j] = temp++; } } // 初始化三 int crr[3][4]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { scanf("%d", &crr[i][j]); } }五、三维数组
- 三维数组是“由一组相同的二维数组类型构成的集合”。
int arr[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} } };- 三维数组遍历:
for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 4; k++) { printf("%d ", arr[i][j][k]); } printf("\n"); } printf("\n"); }六、数组长度公式
// 一维数组长度 int len1 = sizeof(arr) / sizeof(arr[0]); // 二维数组行数和列数 int rows = sizeof(brr) / sizeof(brr[0]); int cols = sizeof(brr[0]) / sizeof(brr[0][0]); // 三维数组各维度长度 int d1 = sizeof(arr) / sizeof(arr[0]); int d2 = sizeof(arr[0]) / sizeof(arr[0][0]); int d3 = sizeof(arr[0][0]) / sizeof(arr[0][0][0]);七、数组名(面试必考)
int arr[10] = {0}; printf("%d\n", sizeof(arr)); // 40 - 整个数组的大小 printf("%p\n", &arr); // 整个数组的地址 printf("%p\n", arr); // 首元素的地址 printf("%p\n", arr + 1); // 首元素地址 + 4 printf("%p\n", &arr + 1); // 整个数组地址 + 40- 数组名的三种身份:
| 情况 | 含义 | 类型 |
|---|---|---|
sizeof(数组名) | 整个数组的大小 | Type [Size] |
&数组名 | 整个数组的地址 | Type(*) [Size] |
| 其他情况 | 首元素的地址 | Type* |
int main() { int arr[10] = {0}; printf("%p %p\n", arr, arr + 1); // 差4字节(int*) printf("%p %p\n", &arr, &arr + 1); // 差40字节(整个数组) printf("%d %d\n", sizeof(arr), sizeof(&arr)); // 40 和 4 return 0; }八、常用数组操作
1. 求和
int sum = 0; for (int i = 0; i < len; i++) { sum += arr[i]; }2. 最大值(擂台法)
int max = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] > max) { max = arr[i]; } }3. 最小值
int min = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] < min) { min = arr[i]; } }4. 平均值
double avg = (double)sum / len;5. 冒泡排序
void BubbleSort(int arr[], int len) { for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } }九、面试考点与避坑指南
考点1:数组名与指针的区别
int arr[10]; int *p = arr; sizeof(arr); // 40 sizeof(p); // 4(指针大小)考点2:二维数组的指针类型
int arr[3][4]; // arr的类型是 int(*)[4](指向有4个int的数组的指针) // arr + 1 跳过了 4个int = 16字节考点3:数组作为函数参数会退化
void func(int arr[10]) { printf("%d\n", sizeof(arr)); // 4!不是40! } // 因为数组参数退化为指针:int arr[] 等价于 int *arr正确做法:同时传递长度
void func(int arr[], int len) { for (int i = 0; i < len; i++) { printf("%d ", arr[i]); } }考点4:常见错误
//数组不能整体赋值 int arr1[5] = {1, 2, 3, 4, 5}; int arr2[5]; arr2 = arr1; // 错误! //用循环或memcpy for (int i = 0; i < 5; i++) { arr2[i] = arr1[i]; }总结
| 知识点 | 要点 |
|---|---|
| 数组初始化 | 三种方式,Size可省略的情况 |
| 数组名 | sizeof和&时是整体,其他情况是首元素地址 |
| 二维数组 | 行优先存储,arr[i][j]=*(*(arr+i)+j) |
| 数组传参 | 会退化为指针,需要额外传长度 |
| 常见坑 | 数组不能整体赋值,不能返回局部数组 |
