C 语言实现动态数组(malloc() 动态存储)

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. 动态二维数组
  2. 动态结构体数组
  3. 动态数组的错误处理及优化
  4. 动态数组的高级应用

1. 动态二维数组

1.1 为什么需要动态二维数组?

在 C 语言中,静态二维数组的大小 必须在编译时确定

int arr[3][4];  // 3 行 4 列的二维数组(静态)

但如果 行数或列数在运行时决定,就需要使用 动态分配的二维数组


1.2 方法 1:指针数组动态分配二维数组

这是一种 “行指针数组” 方式,实现步骤:

  1. 创建一个指针数组(存储指向每行的指针)。
  2. 为每行分配动态内存(即列)。
  3. 释放内存时,先释放每一行,再释放指针数组

📌 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 语言程序 的关键!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小宝哥Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值