Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When use malloc for a static pointer inside a function?

Tags:

c

pointers

static

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:

  1. Do I understand it correctly?
  2. 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.
  3. I must free temp inside func (at the last step, which, by the way, is not done in this code)?

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.

like image 336
terence hill Avatar asked Dec 22 '15 16:12

terence hill


People also ask

What is the malloc () function in C++?

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.

Why is the result of malloc () function typecasted as (float*)?

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.

What happens when a pointer is returned from malloc ()?

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.

Can I use malloc(sizeof(int)) to initialize static objects?

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.


4 Answers

"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.

freeing such allocated data can be handled various ways. One is to add a parameter to explicitly request freeing. 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.

like image 131
too honest for this site Avatar answered Nov 14 '22 23:11

too honest for this site


  1. 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.

  1. 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.

  1. 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.

like image 24
John Bollinger Avatar answered Nov 15 '22 00:11

John Bollinger


  1. Do I understand it correctly?

Yes, you do.

  1. 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.

  1. 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
}
like image 39
R Sahu Avatar answered Nov 14 '22 23:11

R Sahu


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.

like image 25
n. 1.8e9-where's-my-share m. Avatar answered Nov 14 '22 22:11

n. 1.8e9-where's-my-share m.