从函数返回可变长度数组

Returning a variable length array from a function

下面的函数 "increment" 将表示为数组的数字加 1。

int*  increment(int array[], int size, int *sizeLen)
{
    int temp[size+1];

    int carry = 0;
    carry = (array[size-1]+1)/10;
    temp[size] = (array[size-1]+1)%10;

    for(int i=size-2;i>=0;i--)
    {
        temp[i+1] = (array[i] + carry)%10;
        carry = (array[i]+carry)/10;
    }
    if(carry)
    {
        temp[0] = 1;
        *sizeLen = size+1;
        return temp;
    }
    else
    {
        *sizeLen = size;
        return (temp+1);
    }
}

int main()
{
    int array[] = {9,9,9};
    int length;
    int *res = increment(array, sizeof(array)/sizeof(int), &length);
    for(int i=0;i<length;i++)
    {
        cout << res[i] << " ";
    }
}

我知道 gcc 支持 variable length arrays 并且它们存储在堆栈中。 一旦此函数结束,我希望 temp 超出范围,并且尝试在 main 中打印数组应该打印垃圾值。 但在我的例子中,实际值被打印出来了。 函数中声明的可变长度数组何时超出范围?

这是未定义的行为。下次程序入栈时,数据会丢失。

专业程序不要依赖这个。

你是对的。 temp 确实超出范围,它应该打印垃圾值。

但有时它会打印出正确的值。因为当当前函数结束时,本地堆栈内存不是cleared/overrided。

这里的关键确实是数组的存储时长。它具有自动存储期限。具有自动存储持续时间的变量的生命周期在它们所在的范围退出时结束。

它完全符合您的预期。但是 C 中没有任何东西可以阻止您获取本地对象的地址并将其从函数中返回。

使用该指针是未定义的行为。它可能看起来有效,但该数组仍然适用于所有意图和目的 "dead"。这样的指针通俗地称为 "dangling pointers".


嗯,以上内容适用于 C。由于这是关于 GCC 扩展的,因此大多数情况下也是如此,但可能需要有所保留。

这行不通。您正在返回一个指向本地数组的指针,该数组将在函数 returns.

后立即被删除(更有可能 over-written/re-used)

C++ 的方法就是使用 std::vector<>。例如(假设你原来的sizesizelen分别指的是array和返回的元素个数)

std::vector<int> increment(std::vector<int> const&array)
{
    std::vector<int> temp(array.size());
    auto a = array.rbegin();
    auto b = temp.rbegin();
    auto carry = (*a+1)/10;
    *b = (*a+1)%10;
    for(++a,++b; a!=array.rend(); ++a,++b)
    {
        *b = (*a+carry)%10;
        carry = (*a+carry)/10;
    }
    if(carry) { // we must add another element into temp at the start
                // that cannot be done with vector, hence we must create
                // another vector. Note that this should rarely happen.
       std::vector<int> result(temp.size()+1);
       auto r = result.begin();
       *r = 1;
       std::copy(temp.begin(),temp.end(),++r);
       return result;
    } else
       return temp;
}

请注意,如果您以相反的方式定义数字顺序,即最低有效数字作为第一个元素(索引 0),您的代码会简单得多。此外,由于您的数字似乎是十进制的,因此您可以使用比 int 更小的类型。在这种情况下,代码看起来像

std::vector<std::uint8_t> increment(std::vector<std::uint8_t> const&input)
{
    std::vector<std::uint8_t> result;
    result.reserve(input.size()+1);
    auto a = input.begin();
    auto carry = (*a+1)/10;
    result.push_back((*a+1)%10);
    for(++a; a!=input.end(); ++a)
    {
        result.push_back((*a+carry)%10);
        carry = (*a+carry)/10;
    }
    if(carry)
        result.push_back(1);
    return result;
}