Hen*_*nry 9 c arrays variable-length
在支持可变长度数组之前,我会像这样动态分配它们:
int foo(size_t n)
{
int *arr = malloc(n * sizeof int);
if (!arr) return ENOMEM; /* not enough memory */
.
. else do stuff with arr[]
.
free(arr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用可变长度数组,我现在可以使它看起来更干净:
int bar(size_t n)
{
int arr[n];
.
. do stuff with arr[]
.
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但现在我没有"内存不足"检查.事实上,如果n太大,程序会崩溃.
如果n太大,我如何优雅地从bar(n)保释?
caf*_*caf 12
情况与任何其他局部变量完全没有变化 - 这样的声明:
int baz(void)
{
int arr[100000];
.
. do stuff with arr[]
.
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有完全相同的问题."解决方案"与以往一样 - 不要过于夸张,并且不要分配具有自动存储持续时间的非常大的数据结构(继续malloc()用于这些情况)."非常大"的价值在很大程度上取决于您的环境.
换句话说,不要声明,int array[n];除非你知道它n被限制在一个合理的值,这样你就可以很乐意将这个最大大小的数组声明为普通的,非可变修改类型的数组.
(是的,这意味着可变修改类型的数组不像它们第一次出现那样有用,因为你只需要以最大所需大小声明数组就可以获得很少的数据).
您可以通过不使用它们来防止它们崩溃.:)
严肃地说,几乎没有安全的方法来使用可变长度数组来使你的生活更轻松,除非你有大小的强大界限.另一方面,您可以通过以下方式有条件地使用它们:
char vla_buf[n < 1000 ? n : 1];
char *buf = sizeof vla_buf < n ? malloc(n) : vla_buf;
if (!buf) goto error;
/* ... Do stuff with buf ... */
if (buf != vla_buf) free(buf);
Run Code Online (Sandbox Code Playgroud)
虽然这看起来像无用的痛苦,但它可以产生巨大的性能差异,尤其是在许多调用malloc并free可能导致锁争用的线程应用程序中.(这一招的一个显着的附带好处是,你可以通过简单地替换支持旧的编译器不沃拉斯[n < 1000 ? n : 1]与1000用宏,如.)
另一个晦涩难懂的情况是,VGA可能是有用的,在递归算法中你知道所有递归级别所需的数组条目总数是有界的n,哪里n足够小你就相信它不会溢出堆栈,但是那里有可以达到n递归级别和最多使用n元素的单个级别.在C99之前,处理这种情况而不占用n^2堆栈空间的唯一方法是使用malloc.使用VLA,您可以完全在堆栈上解决问题.
请记住,这些VLA非常有用的情况非常罕见.通常情况下,VLA只是一种欺骗自己的方式,内存管理很容易,直到你得到你创建的(易受攻击的)漏洞.:-)
编辑:为了更好地解决OP的原始问题:
#define MAX_VLA 10000
int bar(size_t n)
{
int arr[n <= MAX_VLA ? n : 1];
if (sizeof arr/sizeof *arr < n) return ENOMEM;
/* ... */
return 0;
}
Run Code Online (Sandbox Code Playgroud)