C 语言实现动态数组(使用 malloc()
进行动态存储)
在 C 语言中,数组的大小通常是 固定的,必须在编译时确定。但有时,我们需要 在运行时动态分配数组,以适应不同的数据量需求。
malloc()
允许我们在 堆(heap) 上分配内存,以创建 动态数组,相比静态数组更灵活。
1. 使用 malloc()
分配动态数组
1.1 malloc()
介绍
malloc()
(Memory Allocation)用于动态分配内存:
void* malloc(size_t size);
- 参数
size_t size
:要分配的字节数。 - 返回值:
- 成功:返回 指向分配内存的指针(
void*
)。 - 失败:返回
NULL
(内存不足)。
- 成功:返回 指向分配内存的指针(
📌 示例:创建动态整型数组
#include <stdio.h>
#include <stdlib.h> // 包含 malloc() 和 free()
int main() {
int n;
printf("请输入数组大小: ");
scanf("%d", &n);
// 使用 malloc() 分配 n 个 int 大小的内存
int *arr = (int*) malloc(n * sizeof(int));
if (arr == NULL) { // 检查 malloc() 是否成功
printf("内存分配失败!\n");
return 1;
}
// 输入数组元素
printf("请输入 %d 个整数:\n", n);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// 输出数组元素
printf("数组元素: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 释放内存
free(arr);
return 0;
}
📌 运行示例
请输入数组大小: 5
请输入 5 个整数:
1 2 3 4 5
数组元素: 1 2 3 4 5
2. 使用 realloc()
动态调整数组大小
2.1 realloc()
介绍
如果动态数组 需要扩展或缩小,可以使用 realloc()
重新分配内存:
void* realloc(void* ptr, size_t new_size);
ptr
:指向当前已分配的内存块(可以是malloc()
分配的)。new_size
:新分配的字节数。- 返回值:
- 成功:返回新内存地址。
- 失败:返回
NULL
(原内存不变)。
2.2 realloc()
动态扩展数组
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, new_size;
printf("请输入数组初始大小: ");
scanf("%d", &n);
// 分配初始内存
int *arr = (int*) malloc(n * sizeof(int));
if (arr == NULL) {
printf("内存分配失败!\n");
return 1;
}
// 输入初始元素
printf("请输入 %d 个整数:\n", n);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// 扩展数组
printf("请输入新的数组大小: ");
scanf("%d", &new_size);
arr = (int*) realloc(arr, new_size * sizeof(int));
if (arr == NULL) {
printf("内存重新分配失败!\n");
return 1;
}
// 输入新增元素
if (new_size > n) {
printf("请输入新增的 %d 个整数:\n", new_size - n);
for (int i = n; i < new_size; i++) {
scanf("%d", &arr[i]);
}
}
// 输出扩展后的数组
printf("扩展后的数组元素: ");
for (int i = 0; i < new_size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 释放内存
free(arr);
return 0;
}
📌 运行示例
请输入数组初始大小: 3
请输入 3 个整数:
1 2 3
请输入新的数组大小: 5
请输入新增的 2 个整数:
4 5
扩展后的数组元素: 1 2 3 4 5
3. 使用 calloc()
分配初始化的动态数组
3.1 calloc()
介绍
calloc()
(Clear Allocation)用于分配并初始化内存:
void* calloc(size_t num, size_t size);
num
:分配的元素个数。size
:每个元素的大小。- 特点:
- 与
malloc()
不同,calloc()
会初始化所有内存为 0。
- 与
3.2 calloc()
示例
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("请输入数组大小: ");
scanf("%d", &n);
// 使用 calloc() 分配 n 个 int 大小的内存,并初始化为 0
int *arr = (int*) calloc(n, sizeof(int));
if (arr == NULL) { // 检查是否分配成功
printf("内存分配失败!\n");
return 1;
}
// 输出初始化的数组
printf("calloc() 初始化的数组元素: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]); // 输出全是 0
}
printf("\n");
// 释放内存
free(arr);
return 0;
}
📌 运行示例
请输入数组大小: 5
calloc() 初始化的数组元素: 0 0 0 0 0
4. malloc()
vs calloc()
vs realloc()
函数 | 作用 | 是否初始化 | 使用场景 |
---|---|---|---|
malloc(size) | 分配 size 字节 | ❌ 不初始化 | 需要手动初始化 |
calloc(n, size) | 分配 n * size 字节 | ✅ 初始化为 0 | 适用于初始值为 0 的数组 |
realloc(ptr, size) | 重新分配 size 字节 | ❌ 旧数据保留 | 动态扩展或缩小内存 |
5. 动态数组的最佳实践
✅ 始终检查 malloc()
、calloc()
、realloc()
是否成功:
if (arr == NULL) {
printf("内存分配失败!\n");
return 1;
}
✅ 使用 free()
释放动态内存,避免 内存泄漏(Memory Leak):
free(arr);
✅ 避免“野指针”:
arr = NULL; // 释放后置空,防止访问已释放的内存
6. 总结
malloc()
:动态分配内存,但不初始化数据。calloc()
:分配并初始化内存为0
。realloc()
:调整已分配的内存大小。free()
:释放动态分配的内存,防止内存泄漏。
动态数组适用于 数据量变化的场景,如 动态列表、栈、队列、哈希表 等。掌握动态内存管理是 C 语言编程中的核心技能!🚀
C 语言动态数组进阶:动态二维数组、动态结构体数组及最佳实践
在前面的内容中,我们学习了 malloc()
、calloc()
、realloc()
的基本用法,并实现了一维动态数组。本节将深入探讨:
- 动态二维数组
- 动态结构体数组
- 动态数组的错误处理及优化
- 动态数组的高级应用
1. 动态二维数组
1.1 为什么需要动态二维数组?
在 C 语言中,静态二维数组的大小 必须在编译时确定:
int arr[3][4]; // 3 行 4 列的二维数组(静态)
但如果 行数或列数在运行时决定,就需要使用 动态分配的二维数组。
1.2 方法 1:指针数组动态分配二维数组
这是一种 “行指针数组” 方式,实现步骤:
- 创建一个指针数组(存储指向每行的指针)。
- 为每行分配动态内存(即列)。
- 释放内存时,先释放每一行,再释放指针数组。
📌 C 代码
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows, cols;
printf("请输入二维数组的行数和列数: ");
scanf("%d %d", &rows, &cols);
// 1. 创建指针数组(存储行指针)
int **arr = (int**) malloc(rows * sizeof(int*));
// 2. 为每一行分配内存
for (int i = 0; i < rows; i++) {
arr[i] = (int*) malloc(cols * sizeof(int));
}
// 3. 填充数据
printf("请输入 %d x %d 的整数矩阵:\n", rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
scanf("%d", &arr[i][j]);
}
}
// 4. 输出二维数组
printf("矩阵内容:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
// 5. 释放内存(先释放行,再释放指针数组)
for (int i = 0; i < rows; i++) {
free(arr[i]);
}
free(arr);
return 0;
}
📌 运行示例
请输入二维数组的行数和列数: 2 3
请输入 2 x 3 的整数矩阵:
1 2 3
4 5 6
矩阵内容:
1 2 3
4 5 6
1.3 方法 2:一次性分配整个二维数组
另一种方式是 一次性分配所有数据,然后构造行指针:
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3, cols = 4;
// 1. 分配一块连续的二维数组内存
int *data = (int*) malloc(rows * cols * sizeof(int));
// 2. 创建行指针数组
int **arr = (int**) malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
arr[i] = data + i * cols;
}
// 3. 填充数据
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
arr[i][j] = i * cols + j;
}
}
// 4. 输出数据
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
// 5. 释放内存(只需释放 data 和 arr)
free(data);
free(arr);
return 0;
}
📌 方法对比
方法 | 优点 | 缺点 |
---|---|---|
方法 1:指针数组 | 每行可以单独释放,适用于不规则矩阵 | 需要多次 malloc() 和 free() ,效率较低 |
方法 2:连续内存 | 只需两次 malloc() ,缓存友好,性能更优 | 不能单独释放某行 |
2. 动态结构体数组
2.1 为什么需要动态结构体数组?
如果我们要存储 一批学生信息(如姓名、成绩),并且数量在运行时确定,就必须使用 动态结构体数组。
2.2 结构体动态数组示例
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[50];
int age;
float score;
} Student;
int main() {
int n;
printf("请输入学生数量: ");
scanf("%d", &n);
// 动态分配结构体数组
Student *students = (Student*) malloc(n * sizeof(Student));
if (students == NULL) {
printf("内存分配失败!\n");
return 1;
}
// 输入学生信息
for (int i = 0; i < n; i++) {
printf("请输入第 %d 个学生的姓名、年龄、成绩: ", i + 1);
scanf("%s %d %f", students[i].name, &students[i].age, &students[i].score);
}
// 输出学生信息
printf("\n学生信息:\n");
for (int i = 0; i < n; i++) {
printf("姓名: %s, 年龄: %d, 成绩: %.2f\n", students[i].name, students[i].age, students[i].score);
}
// 释放内存
free(students);
return 0;
}
📌 运行示例
请输入学生数量: 2
请输入第 1 个学生的姓名、年龄、成绩: Alice 20 85.5
请输入第 2 个学生的姓名、年龄、成绩: Bob 22 90.0
学生信息:
姓名: Alice, 年龄: 20, 成绩: 85.50
姓名: Bob, 年龄: 22, 成绩: 90.00
3. 动态数组的优化与错误处理
3.1 避免内存泄漏
如果没有 free()
动态分配的内存,会导致 内存泄漏:
int *arr = (int*) malloc(100 * sizeof(int));
arr = (int*) malloc(200 * sizeof(int)); // 旧内存未释放,导致泄漏!
free(arr); // 只释放了新分配的 200 个元素
✅ 正确做法
free(arr);
arr = NULL;
3.2 确保 malloc()
/realloc()
成功
int *arr = (int*) malloc(10 * sizeof(int));
if (arr == NULL) {
printf("内存分配失败!\n");
exit(1);
}
4. 总结
- 动态数组 适用于数据量不固定的场景,如 学生信息存储、矩阵运算。
malloc()
/calloc()
用于动态分配内存,realloc()
用于扩展数组。- 二维数组 可以使用 指针数组 或 连续内存 方法实现。
- 动态结构体数组 适用于存储复杂数据,如 学生、订单、员工信息。
- 始终释放
malloc()
分配的内存,避免 内存泄漏。
掌握动态数组是编写 高效、灵活的 C 语言程序 的关键!