I don't understand why, in the following code snippet, the programmer used a static variable (and as a consequence I started to doubt all my little knowledge):
int func (...) {
static unsigned int *temp = NULL;
if( temp == NULL ) {
temp = malloc(dim*sizeof(*temp));
}
// do stuff with temp
}
In main(), func is called several time in a loop:
int main() {
for (i = 0; i < N; ++i)
x = func(...);
}
The first call to func initialise the variable temp to NULL and thus temp is allocated (maybe the initialisation is also redundant (according to this post).
The function func doesn't do anything special with temp, just copy some values to it from another (global) array if a condition is met and return the number of elements written.
If I understand correctly, malloc allocates the memory in the heap, thus the memory will be persistent until it is explicitly freed and as the pointer is static it can be accessed in subsequent calls.
Then the questions:
I need to modify the code above (which is a lot more complex) and I prefer to allocate temp outside func and then pass it to the function and I want to be sure that I am not missing something important. By the way I thought I could learn something :).
Thanks.
The malloc () function stands for memory allocation. It is a function which is used to allocate a block of memory dynamically. It reserves memory space of specified size and returns the null pointer pointing to the memory location. The pointer returned is usually of type void.
The variable p is of type pointer to float or (float*), that's why the result of malloc () function is typecasted using (float*). In line 15, the if condition checks whether the pointer returned by malloc () is null pointer or not.
Notice how void pointer returned from the malloc () function is typecasted and then assigned to p. Memory allocated contains garbage value so do not try to dereference it before assigning proper values to it.
clearly, malloc (sizeof (int)); is not a constant expression, so we cannot use it for initialization of a static object. you are not initializing the static object. You're leaving it uninialized. Next instruction, you're assigning the return value of malloc () to it. So your compiler does not produce any complains.
"The first call to func
initialise the variable temp
to NULL
".
No you are not (completely) correct. A static variable is initialised by the environment before any function (including) main
is called. This is the reason initialisers for static variables have to be constant-expressions. As you understood correctly, without an explicit initialiser, it would also be set to a null pointer during startup. It is questionable if explicit is better here. Problem with explicit initialisers is for actual implementations they consume additional space in the program storage. For bare-metal embedded systems this costs precious Flash/ROM storage. Some compilers (e.g. gcc) provide options to circumvent this penalty.
So, the first call of func
will effectively allocate the object which can then be used during subsequent calls. Note that the function (and its caller) must handle allocation failure properly.
Reason not to use a global variable is information hiding. In general, you should define variables at the smallest scope possible (and reasonable). That way you can be sure the variable will not be modified elsewhere. And the likelyhood of name-clashes is reduced to a minimum. As C does not have user-defined namespaces, all such names go into a global pool, which makes this issue quite relevant.
free
ing such allocated data can be handled various ways. One is to add a parameter to explicitly request free
ing. Alternatively, there could be a global registry (basically a simple linked list) of such blocks. On program termination, a framework-function would just traverse this list and free all blocks.
Alternatively, the program could just rely on the runtime-environment which releases allocated storage automatically on exit. While legal, this is IMO not the cleanest way.
- Do I understand it correctly?
You understand the initialization of temp
correctly, for all practical intents and purposes, including that the explicit initializer is redundant. You also seem to understand the allocation correctly, and the implication of temp
being declared static
. In practice, temp
is probably initialized to NULL
before func()
is ever called, and even if it is never called, but there is no way for the program itself to tell the difference from it being initialized on the first call.
- Which is the advantage of this approach instead of malloc temp outside func and then explicitly pass it to func? I guess it depends on circumstances, ok, but maybe there is a well known example. I also saw this answer but I cannot understand the usefulness of the first example.
Presumably the amount of storage needed -- as governed by variable dim
-- is not known until run time. This is the reason for dynamic allocation.
Putting the variable in the function's local scope ensures that it has no linkage -- it is not visible and cannot be referenced (directly) from anywhere outside the function. It is, on the other hand, managed by the function itself. Other functions do not need to worry about preparing an array for this function or passing one to it, and this function does not need to rely on anyone else to set up the array correctly.
As a stylistic matter, I would be inclined to consider a static file-scope pointer instead (in which context, confusingly, the static
keyword signifies something different: internal linkage rather than static duration). The only difference would be the visibility of the variable.
Ultimately, however, the choice of visibility and provisioning of the variable are design issues that to some extent have multiple solutions. You have not provided enough information for us to reason about the specific choices made in the code you are examining.
- I must free temp inside func (at the last step, which, by the way, is not done in this code)?
If temp
is freed then it should be done inside func()
. It would be possible to expose a copy of the temp
pointer to code outside the function, in which case the allocated space could be freed via that pointer, but then temp
would be left as an invalid pointer, with no way for func()
to tell.
However, the point of making temp
static
is surely for the value to be preserved across multiple function calls, so that the allocated space need not be freed and is not leaked. Note in particular that because temp
has static duration, the initialization to NULL
is performed as if at program initialization, not each time the function is called.
In fact, it is probably not necessary to free temp
in this case. Not doing so does not create a memory leak, because the memory allocated for temp
continues to be available indefinitely (albeit only within the scope of func()
). When the program exits, that memory will be returned to the operating system, just like any other memory allocations still outstanding at that time.
- Do I understand it correctly?
Yes, you do.
- Which is the advantage of this approach instead of malloc temp outside func and then explicitly pass it to func? I guess it depends on circumstances, ok, but maybe there is a well known example. I also saw this answer but I cannot understand the usefulness of the first example.
The advantage is that the callers of the function don't need to know that func
needs a buffer to implement the functionality.
- must free temp inside func (at the last step, which, by the way, is not done in this code)?
Yes, you should. Unfortunately, the way it's implemented, you cannot do it. There is no way to access temp
outside func
. func
does not free
it due to the way it's been implemented.
In order to free
the memory allocated in func
, you can use something along the lines of:
static unsigned int *temp = NULL;
void free_temp()
{
free(temp);
}
int func () {
if( temp == NULL ) {
temp = malloc(dim*sizeof(*temp));
// Register free_temp to be called at exit time.
atexit(free_temp);
}
// do stuff with temp
}
Do I understand it correctly?
Yes.
Which is the advantage of this approach instead of malloc temp outside func and then explicitly pass it to func?
In one case, every caller must be aware of temp
and its correct initialisation for func
, making callers strongly coupled to func
. If at any time in the future the type or the size of the temp
array need to be changed, every caller is affected. In the other case, all of this is abstracted away.
I must free temp inside func?
temp
is used throughout the program lifetime. If you free it at the end of the function, you defeat its purpose, which is to reduce the number of calls to malloc
and/or retain data between invocations. You can free it at the end of the program if you find a way to. If you do free it at the end of the function, then you don't need it to be static, and you don't need the if (temp == NULL)
test. IOW you lose the reason to ask this question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With