My question is about returning a value from a function call in c. I've read many questions and answers on this topic such as:
Returning a local variable confusion in C
I also understand that returning a pointer to a local variable is a problem since the local variable has no limited lifetime after the return. In my case below I am returning a pointer value not a pointer to a local variable. This should be ok yes? (i.e. returning &x would be bad)
int *foo(int a) {
int *x; //local scope local lifetime
...
x = &something_non-local;
...
return x; //return value of pointer
}
int main(void) {
int *bar;
bar = foo(10);
}
You can look at it this way. A variable represents a place in memory. Lifetime of a variable is defined by validity of this place in memory. The place in memory keeps a value. Any copy operation just copies values from one place in memory to another.
Every such memory place has an address. A pointer to a variable is just another variable which value is an address of another variable. A copy of a pointer is just a copy of an address from one place to another.
If a variable is declared in the global scope, than its memory will be valid till the exit of the program. If the variable is declared non-statically in a procedure, then its memory is valid till the end of this procedure. Technically it is probably allocated on stack which gets unallocated when the procedure returns, making this memory not valid.
In your case if pointer x points to a variable from a global scope, the variable itself is valid until the exit from the procedure. However, the return statement copies the value from the x into a different location just before the latter becomes invalid. As a result the value of x will end up in bar. This value is the address of a static variable which is still valid.
There would be a different story if you try to return the address of x, i.e. &x. This would be an address of memory which existed inside of the procedure. After return it will point to an invalid memory location.
So, if your something_non-local points to such a thing, than you are in trouble. It should point to something static or something in heap.
BTW, malloc allocates a memory in heap which is valid till you use free.
Related
I'm a beginner to the C programming language. I sort of understand the general definition of stack memory, heap memory, malloc, pointers, and memory addresses. But I'm a little overwhelmed on understanding when to use each technique in practice and the difference between them.
I've written three small programs to serve as examples. They all do the same thing, and I'd like a little commentary and explanation about what the difference between them is. I do realize that's a naive programming question, but I'm hoping to connect some basic dots here.
Program 1:
void B (int* worthRef) {
/* worthRef is a pointer to the
netWorth variable allocated
on the stack in A.
*/
*worthRef = *worthRef + 1;
}
void A() {
int netWorth = 20;
B(&netWorth);
printf("%d", netWorth); // Prints 21
}
int main() {
A();
}
Program 2:
int B (int worthRef) {
/* worthRef is now a local variable. If
I return it, will it get destroyed
once B finishes execution?
*/
worthRef = worthRef + 1;
return (worthRef);
}
void A() {
int netWorth = 20;
int result = B(netWorth);
printf("%d", result); // Also prints 21
}
int main() {
A();
}
Program 3:
void B (int* worthRef) {
/* worthRef is a pointer to the
netWorth variable allocated on
the heap.
*/
*worthRef = *worthRef + 1;
}
void A() {
int *netWorth = (int *) malloc(sizeof(int));
*netWorth = 20;
B(netWorth);
printf("%d", *netWorth); // Also prints 21
free(netWorth);
}
int main() {
A();
}
Please check my understanding:
Program 1 allocates memory on the stack for the variable netWorth, and uses a pointer to this stack memory address to directly modify the variable netWorth. This is an example of pass by reference. No copy of the netWorth variable is made.
Program 2 calls B(), which creates a locally stored copy of the value netWorth on its stack memory, increments this local copy, then returns it back to A() as result. This is an example of pass by value.
Does the local copy of worthRef get destroyed when it's returned?
Program 3 allocates memory on the heap for the variable netWorth, variable, and uses a pointer to this heap memory address to directly modify the variable netWorth. This is an example of pass by reference. No copy of the netWorth variable is made.
My main point of confusion is between Program 1 and Program 3. Both are passing pointers around; it's just that one is passing a pointer to a stack variable versus one passing a pointer to a heap variable, right? But in this situation, why do I even need the heap? I just want to have a single function to change a single value, directly, which I can do just fine without malloc.
The heap allows the programmer to choose the lifetime of the variable, right? In what circumstances would the programmer want to just keep a variable around (e.g. netWorth in this case)? Why not just make it a global variable in that case?
I sort of understand the general definition of stack memory, heap
memory, malloc, pointers, and memory addresses... I'd like a little
commentary and explanation about what the difference between them
is...
<= OK...
Program 1 allocates memory on the stack for the variable netWorth, and
uses a pointer to this stack memory address to directly modify the
variable netWorth. This is an example of pass by reference.
<= Absolutely correct!
Q: Program 2 ... Does the local copy of worthRef get destroyed when it's returned?
A: int netWorth exists only within the scope of A(), whicn included the invocation of B().
Program 1 and Program 3 ... one is passing a pointer to a stack variable versus one passing a pointer to a heap variable.
Q: But in this situation, why do I even need the heap?
A: You don't. It's perfectly OK (arguably preferable) to simply take addressof (&) int, as you did in Program 1.
Q: The heap allows the programmer to choose the lifetime of the variable, right?
A: Yes, that's one aspect of allocating memory dynamically. You are correct.
Q: Why not just make it a global variable in that case?
A: Yes, that's another alternative.
The answer to any question "Why choose one design alternative over another?" is usually "It depends".
For example, maybe you can't just declare everything "local variable" because you're environment happens to have a very small, limited stack. It happens :)
In general,
If you can declare a local variable instead of allocating heap, you generally should.
If you can avoid declaring a global variable, you generally should.
Checking your understanding:
Program 1 allocates memory on within the function stack frame of A() for the variable netWorth, and passes the address of netWorth as a pointer to this stack memory address to function B() allowing B() to directly modify the value for the variable netWorth stored at that memory address. This is an example of pass by reference passing the 'address of' a variable by value. (there is no pass by reference in C -- it's all pass by value) No copy of the netWorth variable is made.
Program 2 calls B(), which creates a locally stored copy of the value netWorth on its stack memory, increments this local copy, then returns the integer back to A() as result. (a function can always return its own type) This is an example of pass by value (because there is only pass by value in C).
(Does the local copy of worthRef get destroyed when it's returned? - answer yes, but since a function can always return its own type, it can return the int value to A() [which is handled by the calling convention for the platform])
Program 3 allocates memory on the heap for the variable netWorth, and uses a pointer to this heap memory address to directly modify the variable netWorth. While "stack/heap" are commonly used terms, C has no concept of stack or heap, the distiction is that variables are either declared with Automatic Storage Duration which is limited to the scope within which they are declared --or-- when you allocate with malloc/calloc/realloc, the block of memory has Allocated Storage Duration which is good for the life of the program or until the block of memory is freed. (there are also static and thread local storage durations not relevant here) See: C11 Standard - 6.2.4 Storage durations of objects This is an example of pass by reference. (It's all pass by Value!) No copy of the netWorth variable is made. A pointer to the address originally returned by malloc is used throughout to reference this memory location.
So I am working with a "standard" library with more than a decade of history for brain image I/O. I encountered this function:
nifti_image* nifti_image_read( const char *hname , int read_data ){
nifti_image* nim;
...
<<<some IO operations>>>
...
return nim;
}
My question is, how come this function is returning a local pointer to an automatic variable? Isn't this practice prohibited since the nim pointer goes out of scope and is supposed to be deleted after completion of the function?
I have already read this question but couldn't get my answer:
It's just returning the value of the nim pointer.
During the << some IO operations >> part I assume nim is set to point at some permanent memory in the heap or global.
This function is returning the value stored in the pointer and it is ok. The pointer value is the address of an object which is probably a allocated dynamically and is NOT deleted at the end, even if it was C++. The only possible issue is the case where the pointer points to another local variable, not allocated dynamically. So even though the pointer itself goes out of scope, the caller that receives the return value gets a copy of the address of a valid object.
You're not returning a pointer to a local variable. You're returning the value of a local variable which happens to be a pointer.
Assuming the pointer is not pointing to another local variable itself, this is a safe operation.
I'm currently learning the C language and I'm struggling to wrap my head around the pointers and malloc() function.
So in my book's example I have the following function defined :
island* create(char *name) {
island *i = malloc(sizeof(island));
i->name = strdup(name);
i->opens = "09:00";
i->closes = "17:00";
i->next = NULL;
return i;
}
Then it's called like this :
char name[80];
fgets(name, 80, stdin);
island *p_island0 = create(name);
There is several things I struggle to understand in this code example:
What happen to the i variable when assigned to malloc(sizeof(island));, does it just temporarily stores the reference of the new memory space allocated on the HEAP ?
After island *p_island0 = create(name); , eventually what is stored in p_island0 ? The address created by malloc() or was another pointer created and the value of the previous i variable copied into p_island0 on the ... STACK?
When you do return i; the pointer value stored in i is copied to the variable p_island0 in the calling function, and then i goes out of scope. The allocated memory never goes out of scope, it has a life-time of the full program or until you call free with the pointer value. Which variable is storing the pointer value doesn't matter, as long as it is the original pointer value returned by the malloc call.
How the value is returned by the function is not specified by the C specification, it depends on the compiler, operating system and underlying hardware. Most likely the stack is not involved, but the returned value is stored in a CPU register.
1. What happen to the i variable when assigned to malloc(sizeof(island));, does it just temporarily stores the reference of the new memory space allocated on the HEAP ?
i stores the pointer returned by malloc(). Later, that is returned as the return value of the function. Dynamic memory has a lifetime equal to the program runtime (unless manually deallocated by free()), so the values stored into the memory area pointed by the pointer are valid and accessible after the function returns.
FWIW, point to note here, before using the return value of the malloc(), it's always good to check the returned value against NULL to avoid UB in case malloc() fails.
2. After island *p_island0 = create(name); , eventually what is stored in p_island0 ? The address created by malloc() or was another pointer created and the value of the previous i variable copied into p_island0?
The same pointer returned by malloc() is returned.
malloc returns the address of the allocated memory block , as a void* wich is a generic pointer type, the address (like any other value) is being copied to i.
the address returned from malloc is being stored in p_island0.
*the address returned from malloc is to the heap memory , the allocated memory lives untill 'free' function is being called or untill the program ends.
island is probably a struct.
The function create(char *name) has its own scope
island *i = malloc(sizeof(island));
This statement allocates memory which is pointed by i.
Therefore, i is limited to this function's scope. This is not accessible outside the function.
However, the function returns the value(memory location) pointed by i which will ultimately be stored in p_island0.
void local () {
int x = 100;
double *loc;
loc = (double *) malloc(sizeof(double)*100);
memset(rxnrun, 0x0, sizeof(double)*100);
// perform some operations
// free(loc);
return; // without doing free for loc variable
}
here, i can see what is wrong as memory leak is there for loc variable. But, what about variable x? What will happen to memory space acquired by both variable if we leave variable x as well as loc variable unattended (not free) after function return?
Will they (both variables) still acquire space?
Actually, both the x and loc variables are local function variables, and both variables are freed when the function returns.
However, loc is a pointer and the memory the pointer points to is what is not freed. It's just the memory allocated by malloc() that is not freed.
All C implementations use a call stack. So a local variable is on that stack (or in a register) and disappears when the called function returns.
In theory, C does not require any call stack. In practice, all C implementations use one.
In fact, a local variable is lost (so disappears) when the block (between braces) declaring it is exited. Actually, the slot on the call frame may be reused, or the variable sits in a register which is often reused for other means.
When coding in C you should think as if every local variable disappears when its block is exited. The compiler is free to implement that abstraction as it wants (generally, using a call stack, or keeping that variable in some register or some other area which will be reused later).
Notice that in your example both x and loc are local variables. But loc contains a pointer to a memory zone on the heap. And that zone is released by free
Read about undefined behavior, e.g.
// WRONG CODE!
int* p = 0;
{
int y = 23;
p = &y;
};
int z = *p; // undefined behavior
Here y is a local variable to the block in braces. You store its address in p. When you dereference that address to put its content into z you have an undefined behavior and the implementation can do anything (including destroying the universe, or exploding your computer) and still be conformant to the specification of C.
What happens in reality is unpredictable without knowing the specific implementation and environment. Actually, and this is bad for you, the above code might not even "fault" and something could be stored in z.
variables x and loc will be forgotten, but memory allocated by malloc will be occupied but pointer to this memory will be forgotten.
nothing good will come.
Why can I return from a function an array setup by malloc:
int *dog = (int*)malloc(n * sizeof(int));
but not an array setup by
int cat[3] = {0,0,0};
The "cat[ ]" array is returned with a Warning.
Thanks all for your help
This is a question of scope.
int cat[3]; // declares a local variable cat
Local variables versus malloc'd memory
Local variables exist on the stack. When this function returns, these local variables will be destroyed. At that point, the addresses used to store your array are recycled, so you cannot guarantee anything about their contents.
If you call malloc, you will be allocating from the heap, so the memory will persist beyond the life of your function.
If the function is supposed to return a pointer (in this case, a pointer-to-int which is the first address of the integer array), that pointer should point to good memory. Malloc is the way to ensure this.
Avoiding Malloc
You do not have to call malloc inside of your function (although it would be normal and appropriate to do so).
Alternatively, you could pass an address into your function which is supposed to hold these values. Your function would do the work of calculating the values and would fill the memory at the given address, and then it would return.
In fact, this is a common pattern. If you do this, however, you will find that you do not need to return the address, since you already know the address outside of the function you are calling. Because of this, it's more common to return a value which indicates the success or failure of the routine, like an int, than it is to return the address of the relevant data.
This way, the caller of the function can know whether or not the data was successfully populated or if an error occurred.
#include <stdio.h> // include stdio for the printf function
int rainCats (int *cats); // pass a pointer-to-int to function rainCats
int main (int argc, char *argv[]) {
int cats[3]; // cats is the address to the first element
int success; // declare an int to store the success value
success = rainCats(cats); // pass the address to the function
if (success == 0) {
int i;
for (i=0; i<3; i++) {
printf("cat[%d] is %d \r", i, cats[i]);
getchar();
}
}
return 0;
}
int rainCats (int *cats) {
int i;
for (i=0; i<3; i++) { // put a number in each element of the cats array
cats[i] = i;
}
return 0; // return a zero to signify success
}
Why this works
Note that you never did have to call malloc here because cats[3] was declared inside of the main function. The local variables in main will only be destroyed when the program exits. Unless the program is very simple, malloc will be used to create and control the lifespan of a data structure.
Also notice that rainCats is hard-coded to return 0. Nothing happens inside of rainCats which would make it fail, such as attempting to access a file, a network request, or other memory allocations. More complex programs have many reasons for failing, so there is often a good reason for returning a success code.
There are two key parts of memory in a running program: the stack, and the heap. The stack is also referred to as the call stack.
When you make a function call, information about the parameters, where to return, and all the variables defined in the scope of the function are pushed onto the stack. (It used to be the case that C variables could only be defined at the beginning of the function. Mostly because it made life easier for the compiler writers.)
When you return from a function, everything on the stack is popped off and is gone (and soon when you make some more function calls you'll overwrite that memory, so you don't want to be pointing at it!)
Anytime you allocate memory you are allocating if from the heap. That's some other part of memory, maintained by the allocation manager. Once you "reserve" part of it, you are responsible for it, and if you want to stop pointing at it, you're supposed to let the manager know. If you drop the pointer and can't ask to have it released any more, that's a leak.
You're also supposed to only look at the part of memory you said you wanted. Overwriting not just the part you said you wanted, but past (or before) that part of memory is a classic technique for exploits: writing information into part of memory that is holding computer instructions instead of data. Knowledge of how the compiler and the runtime manage things helps experts figure out how to do this. Well designed operating systems prevent them from doing that.
heap:
int *dog = (int*)malloc(n*sizeof(int*));
stack:
int cat[3] = {0,0,0};
Because int cat[3] = {0,0,0}; is declaring an automatic variable that only exists while the function is being called.
There is a special "dispensation" in C for inited automatic arrays of char, so that quoted strings can be returned, but it doesn't generalize to other array types.
cat[] is allocated on the stack of the function you are calling, when that stack is freed that memory is freed (when the function returns the stack should be considered freed).
If what you want to do is populate an array of int's in the calling frame pass in a pointer to an that you control from the calling frame;
void somefunction() {
int cats[3];
findMyCats(cats);
}
void findMyCats(int *cats) {
cats[0] = 0;
cats[1] = 0;
cats[2] = 0;
}
of course this is contrived and I've hardcoded that the array length is 3 but this is what you have to do to get data from an invoked function.
A single value works because it's copied back to the calling frame;
int findACat() {
int cat = 3;
return cat;
}
in findACat 3 is copied from findAtCat to the calling frame since its a known quantity the compiler can do that for you. The data a pointer points to can't be copied because the compiler does not know how much to copy.
When you define a variable like 'cat' the compiler assigns it an address. The association between the name and the address is only valid within the scope of the definition. In the case of auto variables that scope is the function body from the point of definition onwards.
Auto variables are allocated on the stack. The same address on the stack is associated with different variables at different times. When you return an array, what is actually returned is the address of the first element of the array. Unfortunately, after the return, the compiler can and will reuse that storage for completely unrelated purposes. What you'd see at a source code level would be your returned variable mysteriously changing for no apparent reason.
Now, if you really must return an initialized array, you can declare that array as static. A static variable has a permanent rather than a temporary storage allocation. You'll need to keep in mind that the same memory will be used by successive calls to the function, so the results from the previous call may need to be copied somewhere else before making the next call.
Another approach is to pass the array in as an argument and write into it in your function. The calling function then owns the variable, and the issues with stack variables don't arise.
None of this will make much sense unless you carefully study how the stack works. Good luck.
You cannot return an array. You are returning a pointer. This is not the same thing.
You can return a pointer to the memory allocated by malloc() because malloc() has allocated the memory and reserved it for use by your program until you explicitly use free() to deallocate it.
You may not return a pointer to the memory allocated by a local array because as soon as the function ends, the local array no longer exists.
This is a question of object lifetime - not scope or stack or heap. While those terms are related to the lifetime of an object, they aren't equivalent to lifetime, and it's the lifetime of the object that you're returning that's important. For example, a dynamically alloced object has a lifetime that extends from allocation to deallocataion. A local variable's lifetime might end when the scope of the variable ends, but if it's static its lifetime won't end there.
The lifetime of an object that has been allocated with malloc() is until that object has been freed using the free() function. Therefore when you create an object using malloc(), you can legitimately return the pointer to that object as long as you haven't freed it - it will still be alive when the function ends. In fact you should take care to do something with the pointer so it gets remembered somewhere or it will result in a leak.
The lifetime of an automatic variable ends when the scope of the variable ends (so scope is related to lifetime). Therefore, it doesn't make sense to return a pointer to such an object from a function - the pointer will be invalid as soon as the function returns.
Now, if your local variable is static instead of automatic, then its lifetime extends beyond the scope that it's in (therefore scope is not equivalent to lifetime). So if a function has a local static variable, the object will still be alive even when the function has returned, and it would be legitimate to return a pointer to a static array from your function. Though that brings in a whole new set of problems because there's only one instance of that object, so returning it multiple times from the function can cause problems with sharing the data (it basically only works if the data doesn't change after initialization or there are clear rules for when it can and cannot change).
Another example taken from another answer here is regarding string literals - pointers to them can be returned from a function not because of a scoping rule, but because of a rule that says that string literals have a lifetime that extends until the program ends.