跳转到内容

C 语言动态数组

来自代码酷


动态数组是C语言中通过内存动态分配实现的、可在运行时调整大小的数组结构。与静态数组不同,其内存空间从堆(heap)而非栈(stack)分配,需手动管理内存生命周期。

核心概念[编辑 | 编辑源代码]

静态数组的局限性[编辑 | 编辑源代码]

静态数组在编译时确定大小,无法应对以下场景:

int static_arr[5]; // 大小固定为5
  • 数据量未知时可能浪费内存或溢出
  • 无法在运行时扩展/收缩

动态数组原理[编辑 | 编辑源代码]

通过指针和内存管理函数实现:

  • malloc():分配内存块
  • calloc():分配并清零内存
  • realloc():调整已分配内存大小
  • free():释放内存

graph LR A[声明指针] --> B[malloc/calloc分配内存] B --> C[使用数组] C --> D{需要调整大小?} D -->|Yes| E[realloc] D -->|No| F[继续使用] E --> C C --> G[free释放内存]

基础实现[编辑 | 编辑源代码]

创建动态数组[编辑 | 编辑源代码]

#include <stdio.h>
#include <stdlib.h>

int main() {
    int size = 5;
    int *dyn_arr = (int*)malloc(size * sizeof(int));
    
    if (dyn_arr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    
    // 初始化数组
    for (int i = 0; i < size; i++) {
        dyn_arr[i] = i * 10;
    }
    
    // 使用示例
    printf("动态数组元素:");
    for (int i = 0; i < size; i++) {
        printf("%d ", dyn_arr[i]);
    }
    
    free(dyn_arr); // 必须释放
    return 0;
}

输出:

动态数组元素:0 10 20 30 40

调整数组大小[编辑 | 编辑源代码]

使用realloc时需注意:

  • 原指针可能被无效化
  • 新内存区域可能迁移到不同地址
int new_size = 10;
int *temp = (int*)realloc(dyn_arr, new_size * sizeof(int));
if (temp == NULL) {
    printf("内存重分配失败\n");
    free(dyn_arr); // 释放原始内存
    return 1;
}
dyn_arr = temp; // 更新指针

高级应用[编辑 | 编辑源代码]

二维动态数组[编辑 | 编辑源代码]

通过指针数组实现:

int rows = 3, cols = 4;
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);

动态字符串数组[编辑 | 编辑源代码]

结合字符串特性处理:

char **str_array = (char**)malloc(5 * sizeof(char*));
for (int i = 0; i < 5; i++) {
    str_array[i] = (char*)malloc(20 * sizeof(char));
    sprintf(str_array[i], "String%d", i+1);
}

内存管理最佳实践[编辑 | 编辑源代码]

1. NULL检查:每次分配后验证指针 2. 初始化内存calloc或手动初始化 3. 释放后置空:避免悬垂指针

   free(ptr);
   ptr = NULL;

4. 匹配释放:每种分配方式对应正确释放

性能考量[编辑 | 编辑源代码]

  • O(n)时间复杂度:realloc可能触发内存拷贝
  • 内存碎片风险:频繁调整大小可能导致碎片
  • 预分配策略:根据场景预估初始大小

实际案例[编辑 | 编辑源代码]

动态数据收集器[编辑 | 编辑源代码]

处理未知数量的用户输入:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int capacity = 2;
    int count = 0;
    int *numbers = (int*)malloc(capacity * sizeof(int));
    
    printf("输入整数序列(以-1结束):\n");
    while (1) {
        int input;
        scanf("%d", &input);
        
        if (input == -1) break;
        
        if (count >= capacity) {
            capacity *= 2;
            numbers = (int*)realloc(numbers, capacity * sizeof(int));
            printf("数组扩容至%d\n", capacity);
        }
        
        numbers[count++] = input;
    }
    
    printf("最终数组:");
    for (int i = 0; i < count; i++) {
        printf("%d ", numbers[i]);
    }
    
    free(numbers);
    return 0;
}

示例交互:

输入整数序列(以-1结束):
10 20 30 40 50 -1
数组扩容至4
数组扩容至8
最终数组:10 20 30 40 50

常见错误[编辑 | 编辑源代码]

错误类型 示例 后果
内存泄漏 忘记free 程序内存持续增长
悬垂指针 释放后继续使用指针 未定义行为
缓冲区溢出 越界访问 数据损坏/安全漏洞
双重释放 对同一指针多次free 程序崩溃

扩展阅读[编辑 | 编辑源代码]

  • 数据结构:动态数组是向量(Vector)的基础实现
  • 对比:C++中的std::vector提供自动内存管理
  • 进阶:内存池技术优化频繁分配场景