2
#include <iostream>
#include <malloc.h>

void print_vals(int n)
{
    int *arr = (int *)alloca(n);

    for (int i = 0; i < n; i++)
        arr[i] = i;

    for (int i = 0; i < n; i++)
        std::cout << arr[i] << ' ';

    std::cout << '\n';
}

int main()
{
    print_vals(5);
    print_vals(10);
}

当我运行此代码时,每次调用都会出现此错误:

Run-Time Check Failure #4 - Stack area around _alloca memory reserved by this function is corrupted

在此处输入图像描述 我正在使用 Visual C++ 2019,stdc++14 和 stdc++17 都会产生相同的错误。

这段代码有什么问题?

4

2 回答 2

8

我将假设这只是示例代码,因为如果您的意图只是打印数字0..n,那么您绝对没有理由为此使用数组:-)


对于您的实际问题,该alloca函数,如malloc,分配了一些字节。如果你然后把它当作你有许多int值(几乎可以肯定大于一个字节),那不会很好。这实际上在对话框中得到确认,您会看到大小为 10 但每个数组元素占用 4 个:

Size: 10
Data: <> 00 00 00 00 01 00 00 00 02 00
         \_________/ \_________/ \____
            arr[0]      arr[1]      ar

您需要做的是:

int *arr = (int*) alloca(n * sizeof(*arr)); // n ints, not bytes.

无论如何,我会避免 alloca,因为:

  1. 这真的不标准;和
  2. 如果它不能分配空间,它就会有行为不端的恼人习惯,而不是像那样引发异常new

最后一点,Linux doco foralloca states(我的重点):

alloca() 函数返回一个指向已分配空间开头的指针。如果分配导致堆栈溢出,则程序行为未定义。

如果你想要一些你不必担心自己取消分配的东西,现代 C++ 有智能指针,所以你可以使用类似的东西:

std::unique_ptr<int[]> arr(new int[n]);

当该arr变量超出范围时,为其分配的内存将自动释放。您可以在原始代码的完整变体中尝试:

#include <iostream>
#include <memory>

void print_vals(size_t n) {
    std::unique_ptr<int[]> arr(new int[n]);

    for (size_t i = 0; i < n; i++)
        arr[i] = static_cast<int>(i);
    for (size_t i = 0; i < n; i++)
        std::cout << arr[i] << ' ';
    std::cout << '\n';
}

int main() {
    print_vals(5);
    print_vals(10);
}

顺便说一句,您会注意到我也更改为使用size_t而不是int大小和索引 - 我相信这更合适。现在,当然,这使用而不是堆栈,但根据之前关于alloca.

如果你保证对大小有一些限制,你可能会更有可能成功,例如alloca

void print_vals(size_t n) {
    if (n >= 100) {
        doSomethingIntelligent();
        return;
    }
    int *arr = (int *)alloca(n * sizeof(*arr));

    ...
}

但这实际上并不能保证它的安全性,如果你要这样做,你也可以使用固定缓冲区,因为你会知道最大大小:

void print_vals(size_t n) {
    int arr[100];
    if (n >= sizeof(arr) / sizeof(*arr)) {
        doSomethingIntelligent();
        return;
    }

    ...
}

我想提出另一种解决方案:如果您的意图是尽可能高效,您可以使用混合方法。我的意思是使用低于一定大小的本地缓冲区并仅在需要时分配内存:

void print_vals(size_t n) {
    // Default to using local buffer.

    int localBuff[100];
    int *arr = localBuff;

    // If more space needed, allocate  an auto-freeing smart pointer.

    std::unique_ptr<int[]> allocBuff;
    if (n >= sizeof(localBuff) / sizeof(*localBuff)) {
        allocBuff.reset(new int[n]);
        arr = allocBuff.get();
    }

    // Here, arr points to to a big-enough buffer.

    ...
于 2020-09-05T00:22:20.387 回答
1

函数的参数alloca()是要分配的字节,因此元素的大小必须乘以元素的数量。

可以这样做:

int *arr = (int *)alloca(sizeof(*arr) * n);
于 2020-09-05T00:23:02.227 回答