Return stack data to C; Is it freed properly?

I was looking at a friend's code and was interested in how C / C ++ allocated memory on the stack and controlled its release. If I needed to create an array of 10 objects in a function, but return this array, it will be freed up when the function pops up (which makes the data invalid) or is placed in a heap (which raises the question of how we release it?).

Sample code as follows:

Gene* GetTopTen() { // Create 10 genes (or 10 objects, doesn't matter) Gene Ten[10]; // Sort out external pool data Sort(); // Copy over data to the array of 10 objects for(int i = 0; i < 10; Ten[i++] = pool[i]); // Here is the core of my question: return Ten; } 

Any help is much appreciated, it turns into a very interesting question from my friends, and I can’t answer.

+4
source share
8 answers

This is an array allocated by the stack, so the returned pointer is invalid.

+22
source

As soon as the function returns, the data will not be destroyed, but will most likely be overwritten by the next function call. You may be lucky and it may still be there, but this behavior is undefined. You should not rely on this.

Here's what could happen: during a function, the stack looks like this:

 "--------------------------- | caller function data | ---------------------------- | Ten[9] | | Ten[8] | | ... | | Ten[0] | ---------------------------" 

Immediately after the function exits, it will probably look the same. But if the caller calls another function like this,

 void some_func() { Gene g; ... } 

the stack will now look:

 "--------------------------- | caller function data | ---------------------------- | g | ---------------------------- | Ten[8] | | ... | | Ten[0] | ---------------------------" 

Some data may be overwritten unnoticed (in this case, Ten[9] ), and your code will not know this. You must allocate the data on the heap with malloc() and explicitly free it with free() .

+9
source

This leads to undefined behavior . The array contains ten arrays. As soon as the GetTopGene function ends, this stack will be destroyed, so you should not use pointers to this part of memory.

What you want to do is allocate space on the heap.

 Gene* GetTopTen(){ Gene* genes = (Gene*) malloc (10*sizeof(Gene)); //do stuff. return genes; } 

You must remember that you free this memory when you are done with it.

  Gene* genes = GetTopTen(); //do stuff with it. free(genes); 
+3
source

This is the cause of the most disgusting mistakes! Sometimes it will work, sometimes it will not.

This is a mistake, not a "smart piece of code."

+2
source

Another way to do this correctly without allocating heap memory is to change the function prototype to take a pointer to an array to write the result:

void GetTopTen (Gene Ten []) {...}

then simply delete the declaration of ten in the function body, since now it is a parameter.

Now the caller needs to declare its own ten-element array and pass it as a parameter:

... Gene top [10]; GetTopTen (top); ...

Just be careful that the caller declares a sufficiently large array! Unfortunately, C does not have a good way for a function to specify the size of the array to be passed, so the compiler will not warn you if the caller declares an array too small; it will just overwrite the stack at runtime.

+2
source

If you want to return an array from a function, you have to put it in a heap yourself:

In C

 Gene* GetTopTen() { // Create 10 genes (or 10 objects, doesn't matter) Gene *Ten = malloc(sizeof(Gene)*10); .... // Now it ok to return return Ten; } int main() { Gene *genes = GetTopTen(); free (genes); } 

And in C ++:

 Gene* GetTopTen() { // Create 10 genes (or 10 objects, doesn't matter) Gene *Ten = new Gene[10]; .... // Now it ok to return return Ten; } int main() { Gene *genes = GetTopTen(); delete [] genes; } 

Of course, you also need to keep track of how long this array is, either by returning the length from GetTopTen to a pointer / reference parameter, or some kind of constant.

+1
source

Your function says it returns a pointer, so when you call a function on the stack, only space is allocated for the pointer for the return value. Therefore, your return value is a pointer pointing to a place on the stack that will be invalid when you exit your function.

Wrap the return value in a struct .

 typedef struct { int Array[10]; } ArrayOfTen; ArrayOfTen SomeFunction () { ArrayOfTen array = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; return array; } int main (int argc, char *argv[]) { ArrayOfTen array = SomeFunction (); int i; for (i = 0; i < 0; i++) fprintf (stdout, "%d\n", array.Array[i]); return 0; } 
0
source

This is not a mistake, it is just a low level language. You (almost) cannot stack an array and return it to the same function - until you are one of the (deleted) people. But also you should not call malloc in every situation.

To make your program memory-friendly, allocate this array on the stack in the calling object and pass it as an argument.

The GetTopTen function will look:

 void GetTopTen(Gene* genes) { /* Do something Do not allocate new Gene array, you already have one - modify values at "genes" pointer */ } 

Name it:

 Gene genes[10]; GetTopTen(genes); /* Now, do whatever you want with top ten "genes", which are safe until return from this function */ 

This style, as I see today, is not used, and it’s very sad that I’m not joking, because it is that low-level languages ​​are different from them with garbage collection, and also much faster than calling malloc() all the time; these variables are automatically freed up and take up less memory. But keep in mind that it depends on the size of the structure and the number of elements - if it is really large, select it through malloc, otherwise you may get a stack overflow.

0
source

All Articles