What is the advantage of the static keyword in block scope vs. using malloc?
For example:
Function A:
f() {
static int x = 7;
}
Function B:
f() {
int *x = malloc(sizeof(int));
if (x != NULL)
*x = 7;
}
If I am understanding this correctly, both programs create an integer 7 that is stored on the heap. In A, the variable is created at the very beginning in some permanent storage, before the main method executes. In B, you are allocating the memory on the spot once the function is called and then storing a 7 where that pointer points. In what type of situations might you use one method over the other? I know that you cannot free the x in function A, so wouldn't that make B generally more preferable?
Both programs create an integer 7 that is stored on the heap
No, they don't.
static creates a object with static storage duration which remains alive throughout the lifetime of the program. While a dynamically allocated object(created by malloc) remains in memory until explicitly deleted by free. Both provide distinct functionality. static maintains the state of the object within function calls while dynamically allocated object does not.
In what type of situations might you use one method over the other?
You use static when you want the object to be alive throughout the lifetime of program and maintain its state within function calls. If you are working in a multithreaded environment the same static object will be shared for all the threads and hence would need synchronization.
You use malloc when you explicitly want to control the lifetime of the object.for e.g: Making sure the object lives long enough till caller of function accesses it after the function call.(An automatic/local object will be deallocated once the scope{ } of the function ends). Unless the caller explicitly calls free the allocated memory is leaked until the OS reclaims it at program exit.
In Function A, you're allocating x with static storage duration, which generally means it is not on (what most people recognize as) the heap. Rather, it's just memory that's guaranteed to exist the entire time your program is running.
In Function B, you're allocating the storage every time you enter the function, and then (unless there's a free you haven't shown) leaking that memory.
Given only those two choices, Function A is clearly preferable. It has shortcomings (especially in the face of multi-threading) but at least there are some circumstances under which it's correct. Function B (as it stands) is just plain wrong.
Forget stack v. heap. That is not the most important thing that is going on here.
Sometimes static modifies scope and sometimes it modifies lifetime. Prototypical example:
void int foo() {
static int count = 0;
return count++;
}
Try calling this repeatedly, perhaps from several different functions or files even, and you'll see that count keeps increasing, because in this case static gives the variable a lifetime equal to that of the entire execution of the program.
Read http://www.teigfam.net/oyvind/pub/notes/09_ANSI_C_static_vs_malloc.html
The static variable is created before main() and memory does not need to be allocated after running the program.
If I am understanding this correctly, both programs create an integer 7 that is stored on the heap
No, static variables are created in Data or BSS segment, and they have lifetime throughout the lifetime of the program. When you alloc using malloc(), memory is allocated in heap, and they must be explicitly freed using free() call.
In what type of situations might you use one method over the other?
Well, you use the first method, when you want access to the same variable for the multiple invocation of the same function. ie, in your example, x will only initialized once, and when you call the method for the second time, the same x variable is used.
Second method can be used, when you don't want to share the variable for multiple invocation of the function, so that this function is called for the second time, x is malloced again.
You must free x every time.
You can see the difference by calling f() 2 times, for each kind of f()
...
f();
f();
...
f(){
static int x = 7;
printf("x is : %d", x++);
}
f(){
int *x = malloc(sizeof(int));
if (x != NULL)
*x = 7;
printf("x is : %d", (*x)++);
free(x); //never forget this,
}
the results will be different
First things first , static is a storage class , and malloc() is an API , which triggers the brk() system call to allocate memory on the heap.
If I am understanding this correctly, both programs create an integer
7 that is stored on the heap ?
No.Static variables are stored in the data section of the memory allocated to the program. Even though if the scope of a static variable ends , it can still be accessed outside its scope , this may indicate that , the contents of data segment , has a lifetime independent of scope.
In what type of situations might you use one method over the other?
If you want more control , within a given scope ,over your memory use malloc()/free(), else the simpler (and more cleaner) way is to use static.
In terms of performance , declaring a variable static is much faster , than allocating it on the heap . since the algorithms for heap management is complex and the time needed to service a heap request varies depending on the type of algorithm
One more reason i can think of suggesting static is that , the static variables are by default initialized to zero , so one more less thing to worry about.
consider below exaple to understand how static works. Generally we use static keyword to define scope of variable or function. e.g. a variable defined as static will be restricted within the function and will retail its value.
But as shown in below sample program if you pass the reference of the static variable to any other function you can still update the same variable from any other function.
But precisely the static variable dies when the program terminates, it means the memory will be freed.
#include <stdio.h>
void f2(int *j)
{
(*j)++;
printf("%d\n", *j);
}
void f1()
{
static int i = 10;
printf("%d\n", i);
f2(&i);
printf("%d\n", i);
}
int main()
{
f1();
return 0;
}
But in case of malloc(), memory will not be freed on termination of the program unless and untill programmer takes care of freeing the memory using free() before termination of the program.
This way you will feel that using malloc() we can have control over variable lifespan but beware...you have to be very precise in allocating and freeing the memory when you choose dynamic memory allocation.
If you forget to free the memory and program terminated that part of heap cannot be used to allocate memory by other process. This will probably lead to starvation of memory in real world and slows down the computation. To come out of such situation you have to manually reboot the system.
Related
I am wondering if dynamically allocated memory with malloc global? I am reading online that allocated memory with malloc is stored on the heap. I also read online that all global variables are stored on the heap. Wouldn't this mean that dynamically allocated memory can be accessed globally? For example, I receive an error with the following code:
#include <stdio.h>
#include <stdlib.h>
void my_func(void)
{
printf("Pointer variables is: %d\n", *ptr);
}
int main()
{
int *ptr = (int *)malloc(sizeof(int));
*ptr = 5;
my_func();
return 0;
}
However, when i run the following code with a global variable there is no error:
#include <stdio.h>
int var = 5;
void my_func(void)
{
printf("Global variable is: %d\n", var);
}
int main()
{
my_func();
return 0;
}
You can access the memory created by malloc anywhere as long as you don't free it. I think that is your meaning of global.
But the ptr is a local variable of pointer type, points to the memory allocated. You have to pass it as a parameter of the function to use it.
They are two different concepts.
First, C has no global scope. “Global” means a name (an identifier) can be defined once and will be known throughout the program. In C, for a name to be known in multiple translation units, you must declare it in each translation unit where it is to be known (and define it in one of them) and link the translated files together.
Second, it would only make sense to speak of names as global or as having linkage (the property about linking different declarations of a name to the same object or function) or scope (where in a program a name is visible, meaning able to be used). Memory does not have scope or linkage. It might be said to be global in the sense it is accessible throughout the entire program, but “global” is not the right word for this since that is about visibility of names.
Third, “on the heap” is slang and should be avoided. Memory is dynamically allocated. (The C standard uses just “allocated,” but “dynamically allocated” is more explicit and is clearer in other contexts.) This slang arose because early memory management software would keep records about free blocks of memory in a heap data structure. When memory was allocated, if it could be satisfied by an existing free block, that block would be removed from the heap and given to the calling routine for its use. So allocated memory is actually taken off the heap; it is not on the heap. And modern memory managers may use diverse data structures to hold their records, either with or without heaps.
The typical memory model for a program is that all of its memory is accessible throughout the program. When memory is reserved for some use, whether by malloc or by other means, that memory may be used by any software in the program that has the address of that memory. Some memory is limited in how it may be used. For example, some may hold initialized data and be marked read-only, so that it cannot be modified. Other memory may hold program instructions and be marked as executable, so it can be executed (by a jump instruction or other instruction that transfers program control to that memory), whereas other memory in the program cannot be executed. However, these limitations generally apply to all software seeking to access memory in one way or another, unless special provisions are made (such as by calling operating system routines to change the protections).
In your program, ptr is not declared before my_func. Because of this, it is not visible inside my_func. This means the name ptr is not usable. It has nothing to do with the memory that ptr points to. To make the name ptr visible inside my_func, you must declare it prior to using it. One way to do this would be to declare an external variable (here, “external” means outside of any function):
int *ptr; // External declaration (and tentative definition).
void my_func(void)
{
printf("Pointer variables is: %d\n", *ptr);
}
int main()
{
ptr = malloc(sizeof *ptr); // Changed from declaration to assignment.
*ptr = 5;
my_func();
return 0;
}
Another way is to declare it as a function parameter:
void my_func(int *ptr)
{
printf("Pointer variables is: %d\n", *ptr);
}
int main()
{
int *ptr = malloc(sizeof *ptr);
*ptr = 5;
my_func(ptr);
return 0;
}
In this case, `void my_func(int *ptr)` declares a **different** `ptr` from the one in `main`. There are two variables named `ptr` in this program, and they are not linked together. The one in `main` is given a value in `main`. Then the call `my_func(ptr)` passes the value of this `ptr` to `my_func`. When `my_func` starts executing, a new variable named `ptr` is created and is given the value passed as the argument.
Bonus: I changed `(int *)malloc(sizeof(int));` to `malloc(sizeof *ptr);`. In C, unlike C++, it is not necessary to cast the result of `malloc`, and it is recommended not to because doing so can conceal the error of failing to use `#include <stdlib.h>`. Also, `malloc(sizeof *ptr)` says to allocate space for one of whatever type `ptr` points to. With `malloc(sizeof(int))`, an error can occur if somebody changes the type of `ptr` but forgets to find all places that type is used with `ptr` and change them too. With `malloc(sizeof *ptr)`, appropriate space will be allocated even if the type of `ptr` is changed with no other edits.
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.
I am trying to understand C language, more specifically about memory managment. I have a function func that takes 1 argument, an int pointer. If I used int i instead of int *i it would allocate more memory because the value would be copied. Since I know that both func1 and func2 will not change the i variable, the result of those 2 functions is exactly the same.
What would happen if I called those functions many times ? Obviously the func1 would perform better, correct ? What about func2 ? Would it allocate new memory every time it is called ? So allocate 10000 * 4 extra bytes ? or just 4 extra bytes ?
I suppose it allocates 4 extra bytes, if it actually is, when is this memory allocated ? Is it when the function is first called ? Also, how and when will this 4(?) bytes of memory become free ?
void func1(int *i)
{
}
void func2(int i)
{
}
void main()
{
int x = 100;
for(int i = 0; i < 10000 ; i++) func1(&x);
for(int i = 0; i < 10000 ; i++) func2(x);
}
This is probably compiler-specific (you could look through the C spec to be sure), but the integer parameter should be allocated on the call stack for the function. Each time you call the function, there will be an extra 4 bytes allocated to work with that will be freed when the function returns.
For the reference version of the function, it will allocate space for the int pointer on each function call. Depending on your machine, that may be bigger, smaller, or the same size as an int. Compare sizeof(int) with sizeof(int*) to see which is bigger.
Let's talk about storage duration, which is the duration for which the object (region of data storage in the execution environment, the contents of which can represent values) named by a variable exists. Function arguments and local variables with no explicit storage duration or storage duration auto or register have automatic storage duration. That is, they are created when they are declared and are destroyed when the function containing them returns.
On function call the values specified for the arguments are copied into the automatic variables representing the arguments in the function definition. These variables are destroyed on function return so unless you recursively call yourself, you won't amass tons of memory. You shouldn't care about the difference between the size of an int and an int* either unless you have a lot of these. When in doubt, profile and change the code when it turns out that you have a problem.
The C standard does not specify how arguments are passed, however, in most C implementations, the memory used by arguments are automatically allocated and freed on the call stack, which has little overhead compared to heap allocation. Usually, memory is allocated on the stack as the arguments are passed, and freed before or when the function returns.
Both versions of function will allocate memory on the call stack. The reference version will allocate memory for the pointer. And the reference version is probably slower because it involves pointer dereference.
As the risk of over simplification and looking at practicable implementation, there is generally no performance or memory difference between
void func1(int *i)
void func2(int i)
A compiler is going to implement the former something like
PUSHAL I(SP)
CALL func1
and the latter like
PUSHL I(SP)
CALL func2
For atomic values, there simply is not going to be much difference. Change to
struct somestruct
{
char buffer [20000] ;
} ;
In that case
void func3(somestruct *i)
is likely to be much faster than
void func3 (somestruct i)
because the amount of data to be copied is much greater.
If I define an array in if statement then does memory gets allocated during compile time eg.
if(1)
{
int a[1000];
}
else
{
float b[1000];
}
Then a memory of 2 * 1000 for ints + 4 * 1000 for floats get allocated?
It is reserved on the stack at run-time (assuming a non-trivial condition - in your case, the compiler would just exclude the else part). That means it only exists inside the scope block (between the {}).
In your example, only the memory for the ints gets allocated on the stack (1000 * sizeof(int)).
As you can guess, this is happening at run time. The generated code has instructions to allocate the space on the stack when the corresponding block of code is entered.
Keep in mind that this is happening because of the semantics of the language. The block structure introduces a new scope, and any automatic variables allocated in that scope have a lifetime that lasts as long as the scope does. In C, this is implemented by allocating it on the stack, which collapses as the scope disappears.
Just to drive home the point, note that the allocation would be different had the variables been of different nature.
if(1)
{
static int a[1000];
}
else
{
static float b[1000];
}
In this case, space is allocated for both the ints and the floats. The lifetime of these variables is the program. But the visibility is within the block scope they are allocated in.
Scope
Variables declared inside the scope of a pair of { } are on the stack. This applies to variables declared at the beginning of a function or in any pair of { } within the function.
int myfunc()
{
int i = 0; // On the stack, scoped: myfunc
printf("%i\n");
if (1)
{
int j = 1; // On the stack, scope: this if statement
printf("%i %i\n",i,j);
}
printf("%i %i\n",i,j); // Won't work, no j
}
These days the scope of the variables is limited to the surrounding { }. I recall that some older Microsoft compilers didn't limit the scope, and that in the example above the final printf() would compile.
So Where is it in memory?
The memory of i and j is merely reserved on the stack. This is not the same as memory allocation done with malloc(). That is important, because calling malloc() is very slow in comparison. Also with memory dynamically allocated using malloc() you have to call free().
In effect the compiler knows ahead of time what space is needed for a function's variables and will generate code that refers to memory relative to whatever the stack pointer is when myfunc() is called. So long as the stack is big enough (2MBytes normally, depends on the OS), all is good.
Stack overflow occurs in the situation where myfunc() is called with the stack pointer already close to the end of the stack (i.e. myfunc() is called by a function which in turn had been called by another which it self was called by yet another, etc. Each layer of nested calls to functions moves the stack pointer on a bit more, and is only moved back when functions return).
If the space between the stack pointer and the end of the stack isn't big enough to hold all the variables that are declared in myfunc(), the code for myfunc() will simply try to use locations beyond the end of the stack. That is almost always a bad thing, and exactly how bad and how hard it is to notice that something has gone wrong depends on the operating system. On small embedded micro controllers it can be a nightmare as it usually means some other part of the program's data (eg global variables) get silently overwritten, and it can be very hard to debug. On bigger systems (Linux, Windows) the OS will tell you what's happened, or will merely make the stack bigger.
Runtime Efficiency Considerations
In the example above I'm assigning values to i and j. This does actually take up a small amount of runtime. j is assigned 1 only after evaluation of the if statement and subsequent branch into where j is declared.
Say for example the if statement hadn't evaluated as true; in that case j is never assigned 1. If j was declared at the start of myfunc() then it would always get assigned the value of 1 regardless of whether the if statement was true - a minor waste of time. But consider a less trivial example where a large array is declared an initialised; that would take more execution time.
int myfunc()
{
int i = 0; // On the stack, scoped: myfunc
int k[10000] = {0} // On the stack, scoped: myfunc. A complete waste of time
// when the if statement evaluates to false.
printf("%i\n");
if (0)
{
int j = 1; // On the stack, scope: this if statement
// It would be better to move the declaration of k to here
// so that it is initialised only when the if evaluates to true.
printf("%i %i %i\n",i,j,k[500]);
}
printf("%i %i\n",i,j); // Won't work, no j
}
Placing the declaration of k at the top of myfunc() means that a loop 10,000 long is executed to initialise k every time myfunc() is called. However it never gets used, so that loop is a complete waste of time.
Of course, in these trivial examples compilers will optimise out the unnecessary code, etc. In real code where the compiler cannot predict ahead of time what the execution flow will be then things are left in place.
Memory for the array in the if block will be allocated on stack at run time. else part will be optimized (removed) by the compiler. For more on where the variables will be allocated memory, see Segmentation Fault when writing to a string
As DCoder & paddy corrected me, the memory will be calculated at compile time but allocated at run-time in stack memory segment, but with the scope & lifetime of the block in which the array is defined. The size of memory allocated depends on size of int & float in your system. Read this for an overview on C memory map
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.