Dynamic memory allocation with static pointer

Can someone explain to me why the following piece of code works the way it does. Here I have initialized outd

as a static pointer in a file code2.c

. Then I allocate it dynamically with malloc

. By calling it over and over from the main function in a separate file code1.c

, it looks at how the entire array behaves in a static way, since it retains all values ​​from one function call to another function call, even if memory for the array was dynamically allocated. I was expecting something like a segmentation fault.

IN code2.c

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

static double *outd;

void init0(int len)
{
    int i;
    outd=malloc(sizeof(double)*len);
    for (i=0; i<len; i++)
    {
       outd[i]=0.0;
    }
}

void showarray(int len, int iterno)
{
    int i;
    printf("iteration %d, array is \n",iterno);
    for (i=0; i<len; i++)
    {
        outd[i]=outd[i]+iterno;
        printf("%.2f ",outd[i]);
    }
    printf("\n");
}

void deletearray()
{
    free(outd);
}

      

IN code1.c

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

void init0(int len);
void showarray(int len, int iterno);
void deletearray();

int main(int argc,char* argv[])
{
    int i, len;
    len=5;

    init0(len);

    for (i=0; i<7; i++)
    {
        showarray(len,i);
    }

    deletearray();
}

      

compiling,

$(CC) -c -O2 code1.c 
$(CC) -c -O2 code2.c 
$(CC) -o bb5 code1.o code2.o -lm

      

Performance

localhost:testfft avinash$ ./bb5
iteration 0, array is 
0.00 0.00 0.00 0.00 0.00 
iteration 1, array is 
1.00 1.00 1.00 1.00 1.00 
iteration 2, array is 
3.00 3.00 3.00 3.00 3.00 
iteration 3, array is 
6.00 6.00 6.00 6.00 6.00 
iteration 4, array is 
10.00 10.00 10.00 10.00 10.00 
iteration 5, array is 
15.00 15.00 15.00 15.00 15.00 
iteration 6, array is 
21.00 21.00 21.00 21.00 21.00 

      

+1


source to share


3 answers


Please find a technical answer in the comments and other answers.
I provide code (based on your code) to illustrate these good explanations.

To achieve this illustration, I play with all types of static (two kinds), local and global variables.
(I use integers instead of pointers to keep things okay.
The difference that might be part of the answer for your outstanding puzzling is just whether the buffer changes. There are comments on what happens and what doesn't happen with this.)

code2.c:

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

// defining a pointer which is only visible from this file,
// to later be initialised to the return value of malloc()
static double *outd;

// defining an int which is only visible from this file,
// to later be initialised to some integer value
static    int  outI;

// define an int which is only visible from this file,
// but has an identically named twin in the other file
// (there be dragons)
static    int unknownTwinI;

// defining a global int which is visible from main()
          int  globalI;

void init0(int len)
{
    int i;

    // initialise the pointer
    // to the address of a buffer reserved for use via this pointer
    outd=malloc(sizeof(double)*len);

    // initialise the memory inside that buffer
    for (i=0; i<len; i++)
    {
       outd[i]=0.0;
    }

    // initialise the int to a value
    outI = 0;

    // initialise the global int to a value
    globalI = 5;

    // initialise one of the two twins
    unknownTwinI = 6;
}

// show the content of the buffer referenced by the pointer
// and the value of the integer
void showarray(int len, int iterno)
{
    int i;

    // make a function local, non-static integer
           int locI =0; // this init happens every time the functin is executed
    // make a function-local, but static integer
    static int inI  =0; // this init happens before the first execution of the function

    printf("iteration %d, array is \n",iterno);
    for (i=0; i<len; i++)
    {
        outd[i]=outd[i]+iterno; // "counting up" array contents
        printf("%.2f ",outd[i]);// show
    }
    outI   = outI  + iterno;    // "counting up" file-local integer value
    printf(" outI:%d", outI);   // show

    inI    = inI   + iterno;    // "counting up" the function-local static integer
    printf(" inI:%d", inI);     // show

    locI   = locI  + iterno;    // "single increase" the function-local integer
    printf(" locI:%d", locI);   // show  

    globalI   = globalI  + iterno;    // "single increase" the function-local integer
    printf(" globalI:%d", globalI);    // show

    unknownTwinI   = unknownTwinI  + iterno;    // "single increase" the function-local integer
    printf(" unknownTwinI:%d", unknownTwinI);    // show

    // Note that nothing here frees the buffer
    // or changes the pointer (which would be highly questionable, thinking of the free() later

    printf("\n");


}

void deletearray()
{
    free(outd);
}

      



code1.c:

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

void init0(int len);
void showarray(int len, int iterno);
void deletearray();

// declare the global integer, which is defined in code2.cabs
// (should be in a header.h, 
//  excuse me for taking a shortcut for only having two files to post)
extern int globalI;

// attempt to similarly declare some of the identifiers which cannot be accessed
extern double *outd;
extern    int  outI;
extern    int inI;
extern    int locI;

// define an int which is only visible from this file,
// but has an identically named twin in the other file
// (there be dragons)
static    int unknownTwinI;

int main(int argc,char* argv[])
{
    int i, len;
    len=5;

    // exception of an init outside of init0(),
    // this one targets the twin in THIS file here
    unknownTwinI =0;

    // pointer gets address, buffer gets values
    // integers (those not static to showarray) get values
    init0(len);

    for (i=0; i<7; i++)
    {
        // all kinds of counting gets done
        // (only during the first execution
        //  the local static int initially has the init value)
        showarray(len,i);

        // demonstrating that the global integer is accessable
        globalI = globalI * 2;

        // the showarray outputs the value of the twin in the other file,
        // attempting to resist/undo the cumulative changes done there
        unknownTwinI =0;
        // (resistance is futile)

        // these are forbidden accesses,
        //  with the warnings you get WITHOUT trying to declare them

        // outd=NULL; // 'outd' undeclared (first use in this function)
        // outI=0;    // 'outI' undeclared (first use in this function)
        // inI = 0;   // 'inI' undeclared (first use in this function)
        // locI =0;   // 'locI' undeclared (first use in this function)



        // these are the forbidden accesses again,
        //   with the warnings you get WITH trying to declare them

        // outd=NULL; // undefined reference to `outd'
        // outI=0;    // undefined reference to `outI'
        // inI = 0;   // undefined reference to `inI'
        // locI =0;   // undefined reference to `locI'
    }

    deletearray();

    return 0;
}

      

Output:

iteration 0, array is
0.00 0.00 0.00 0.00 0.00  outI:0 inI:0 locI:0 globalI:5 unknownTwinI:6
iteration 1, array is
1.00 1.00 1.00 1.00 1.00  outI:1 inI:1 locI:1 globalI:11 unknownTwinI:7
iteration 2, array is
3.00 3.00 3.00 3.00 3.00  outI:3 inI:3 locI:2 globalI:24 unknownTwinI:9
iteration 3, array is
6.00 6.00 6.00 6.00 6.00  outI:6 inI:6 locI:3 globalI:51 unknownTwinI:12
iteration 4, array is
10.00 10.00 10.00 10.00 10.00  outI:10 inI:10 locI:4 globalI:106 unknownTwinI:16
iteration 5, array is
15.00 15.00 15.00 15.00 15.00  outI:15 inI:15 locI:5 globalI:217 unknownTwinI:21
iteration 6, array is
21.00 21.00 21.00 21.00 21.00  outI:21 inI:21 locI:6 globalI:440 unknownTwinI:27

      

+1


source


Yunnosch's answer explains the effects of various declarations with an example pretty well, but I want to add some background from the language specification because I think it helps a lot to understand.

  • Identifiers in C are scoped. Scope defines the scope in which this identifier refers to its associated object. In C, the scope of an identifier is the enclosing pair of curly braces ( { ... }

    ).

    if (1) {
        int i = 2;
        // i refers to an object holding the value 2 here
    }
    // i doesn't refer to any object
    
          

    Identifiers outside of any curly braces are file-scoped and refer to an object throughout the entire source file.

  • Objects in C can have different storage durations. The storage duration determines how long the object is alive and can be accessed. You should know the following:

    • automatic: the object lives as long as the execution is inside the scope. This is the default for any variable not in file scope.
    • static: the object lives for the entire runtime of the program. This is the default for content-area ads.
    • dynamic: The object is created by allocation ( malloc()

      and friends) and lives until it is manually removed ( free()

      ).
  • Finally, identifiers can have different relationships. This determines the visibility between different translation units. An identifier with an external link is visible outside of its own translation unit, one with an internal link is not.

    Default relationship for external scope identifiers.


With this theoretical background, let's see what it means static

. static

- storage class and sets storage duration to static and associated with internal.

example1.c:



static int i;
// static storage duration, internal linkage

int foobar(void) {
    static int j = 5;
    // static storage duration, internal linkage
    return ++j;
    // returns one more at each call, starting from 6
}

      

vs example2.c:

int i;
// static storage duration, external linkage

int foobar(void) {
    int j = 5;
    // automatic storage duration, internal linkage
    return ++j;
    // always returns 6, because with automatic storage duration,
    // j refers to a NEW object every time the function is entered
}

      


As for your code in the question: A pointer has static storage duration, so it lives for the entire program. Whatever you malloc()

live up to as long as you don't have free()

it (see above: dynamic storage duration), so you do a great job with this code.

+1


source


The meaning static

in C (and in other languages ​​too) is different when used for functions, global variables, or local variables. this keyword does not indicate whether the variable will be allocated statically or dynamically, if you use pointers you are actually choosing dynamic allocation.

-Using local variables, the static keyword changes the lifespan of that variable; but if you call malloc

on a static pointer it will change its value. Here's an example:

void myfunction(){
static int* p = NULL;

if (p == NULL)
    p = (int*) malloc(sizeof(int) * 4);
else
{
    *(p) = 1;
    printf("address: %d, first element: %d", p, p[0]);
}
}

int main()
{
    myfunction();
    myfunction();

    return 0;
}

      

Only the second myfunction

will print the address and the first element. (I know I didn't name free

)

  • If static

    used with a function or with global variables instead, the value changes completely: in this case, it changes the visibility of that function or global variable. As you saw in the comments, static functions are only visible by other functions in the same translation system (object file). For a global static variable, it's pretty much the same.
0


source







All Articles