int a[n];
Run Code Online (Sandbox Code Playgroud)
与
int * a;
a = malloc(n * sizeof(int));
Run Code Online (Sandbox Code Playgroud)
谁能分别解释一下这两种方法的优缺点?(效率、安全性等)
主要区别是 VLA 声明引入了新的可变修改(VM)类型,并且对象具有自动存储,变体malloc()具有动态存储。
代码:
int a[n];
Run Code Online (Sandbox Code Playgroud)
编译器将其视为:
int T_elems = n;
typedef int T[T_elems];
T a;
Run Code Online (Sandbox Code Playgroud)
由于结果数组a具有自动存储,并且在现代系统上分配在堆栈上。自动意味着当离开对象被引入的范围时,对象的内存被释放。
int *b;
{
int a[n];
// `a` is valid
b = a;
}
// resources pointed by `b` are released
Run Code Online (Sandbox Code Playgroud)
另一方面,第二个片段:
int * a = malloc(n * sizeof(int));
Run Code Online (Sandbox Code Playgroud)
创建一个指向它的指针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
Run Code Online (Sandbox Code Playgroud)
有一个常见的误解,认为 VLA 总是分配在堆栈上。VLA 可以通过指向数组的指针在堆上分配:
int (*a)[n] = malloc(sizeof(int[n]));
Run Code Online (Sandbox Code Playgroud)
优点:
sizeof a返回n * sizeof int缺点:
sizeof评估 VLA 类型的操作数优点:
malloc()保留了地址空间。操作系统几乎不能保证内存被保留realloc()缺点:
free()避免泄漏相同的数据组织为表格:
| 自动VLA | malloc |
|
|---|---|---|
| 句法 | 简单的 | 更详细 |
| 错误时的行为 | 堆栈溢出 | NULL |
| 错误处理 | 不可能:失败时的行为未定义 | 必须检查 的malloc返回值 |
| 最大尺寸 | 堆栈大小 | 堆大小(大于堆栈) |
| 速度 | 非常快(比固定数组稍慢) | 比任何基于堆栈的分配都慢 |
| 解除分配 | 自动的; 无泄漏风险 | 内存必须用 free() 释放以避免泄漏 |
| 数组大小支持 | 是的,由sizeof |
不,程序员必须显式存储 |
| 可以退货吗? | 不 | 是的 |
可以放进去struct吗? |
不 | 是的 |
| 可移植性 | C99,自C11起成为可选功能 | 受所有 C 标准支持 |
| 支持调整大小吗? | 不 | 是的,由realloc |
| 多维 | 语法简单 | 可能令人困惑的语法 |