C 数组
C 数组
在 C 语言中,数组(Array)是一种用于存储固定数量、相同类型数据的集合。数组提供了一种连续的内存结构,让我们能以索引方式访问和操作元素。
数组的定义和初始化
定义数组
1 2 3
int arr[5]; // 定义一个整型数组,包含5个元素,初值不确定 float prices[10]; // 包含10个 float 类型元素 char name[20]; // 字符数组(可用于存储字符串)
数组下标从 0 开始,即
arr[0]
是第一个元素,arr[4]
是最后一个元素(共5个)。初始化数组
1 2 3 4
int a[5] = {1, 2, 3, 4, 5}; // 完全初始化 int b[5] = {1, 2}; // 部分初始化,其余自动填 0 int c[] = {10, 20, 30}; // 自动推导长度为 3 char s[] = "hello"; // 自动加上 '\0',长度为 6
数组的访问
通过索引访问(从 0 到 n-1):
1
2
a[0] = 10;
printf("%d\n", a[2]);
越界访问(如
a[5]
)会导致未定义行为。
数组的元素修改
1
2
3
4
5
6
int myNumbers[] = {25, 50, 75, 100};
myNumbers[0] = 33;
printf("%d", myNumbers[0]);
// 现在输出 33 而不是 25
数组和指针的关系
在大多数表达式中,数组名会退化为指向第一个元素的指针:
1
2
3
int a[5] = {1,2,3,4,5};
int *p = a; // 等同于 int *p = &a[0];
printf("%d\n", *(p + 2)); // 输出 3
数组作为函数参数
1
2
3
4
void printArr(int arr[], int len) {
for (int i = 0; i < len; i++)
printf("%d ", arr[i]);
}
在函数中,
arr[]
实际上传递的是指针,不包含长度信息,需手动传入长度参数。
多维数组
定义多维数组
1 2 3 4
int mat[2][3] = { {1, 2, 3}, {4, 5, 6} };
访问多维数组
1
printf("%d\n", mat[1][2]); // 输出 6
字符数组
- 字符串本质上是以
'\0'
结尾的字符数组(char[]
)。 - 字符串数组通常指包含多个字符串(即多个字符数组)的二维数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
char str1[6] = "hello"; // 包括结尾的 '\0',共6个字节
char str2[] = "hello"; // 自动推断长度为6个字节
char str3[10] = "hello"; // 包括字符"hello" + "\0" + 4个空位
char str4[] = {'h','e','l','l','o','\0'}; // 手动初始化
// 字符串指针数组
const char * colors[] = {
"red", "green", "blue"
}
// 每一个元素都是char[]
// 优势:总内存更节省,可以指向不同长度的字符串
// 字符串的内容不能修改
// 二维数组
char fruits[3][10] = {
"apple", // 实际为 {'a','p','p','l','e','\0', ...}
"banana",
"cherry"
};
// fruits[i] 是第 i 个字符串
// 每行最多能存放 9 个可见字符 + \0(共 10 字节)
- 字符数组的访问方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char fruits[3][10] = {
"apple",
"banana",
"cherry"
};
printf("%s\n", fruits[1]); // 输出 "banana"
printf("%c\n", fruits[0][2]); // 输出 'p'
printf("%s\n", colors[2]); // 输出 "blue"
// 字符串指针数组
const char *pets[] = {"dog", "cat", "bird"};
printf("%s\n", pets[2]); // 输出 "bird"
char c = pets[0][1]; // 'o'
二维数组和指针数组的对比
特性 | char arr[N][M] | char *arr[] |
---|---|---|
内存结构 | 一块连续内存(固定大小) | 每项是指针,指向常量字符串 |
占用空间 | 更大 | 更小(更节省) |
可否修改内容 | ✅ 可以(写进数组) | ❌ 常量字符串,不可以修改内容 |
是否支持变长字符串 | ❌ 长度固定 | ✅ 每个字符串可不同长度 |
malloc申请空间
malloc()
可以实现 动态内存分配,用于在运行时按需创建数组(尤其是长度不确定时)。
用途:
- 数组长度在运行时才知道
- 数组需要跨函数使用
- 需要在堆上分配内存(避免栈溢出)
- 可与 realloc 搭配动态扩容
一维数组动态分配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
scanf("%d", &n);
int *arr = (int *)malloc(n * sizeof(int)); // 分配 n 个 int 的空间
if (arr == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
for (int i = 0; i < n; i++)
arr[i] = i * i;
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
free(arr); // 释放内存
return 0;
}
二维数组动态分配(常用两种方式)
- 方法 1:分配“指针数组 + 每行”
1
2
3
4
5
6
7
8
9
10
11
12
int **matrix = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
matrix[i] = (int *)malloc(cols * sizeof(int));
}
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
- 方法 2:一次性分配整个二维块(更高效)
1
2
3
4
5
6
7
8
9
10
int *data = (int *)malloc(rows * cols * sizeof(int));
int **matrix = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
matrix[i] = data + i * cols;
}
free(matrix);
free(data);
calloc() 和 realloc()
calloc()
:自动初始化为 0
1
int *a = (int *)calloc(n, sizeof(int));
realloc()
:动态扩容数组
1
2
int *a = (int *)malloc(5 * sizeof(int));
a = (int *)realloc(a, 10 * sizeof(int)); // 扩容为10个元素
计算数组的长度
1
2
int a[5] = {1,2,3,4,5};
int len = sizeof(a) / sizeof(a[0]); // 计算数组长度(元素个数)
注意事项
问题/陷阱 | 说明 |
---|---|
数组越界 | 会造成未定义行为,可能崩溃或错误数据 |
使用未初始化的数组元素 | 会导致不可预测的值 |
数组大小必须是常量(C89) | C89 中不支持变长数组(VLA) |
数组与指针混淆 | 虽然语法上接近,但数组和指针在内存上是不同的 |
本文由作者按照 CC BY 4.0 进行授权