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

C 当内存不足时,如何防止可变长度数组崩溃?,c,arrays,variable-length,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; } int baz(void) { int arr[100000];

在支持可变长度数组之前,我会这样动态分配它们:

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;
}
int baz(void)
{
    int arr[100000];
    .
    . do stuff with arr[]
    .
    return 0;
}
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);
使用可变长度阵列,我现在可以让它看起来更干净:

int bar(size_t n)
{
    int arr[n];
    .
    . do stuff with arr[]
    .
    return 0;
}
但是现在我没有“内存不足”检查。事实上,如果n太大,程序就会崩溃


如果n太大,我怎么能优雅地从bar(n)中退出呢?

任何其他局部变量的情况都是完全不变的-声明如下:

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;
}
int baz(void)
{
    int arr[100000];
    .
    . do stuff with arr[]
    .
    return 0;
}
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);
有完全相同的问题。“解决方案”与以往一样-不要递归太深,也不要分配具有自动存储持续时间的非常大的数据结构(对于这些情况,继续使用
malloc()
)。“非常大”的值在很大程度上取决于您的环境

换句话说,不要声明
int数组[n]
除非您知道
n
被限定为一个合理的值,这样您就可以很高兴地将一个最大大小的数组声明为一个普通的、不可变修改的类型数组


(是的,这意味着可变修改类型数组没有它们最初出现时那么有用,因为仅将数组声明为所需的最大大小几乎没有什么好处)。

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

说真的,除非对大小有严格的限制,否则几乎没有安全的方法可以使用可变长度数组来简化您的生活。另一方面,您可以有条件地使用它们,方式如下:

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;
}
int baz(void)
{
    int arr[100000];
    .
    . do stuff with arr[]
    .
    return 0;
}
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);

在现实中,到处检查内存不足的情况是非常昂贵的。处理海量数据的企业方法是通过在单个早期检查点定义大小的硬上限来限制数据大小,并在达到上限时快速而优雅地失败


我刚才的建议既简单又愚蠢。但这是每一个普通(非科学或特殊)产品总是做的。这是客户通常期望的

您的边界(当然取决于系统)可能不是“内存”,而是“堆栈大小”。现在这个问题对我来说更有意义了,因为我想到了你在一个相当现代的消费盒子上的“之前”实现,并想知道“他在做什么,他需要一个GB的很大一部分?”。无论如何如果堆栈限制了您,那么“旧”方法可能会更好。这正是为什么VLA没有得到那么多使用的原因(另一个原因是编译器中的支持较差)。C99 VLA根本不稳定。在第一个示例中,您可以在任何地方使用
[1000]
,因为您已经确定该值不会(不应该)崩溃。递归算法似乎是真正的用例。你给了我一些好主意,但我认为最简单的方法是用
if(注意,你的示例中有bug:-)启动函数,应该是
if((sizeof arr)/(sizeof int)
,等等@caf:我基本同意。在第一种情况下,以牺牲一些额外的设置逻辑为代价,可以节省堆栈空间(并可能提高缓存一致性)。也许不值得,但谁知道呢。这确实是正确的,谢谢。我可以决定一个最大大小,并以
if(n)开始函数