💾 Dynamic Memory Allocation动态内存分配

Master malloc, free, and heap memory management掌握 malloc、free 和堆内存管理

What is Dynamic Memory Allocation?什么是动态内存分配?

Dynamic memory allocation lets a program request and free memory at runtime, rather than fixing sizes at compile time. This provides flexibility when the required size is not known in advance. 动态内存分配允许程序在运行时申请和释放内存,而不是在编译时就确定内存大小。它在我们事先无法确定所需内存时提供了更大的灵活性。

Memory Layout Overview:内存布局示意图:
+------------------+
|      栈区        |  函数调用、局部变量
+------------------+
|      堆区        |  动态分配的内存 (malloc)
+------------------+
|      静态区      |  全局变量、静态变量
+------------------+
|      代码区      |  程序代码
+------------------+
                
#include // 包含malloc和free的头文件 // 动态分配一个整数的内存 int *ptr = (int *)malloc(sizeof(int)); if (ptr == NULL) { printf("内存分配失败\n"); return 1; } *ptr = 42; // 使用分配的内存 free(ptr); // 释放内存

Core Memory Allocation Functions核心内存管理函数

1. malloc() - 分配内存

void *malloc(size_t size);

2. free() - 释放内存

void free(void *ptr);

3. calloc() - 分配并清零

void *calloc(size_t num, size_t size);

💡 malloc vs calloc

  • malloc(size): allocate bytes; uninitializedmalloc(size): 分配size字节,内容未初始化
  • calloc(num, size): allocate num×size; zeroedcalloc(num, size): 分配num×size字节,内容初始化为0
  • realloc(ptr, size): resize allocationrealloc(ptr, size): 重新分配内存大小

Dynamic Array Creation动态数组创建

The most common use of dynamic allocation is arrays whose size is known only at runtime:动态内存最常见的用途是创建运行时确定大小的数组:

int *create_array(int size) { // 分配size个整数的内存 int *array = (int *)malloc(size * sizeof(int)); if (array == NULL) { printf("内存分配失败\n"); return NULL; } // 填充数组 for (int i = 0; i < size; i++) { printf("输入第%d个元素: ", i); scanf("%d", &array[i]); } return array; }

🎯 动态数组操作实例

Let’s write a function to print doubled values of an array:让我们实现一个函数来打印数组的双倍值:

void print_double(int *array, int size) { for (int i = 0; i < size; i++) { printf("%d ", array[i] * 2); } printf("\n"); } // 使用示例 int main() { int size; printf("输入数组大小: "); scanf("%d", &size); int *array = create_array(size); if (array != NULL) { printf("数组元素双倍值: "); print_double(array, size); free(array); // 记得释放内存 } return 0; }

Dynamic Struct Creation动态结构体创建

We can allocate structs dynamically, which is crucial for lists, trees, and other structures:我们可以动态创建结构体,这对于链表、树等数据结构非常重要:

struct movie_review *new_review(char *title, int year, int rating) { // 分配结构体内存 struct movie_review *review = (struct movie_review *)malloc(sizeof(struct movie_review)); if (review == NULL) { return NULL; } // 复制标题字符串 strcpy(review->title, title); review->release_year = year; review->rating = rating; return review; }

⚠️ 常见内存错误

  • Memory leak: allocated but never freed内存泄漏: 分配内存但忘记释放
  • Wild pointer: using pointer after free野指针: 释放内存后继续使用指针
  • Double free: calling free() twice双重释放: 对同一内存多次调用free
  • Out-of-bounds: access beyond allocation越界访问: 访问超出分配范围的内存

Memory Debugging Tools内存调试工具

On Linux, use dedicated tools to detect memory issues:在Linux系统中,我们可以使用专门的工具来检测内存问题:

// 编译时启用调试信息 gcc -g program.c -o program // 使用valgrind检测内存错误 valgrind --leak-check=full ./program // 输出示例: // ==12345== HEAP SUMMARY: // ==12345== in use at exit: 0 bytes in 0 blocks // ==12345== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated // ==12345== All heap blocks were freed -- no leaks are possible

💡 调试技巧

  • Always check if malloc returned NULL总是检查malloc的返回值是否为NULL
  • Set pointer to NULL after free在free后将指针设为NULL避免野指针
  • Use valgrind to check leaks使用valgrind定期检查内存泄漏
  • Pair every malloc with a free为每个malloc配对一个free

🎯 Practice & Consolidation练习与巩固

练习1: 动态数组反转

Write a function to create a dynamic array and reverse its elements:编写一个函数,创建动态数组并将其元素反转:

int *reverse_array(int *array, int size) { // 分配新数组 int *reversed = (int *)malloc(size * sizeof(int)); if (reversed == NULL) { return NULL; } // 在这里实现反转逻辑 // reversed[0] = array[size-1] // reversed[1] = array[size-2] // ... return reversed; }

Answer:答案:

int *reverse_array(int *array, int size) { int *reversed = (int *)malloc(size * sizeof(int)); if (reversed == NULL) { return NULL; } for (int i = 0; i < size; i++) { reversed[i] = array[size - 1 - i]; } return reversed; }

练习2: 动态字符串连接

Implement a function to concatenate two dynamic strings:实现一个函数,连接两个动态字符串:

char *concat_strings(char *str1, char *str2) { // 计算总长度 int len1 = strlen(str1); int len2 = strlen(str2); // 分配内存 (+1 for null terminator) char *result = (char *)malloc(len1 + len2 + 1); // 在这里实现字符串连接 return result; }

Answer:答案:

char *concat_strings(char *str1, char *str2) { int len1 = strlen(str1); int len2 = strlen(str2); char *result = (char *)malloc(len1 + len2 + 1); if (result == NULL) { return NULL; } strcpy(result, str1); strcat(result, str2); return result; }

Summary总结

Dynamic allocation is a core skill in advanced C. In this module, you learned:动态内存分配是C语言高级编程的核心技能,本周我们学习了:

🚀 下一步学习

After mastering dynamic allocation, we’ll study recursion and the underlying call mechanics.掌握了动态内存分配后,我们将学习递归编程,探索函数调用的底层机制。