int a[n];
对比
int * a;
a = malloc(n * sizeof(int));
谁能分别解释一下这两种方法的优缺点? (效率、安全等)
最佳答案
主要区别在于 VLA 声明引入了一种新的可变修改 (VM) 类型并且该对象具有自动存储,malloc()
变体具有动态存储。
代码:
int a[n];
被编译器视为:
int T_elems = n;
typedef int T[T_elems];
T a;
结果数组 a
具有自动存储,并且在现代系统上分配在堆栈上。自动意味着在离开范围时释放对象的内存,如果对象被引入。
int *b;
{
int a[n];
// `a` is valid
b = a;
}
// resources pointed by `b` are released
另一方面,第二个片段:
int * a = malloc(n * sizeof(int));
创建一个指向int
的指针并为其分配一个动态分配的对象。即使 a
的范围已经结束,对象资源仍然有效。内存在使用 free()
释放之前有效。
int *b;
{
int * a = malloc(n * sizeof(int));
b = a;
}
// resources pointed by `b` are valid!
free(b);
// memory is no longer valid
有一个常见的误解,认为 VLA 总是分配在堆栈上。 可以通过指向数组的指针在堆上分配 VLA:
int (*a)[n] = malloc(sizeof(int[n]));
总结:
- VLA(和 VM 类型)
优点:
- 自动 VLA 的简单分配
- “总是”成功(C 标准未定义失败时的行为)
- 分配非常快(比固定数组稍慢)
- 自动 VLA 没有泄漏风险
- 可以有动态存储(通过指向 VLA 的指针)
- 对于多维数组非常方便
- 携带其大小
sizeof a
返回n * sizeof int
缺点:
- 自动 VLA 很容易溢出堆栈
- 不能在文件范围内定义 VM 类型(不能返回)
- VM 类型不能用作结构成员
- 自 C11 起成为可选功能
- 计算 VLA 类型的
sizeof
的操作数 - 不能调整自动 VLA 的大小
- 动态一维数组。
优点:
- 受所有 C 标准支持
- 可以是任意大小,没有堆叠限制
- 指示分配是否成功,但是在现代操作系统
malloc()
上保留地址空间。操作系统很少保证内存 已保留 - 可以用
realloc()
调整大小
缺点:
- 更冗长的语法
- 必须检查是否成功
- 分配比任何基于堆栈的分配都慢
- 必须使用
free()
释放内存以避免泄漏 - 不携带大小,必须保持数组的大小
组织成表格的相同数据:
malloc
空
malloc
的返回值sizeof
struct
吗?realloc
关于c - 可变长度数组和动态内存分配有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67356818/