Gianni
Gianni

Reputation: 518

memory shared by functions stored in one of the functions static variable

Within a larger project, i am to write a list of C functions which work on a same memory structure. As these functions are called in very different parts of the code (and in different libraries which are compiled separately and then linked), I would like to avoid having to pass a pointer to the memory structure as argument to each of my function calls.

I was thinking to store the memory structure as a static variable in a single function, and to always call that function within my other functions to get back a pointer to the memory structure. In the sample below, I use storage() to get set the sto pointer.

I tested the code below and it seems to work fine. Is this a standard approach? What risks am i running? Will that always work? Better solutions?

There are no concurrent calls to my functions. Of course i whould free the allocated memory as well.

#include <stdio.h>
#include <stdlib.h>

int* storage(int get_set)
{
    static int* sto;
    if (get_set==1)
    {
        sto=malloc(2*sizeof(int));
        sto[0]=1;
        sto[1]=2;
    }
    printf("storage: content = %d %d, pointer= %d\n", sto[0], sto[1], sto);
    return sto;
}

void add11()
{
    int* sto =storage(0);
    sto[0]+=1;
    sto[1]+=1;
    printf("add11: content = %d %d, pointer= %d \n", sto[0], sto[1], sto);
}

void multo0()
{
    int* sto =storage(0);
    sto[0]=sto[1]*sto[0];
    sto[1]=0;
    printf("multo0: content = %d %d, pointer= %d\n", sto[0], sto[1], sto);
}


int main(void) {
    storage(1); // initialize memory only once
    add11();  // work on memory 
    multo0();
    add11();
    // ...
    return 0;
}

The reason why I wanted something like this is the following:

The set of functions i am writing perform a separate and auxiliary optional task of image enhancement, and learn from previous observed images in different manners. sto stores memory for this learning and for parametrization options.

In the overall projects, my functions would be called in multiple nested functions calls. Passing sto as argument would mean declaring the a pointer in the main of the project and changing a large number of core nested functions having nothing to do with the task performed by my functions to pass the additional argument.

Also, the same set of functions is to be integrated in multiple slightly different projects, so a less intrusive integration, having to modify as little as possible of the external code, would be a plus.

For the readability issue, all and only the functions accessing the shared memory have the same prefix. I know this is no full solution but I believe it adds a little bit of readability.

Is there still no option but changing all functions to carry sto all around the project?

Upvotes: 1

Views: 415

Answers (3)

Ivan Voras
Ivan Voras

Reputation: 2014

Since you already have multiple modules you are linking together, the "more standard" approach would be to have a static (private to the single module) variable (1st approach) and if you need accessor functions, return a pointer to that. But if the accessor will simply return a pointer to it, you could simply use "extern" and have access to the data in a natural way (2nd approach).

1st approach:

module containing the data:

static int mydata; /* note: "static" */

int* accessor() {
    return &mydata;
}

module using the data:

int* accessor();

int main() {
    int* foo = accessor();
}

2nd approach:

module containing the data:

int mydata; /* note: no "static" */

module using the data:

extern int mydata; /* note: "extern" */

int main() {
    int* foo = &mydata;
}

The second approach is "more C-ish" and faster. Note that the usual way would be to simply use "mydata" in the second case as if it were a normal local variable and not introduce pointers to it just for the sake of pointers - I did it here to be consistent with the first case.

Upvotes: 2

AndersK
AndersK

Reputation: 36102

There are several drawbacks to this

first your function allocates memory everytime it is called but it is not clear from the name of the function that the caller needs to explicitly free what is returned.

second it acts as a global value, it is better to pass data between functions using a pointer since it makes it more clear - from a readability standpoint - which function accesses the data by just looking at the function prototype:

void foo(storage* p);
void foo1();
void foo2(const storage* p);

third you add overhead when you access the data

you have a memory leak in your storage function as well, you declare sto as static but do not check if it already points to something before assigning it to a malloc.

static int* sto;
if (get_set==1)
{
    sto=malloc(2*sizeof(int));
    sto[0]=1;
    sto[1]=2;
}

should be something like

static int* sto;
if (get_set==1)
{
    if ( sto != NULL ) 
    {
      free(sto);
    }
    sto=malloc(2*sizeof(int));
    sto[0]=1;
    sto[1]=2;
}

if you still insist on using this method you should at least put the values in a struct, then the values will be copied and you do not need to allocate heap everytime (with the drawback of some more overhead).

typedef struct
{
  int a[2];
} storage_ret;

storage_ret storage(int get_set)
{
    static storage_ret sto;
    if (get_set==1)
    {
        sto.a[0]=1;
        sto.a[1]=2;
    }
    printf("storage: content = %d %d, pointer= %d\n", sto.a[0], stoa.[1], &sto);
    return sto;
}

Upvotes: 2

It&#39;sPete
It&#39;sPete

Reputation: 5211

That certainly isn't standard practice and adds a level of readability concerns to your code. Imagine someone who's just added to your project who now needs to use this code, he/she would be really confused. Also, each function call could cause some overhead, thus it would just be better to pass a pointer to all your functions.

Upvotes: 0

Related Questions