问题
The following function "increment" add 1 to a number represented as an array.
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] << " ";
}
}
I know gcc supports variable length arrays and they are stored on stack. I expect temp to go out of scope once this function ends and the attempt to print the array in main should print garbage values. But in my case the actual values are printed. When does the variable length array declared in the function goes out of scope?
回答1:
The key here is indeed the storage duration of the array. It has automatic storage duration. The lifetime of variables with automatic storage duration ends the moment the scope they're are in is exited.
It does exactly as you expect. But nothing in C stops you from taking the address of a local object and returning it from the function.
Using that pointer is undefined behavior. It may appear to work, but the array is still for all intents and purposes "dead". Such pointers are known colloquially as "dangling pointers".
Well, the above is true for C. Since this is about the GCC extension, the same applies mostly, but may need to be taken with a grain of salt.
回答2:
This won't work. You are returning a pointer to a local array, which will be deleted (more likely over-written/re-used) as soon as the function returns.
The C++ way to do things like that is to use std::vector<>
. For example (assuming that in your original size
and sizelen
referred to the number of elements in array
and the returned, respectively)
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;
}
Note that your code would be much simpler if you had defined the order of digits the other way around, i.e. the least significant digit as the first element (index 0). Moreover, as your digits seem to be decimal, you could use a smaller type than int
. In this case, the code would look like
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;
}
回答3:
This is undefined behavior. The next time a program pushes to the stack, the data will be lost.
Don't rely on this for professional programs.
回答4:
You are right. temp
does go out of scope, and it should print garbage values.
But sometimes it prints correct values. Because the local stack memory is not cleared/overrided immediately when current function ends.
来源:https://stackoverflow.com/questions/41823420/returning-a-variable-length-array-from-a-function