Structures and memory management, C - c

I'm trying to understand some things about structures and memory management. I have three versions code whose result is identical. They only differ in the definition/allocation of the structure. In version one, the structure is allocated with this code: resultValue_t *resultVal = malloc(sizeof(resultValue_t));. In version two, the structure is created inside the function: resultValue_t resultVal;. In version three resultValue_t resultVal; is created globally.
I would like to ask how the three definitions actually differ? Which one gives which possibilities? And which one is more appreciated?
I know that if a structure is accessed via a pointer, the -> operator should be used, etc. But here I'm curious about the difference and possibilities between these definitions.
//version_1
typedef struct
{
int valOne;
int valTwo;
}resultValue_t;
void twoSum(int *array, int sum)
{
int baseVal, tempSum;
int arrLen = sizeof(array);
resultValue_t *resultVal = malloc(sizeof(resultValue_t));
//...
if (tempSum == sum)
{
resultVal->valOne = array[index];
resultVal->valTwo = array[nIndex];
printf("%d + %d\n", resultVal->valOne, resultVal->valTwo);
}
//...
free(resultVal);
}
//version_2
typedef struct
{
int valOne;
int valTwo;
}resultValue_t;
void twoSum2(int *array, int sum)
{
int baseVal, tempSum;
resultValue_t resultVal;
//...
if (tempSum == sum)
{
resultVal.valOne = array[index];
resultVal.valTwo = array[nIndex];
printf("%d + %d\n", resultVal.valOne, resultVal.valTwo);
}
//...
}
//version_3
typedef struct
{
int valOne;
int valTwo;
}resultValue_t;
resultValue_t resultVal;

The difference is "storage duration", i.e. the lifetime of object.
In version 1 "allocated storage duration" is used. That means that the object resultVal exists after malloc returns and until some code explicit "kills it" by calling free. On most systems memory is allocated in an area called heap. The allocation is typically slow (i.e. don't use it unless there is a good reason - see later).
In version 2 "automatic storage duration" is used. That means that the object resultVal exists until execution of the associated block ends. In this case until the function returns. In other words - in this case the object resultVal is automatically created when execution enters the function and automatically destroyed when execution leaves the function.
On most systems memory is allocated in an area called stack. The allocation is typically very fast.
In version 3 "static storage duration" is used. That means that the object resultVal exists from execution start to execution end. So the object can be accessed at any time from anywhere in the code. Memory is typically allocated in some special area as part of program start up and it's also very fast.
Obviously there are use cases for all 3 types.
Version 3 shall in general be avoided but there are special cases where static objects make sense. When used it's typically good to limit their use to "file scope" using the keyword static.
In most cases you should go for version 2 as it is fast and secure. However, if the size of the object (in this case resultVal) is very big, version 2 should be avoided due to risk of stack overflow. In that case use version 1.
Version 1 is also useful (actually required) if you want the object to be "alive" after the function returns. That however is not the case for the example in the question as free is called before leaving the function.
Conclusion:
Since resultValue_t; is a rather small object type and the object resultVal doesn't need to be "alive" after the function call, you should go for version 2.

Version 1 allocates memory from the heap.
Version 2 allocates memory from the stack.
Version 3 uses memory from the bss section (In every compiler implementation I've used, but it could come from elsewhere). It's also the only version that initializes the object (in this case, to all zeroes).

Related

Is Dynamically allocated memory global?

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.

In C, why are the first members of a struct frequently "reset" to 0 when it is deallocated with free()?

The setup
Let's say I have a struct father which has member variables such as an int, and another struct(so father is a nested struct). This is an example code:
struct mystruct {
int n;
};
struct father {
int test;
struct mystruct M;
struct mystruct N;
};
In the main function, we allocate memory with malloc() to create a new struct of type struct father, then we fill it's member variables and those of it's children:
struct father* F = (struct father*) malloc(sizeof(struct father));
F->test = 42;
F->M.n = 23;
F->N.n = 11;
We then get pointers to those member variables from outside the structs:
int* p = &F->M.n;
int* q = &F->N.n;
After that, we print the values before and after the execution of free(F), then exit:
printf("test: %d, M.n: %d, N.n: %d\n", F->test, *p, *q);
free(F);
printf("test: %d, M.n: %d, N.n: %d\n", F->test, *p, *q);
return 0;
This is a sample output(*):
test: 42, M.n: 23, N.n: 11
test: 0, M.n: 0, N.n: 1025191952
*: Using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Full code on pastebin: https://pastebin.com/khzyNPY1
The question
That was the test program that I used to test how memory is deallocated using free(). My idea(from reading K&R "8.7 Example - A Storage Allocator", in which a version of free() is implemented and explained) is that, when you free() the struct, you're pretty much just telling the operating system or the rest of the program that you won't be using that particular space in memory that was previously allocated with malloc(). So, after freeing those memory blocks, there should be garbage values in the member variables, right? I can see that happening with N.n in the test program, but, as I ran more and more samples, it was clear that in the overwhelming majority of cases, these member variables are "reset" to 0 more than any other "random" value. My question is: why is that? Is it because the stack/heap is filled with zeroes more frequently than any other value?
As a last note, here are a few links to related questions but which do not answer my particular question:
C - freeing structs
What REALLY happens when you don't free after malloc?
After calling free, the pointers F, p and q no longer point to valid memory. Attempting to dereference those pointers invokes undefined behavior. In fact, the values of those pointers become indeterminate after the call to free, so you may also invoke UB just by reading those pointer values.
Because dereferencing those pointers is undefined behavior, the compiler can assume it will never happen and make optimizations based on that assumption.
That being said, there's nothing that states that the malloc/free implementation has to leave values that were stored in freed memory unchanged or set them to specific values. It might write part of its internal bookkeeping state to the memory you just freed, or it might not. You'd have to look at the source for glibc to see exactly what it's doing.
Apart from undefined behavior and whatever else the standard might dictate, since the dynamic allocator is a program, fixed a specific implementation, assuming it does not make decisions based on external factors (which it does not) the behavior is completely deterministic.
Real answer: what you are seeing here is the effect of the internal workings of glibc's allocator (glibc is the default C library on Ubuntu).
The internal structure of an allocated chunk is the following (source):
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};
In memory, when the chunk is in use (not free), it looks like this:
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of previous chunk, if unallocated (P clear) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of chunk, in bytes |A|M|P| flags
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| User data starts here... |
Every field except mchunk_prev_size and mchunk_size is only populated if the chunk is free. Those two fields are right before the user usable buffer. User data begins right after mchunk_size (i.e. at the offset of fd), and can be arbitrarily large. The mchunk_prev_size field holds the size of the previous chunk if it's free, while the mchunk_size field holds the real size of the chunk (which is at least 16 bytes more than the requested size).
A more thorough explanation is provided as comments in the library itself here (highly suggested read if you want to know more).
When you free() a chunk, there are a lot of decisions to be made as to where to "store" that chunk for bookkeeping purposes. In general, freed chunks are sorted into double linked lists based on their size, in order to optimize subsequent allocations (that can get already available chunks of the right size from these lists). You can see this as a sort of caching mechanism.
Now, depending on your glibc version, they could be handled slightly differently, and the internal implementation is quite complex, but what is happening in your case is something like this:
struct malloc_chunk *victim = addr; // address passed to free()
// Add chunk at the head of the free list
victim->fd = NULL;
victim->bk = head;
head->fd = victim;
Since your structure is basically equivalent to:
struct x {
int a;
int b;
int c;
}
And since on your machine sizeof(struct malloc_chunk *) == 2 * sizeof(int), the first operation (victim->fd = NULL) is effectively wiping out the contents of the first two fields of your structure (remember, user data begins exactly at fd), while the second one (victim->bk = head) is altering the third value.
The Standard specifies nothing about the behavior of a program that uses a pointer to allocated storage after it has been freed. Implementations are free to extend the language by specifying the behavior of more programs than required by the Standard, and the authors of the Standard intended to encourage variety among implementations which would support popular extensions on a quality-of-implementation basis directed by the marketplace. Some operations with pointers to dead objects are widely supported (e.g. given char *x,*y; the Standard would allow conforming implementations to behave in arbitrary fashion if a program executes free(x); y=x; in cases where x had been non-null, without regard for whether anything ever does anything with y after its initialization, but most implementations would extend the language to guarantee that such code would have no effect if y is never used) but dereferencing of such pointers generally isn't.
Note that if one were to pass two copies of the same pointer to a freed object to:
int test(char *p1, char *p2)
{
char *q;
if (*p1)
{
q = malloc(0):
free(q);
return *p1+*p2;
}
else
return 0;
}
it is entirely possible that the act of allocating and freeing q would disturb the bit patterns in the storage that had been allocated to *p1 (and also *p2), but a compiler would not be required to allow for that possibility. A compiler might plausibly return the sum of the value that was read from *p1 before the malloc/free, and a value that was read from *p2 after it; this sum could be an odd number even though if p1 and p2 are equal, *p1+*p2 should always be even.
Two things happen when you call free:
In the C model of computing, any pointer values that point to the freed memory (either its beginning, such as your F, or things within it, such as your p and q) are no longer valid. The C standard does not define what happens when you attempt to use these pointer values, and optimization by the compiler may have unexpected effects on how your program behaves if you attempt to use them.
The freed memory is released for other purposes. One of the most common other purposes for which it is used is tracking memory that is available for allocation. In other words, the software that implements malloc and free needs data structures to record which blocks of memory have been freed and other information. When you free memory, that software often uses some of the memory for this purpose. That can result in the changes you saw.
The freed memory may also be used by other things in your program. In a single-threaded program without signal handlers or similar things, generally no software would run between the free and the preparation of the arguments to the printf you show, so nothing else would reuse the memory so quickly—reuse by the malloc software is the most likely explanation for what you observed. However, in a multithreaded program, the memory might be reused immediately by another thread. (In practice, this may be a bit unlikely, as the malloc software may keep preferentially separate pools of memory for separate threads, to reduce the amount of inter-thread synchronization that is necessary.)
When a dynamically allocated object is freed, it no longer exists. Any subsequent attempt to access it has undefined behavior. The question is therefore nonsense: the members of an allocated struct cease to exist at the end of the host struct's lifetime, so they cannot be set or reset to anything at that point. There is no valid way to attempt to determine any values for such no-longer-existing objects.

Function that returns an array of strings C

Is there a way to return an array of strings from a function without using dynamic memory allocation? The function goes something like this:
char** modify(char original[1000][1000]){
char result[1000][1000];
// some operations are applied to the original
// the original is copied to the result
return result;
}
In C, an object has one of four storage durations (also called lifetimes): static, thread, automatic, and allocated (C 2018 6.2.4 1).
Objects with automatic duration are automatically created inside a function and cease to exist when execution of the function ends, so you cannot use these that is created inside your function to return a value.
Objects with allocated storage duration persist until freed, but you have asked to exclude those.
Thread storage duration is either likely not applicable to your situation or is effectively equivalent to static storage duration, which I will discuss below.
This means your options are:
Let the caller pass you an object in which to return data. That object may have any storage duration—your function does not need to know since it will neither allocate nor release it. If you do this, the caller must provide an object large enough to return the data. If this size is not known in advance, you can either provide a separate function to calculate it (which the caller will then use to allocate the necessary space) or incorporate that into your function as a special mode in which it provides the size required without providing the data yet.
Use an object with static storage duration. Since this object is created when the program starts, you cannot adjust the size within your function. You must build a size limit into the program. A considerable problem with this approach is the function has only one object to return, so only one can be in use at a time. This means that, once the function is called, it should not be called again until the caller has finished using the data in the object. This is both a severe limitation in program design and an opportunity for bugs, so it is rarely used.
Thus, a typical solution looks like this:
size_t HowMuchSpaceIsNeeded(char original[1000][1000])
{
… Calculate size.
return SizeNeeded;
}
void modify(char destination[][1000], char original[1000][1000])
{
… Put results in destination.
}
A variation for safety is:
void modify(char destination[][1000], size_t size, char original[1000][1000])
{
if (size < amount needed)
… Report error (possibly by return value, or program abort).
… Put results in destination.
}
Then the caller does something like:
size_t size = HowMuchSpaceIsNeeded(original);
char (*results)[1000] = malloc(size);
if (!results)
… Report error.
modify(results, size, original)
… Work with results.
free(results);
As Davistor notes, a function can return an array embedded in a structure. In terms of C semantics, this avoids the object lifetime problem by returning a value, not an object. (The entire contents of the structure is the value of the structure.) In terms of actual hardware implementation, it is largely equivalent to the caller-passes-an-object method above. (The reasoning here is based on the logic of how computers work, not on the C specification: In order for a function to return a value that requires a lot of space to represent, the caller must provide the required space to the called function.) Generally, the caller will allocate space on the stack and provide that to the called function. This may be faster than a malloc, but it may also use a considerable amount of stack space. Usually, we avoid using sizable amounts of stack space, to avoid overflowing the stack.
Although you cannot return an array type in C, you can return a struct containing one:
#include <string.h>
#define NSTRINGS 100
#define STR_LEN 100
typedef struct stringtable {
char table[NSTRINGS][STR_LEN];
} stringtable;
stringtable modify ( const stringtable* const input )
{
stringtable result;
memcpy( &result, input, sizeof(result) );
return result;
}
I would generally recommend that you use Eric Postpischil’s solution, however. One way this might not be efficient is if you need to write to a specific variable or location. In that case, you could pass in its address, but here, you would need to create a large temporary array and copy it.
You cannot return a pointer to memory allocated inside a function without dynamic allocation. In your case, you will allocate result[1000][1000] on the stack in a zone which will be deallocated once the function returns. Besides dynamic allocation, you have the option of passing a buffer as an argument to your function:
void modify(char original[1000][1000], char result[][]) { ... }
Now the result matrix has to be allocated outside the modify function and its lifetime will not depend on the function's lifetime. Basically you pass the function an already allocated matrix where the result will be written.
You can't return pointers to the local variables, because lifetime of the memory to which they point is limited to the scope.
Basically result is a pointer to the stack-allocated array first element, so returning it and dereferencing it later will result in undefined behavior.
To bypass this issue, there are few work-arounds.
One of those, I saw in couple of projects, but I don't recommend it, because it is unsafe.
char** modify(char original[1000][1000]){
// `result` is static array, which lifetime is equal to the lifetime of the program
// Calling modify more than one time will result in overwriting of the `result`.
static char result[1000][1000];
return result;
}
Another approach will be to receive result pointer as function argument, so the caller will allocate storage for it.
void modify(char original[1000][1000], char (*result)[1000]){
result[0][1] = 42;
//...
}
void main() {
char result[1000][1000];
modify(someOriginal, result);
}
Anyway, I recommend you to read some decent book about C language and how a computer memory works.
You can use a linked list starts with the first string and ends with the last string .

If I define an array in if statement then does memory get allocated?

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

Static vs. Malloc

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.

Resources