在C语言中,数组是用于存储一个类型的有序元素集合的基本结构。它们提供了按索引的快速访问,并且与指针的使用密切相关。数组可以静态声明、自动声明(在栈上)或动态声明(在堆中)。分配类型影响数组的生命周期、从不同代码部分访问的可用性以及内存管理要求。
问题的历史
最初的C语言只允许定义静态和自动数组,但随着动态内存分配(函数malloc、calloc、free)的出现,出现了新的设计模式,提高了代码的灵活性。
问题
开发人员常常在数组的大小、生命周期和清理上犯错,导致内存泄漏、竞争条件和内存损坏。
解决方案
根据任务仔细选择存储类型,仔细跟踪初始化和及时释放动态数组的内存。
示例代码:
#include <stdio.h> #include <stdlib.h> int main() { // 自动(在栈上) int auto_arr[5] = {1,2,3,4,5}; // 静态(在程序运行时存在) static int static_arr[5]; // 动态(在堆上) int *dyn_arr = malloc(5 * sizeof(int)); for (int i = 0; i < 5; i++) dyn_arr[i] = i * 2; // 使用 for (int i = 0; i < 5; i++) printf("%d ", dyn_arr[i]); printf(" "); free(dyn_arr); return 0; }
关键特点:
可以通过sizeof知道动态数组的大小吗?
不可以,sizeof(ptr)对于动态数组将返回指针的大小,而不是数组的大小。需要手动存储大小或使用单独的变量。
int* arr = malloc(10 * sizeof(int)); printf("%zu ", sizeof(arr)); // 指针的大小,而不是数组的大小
数组越界会发生什么?
在C语言中,没有自动检查数组边界:超出边界的访问会导致未定义行为。错误通常在运行时被发现,或者根本不会被发现。
可以从函数返回局部(自动)数组吗?
不可以!在函数内部声明的数组在函数结束后将被删除。返回这样的数组会导致访问已释放的内存。
int* create_wrong_array() { int arr[10]; return arr; // 错误:返回指向栈的指针 }
开发人员在栈上创建数组,并从函数返回指针。程序有时崩溃或返回垃圾数据。
优点:
缺点:
使用动态分配,传递维度和指针,并通过free清理内存。所有内存释放都经过单元测试验证。
优点:
缺点: