当内存不足时,如何防止可变长度数组崩溃?

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被限制在一个合理的值,这样你就可以很乐意将这个最大大小的数组声明为普通的,非可变修改类型的数组.

(是的,这意味着可变修改类型的数组不像它们第一次出现那样有用,因为你只需要以最大所需大小声明数组就可以获得很少的数据).


R..*_*R.. 6

您可以通过不使用它们来防止它们崩溃.:)

严肃地说,几乎没有安全的方法来使用可变长度数组来使你的生活更轻松,除非你有大小的强大界限.另一方面,您可以通过以下方式有条件地使用它们:

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)

虽然这看起来像无用的痛苦,但它可以产生巨大的性能差异,尤其是在许多调用mallocfree可能导致锁争用的线程应用程序中.(这一招的一个显着的附带好处是,你可以通过简单地替换支持旧的编译器不沃拉斯[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)