Dubby
Dubby

Reputation: 1144

Memory allocation using pointer and pointer to pointer

I have a structure called node:

typedef struct node
{
     int x;
     struct node *next;
}node;

I have two functions change1() and change2() that allocate memory to the node. change1() takes pointer to the node and change2() takes pointer to pointer as argument.

void change1(node ** n)
{
    *n = malloc(sizeof(node));
}
void change2(node * n)
{
    n = malloc(sizeof(node));
}

If I call change2(&n) & then try to allocate a value to x (in main after returning from function call to change2) and print it, I get 4 as output but if I call change1(n) & do the same I get a segmentation fault.

void main()
{
    node * n1,*n2 ;

    change1(&n1); // Pretty much OK
    change2(n2);  // Leads to segmentation fault on printing

    n1->x = 4;  
    n2->x = 4;

    printf("%d ",n1->x);
    printf("%d ",n2->x); // gives SEGMENTATION fault

}

Can someone explain what is happening in terms of memory allocation and why the pointer that I'm sending as n2 unable to reflect change after returning to main(). Thanks!

Upvotes: 0

Views: 95

Answers (3)

user3386109
user3386109

Reputation: 34829

In the second function, n is a pointer to a node. Therefore, the second function is only able to modify the members of the node, e.g.

void change2( node *n )
{
     n->x = 4;
     n->next = NULL;
}

However, this assumes that main has provided the memory to store the node. So main would have to do one of the following

int main( void )
{
    node n2;                    // allocate n2 on the stack
    change2( &n2 );             // pass the address of the node to the change2 function
    printf( "%d\n", n2.x );     // use 'dot' notation to access members of struct
}

--- OR ---

int main( void )
{
    node *n2;                   // n2 is a pointer on the stack
    n2 = malloc(sizeof(node));  // allocate memory to store the node data
    change2( n2 );              // pass the pointer, i.e. pass the address of the node to the change2 function
    printf( "%d\n", n2->x );    // use pointer notation, since n2 was declared as a pointer
}

The third alternative, as mentioned by abligh is to allocate memory in the function and return the pointer to main.

node *create2( void )
{
    node *n2;                   // declare the pointer
    n2 = malloc(sizeof(node));  // allocate memory to store the node data
    n2->x = 4;                  // initialize the members of the node
    n2->next = NULL;
    return( n2 );               // return a pointer to the node
}

int main( void )
{
    node *n2;                   // n2 is just a pointer
    n2 = create2();             // allocate memory for and initialize a node
    printf( "%d\n", n2->x );    // use pointer notation, since n2 is as a pointer
}

Upvotes: 0

Thomas Padron-McCarthy
Thomas Padron-McCarthy

Reputation: 27632

For a moment, ignore the fact the n1 and n2 are pointers. Just look at them as any other variables.

C only has "call by value", which means that when you call a function, the values of the arguments are copied, and those copies are sent to the function. If you call a function with a variable as argument, its value is copied and sent. This means that the called function can't change the content of the variable.

With n1 you use the "address-of" operator (&) to get, and then send, a pointer to the variable. The function can use that pointer to change n1.

With n2, you just send the value of the variable, so the function can't change the variable. n2 will keep its old value, which is just whatever garbage happened to be in that memory position.

Later in the program you follow the pointers in n1 and n2 to whatever they point to. Since n2 contains garbage, you get what the C standard calls "undefined behavior", and in this case your program crashed.

Upvotes: 2

abligh
abligh

Reputation: 25129

When you call change2 it overwrites the value of n passed with the return value of malloc, then promptly forgets it. This won't work as the value of n2 in the main() will remain undefined.

If you don't want to use a pointer to a pointer you will have to use some other mechanism to return the value, e.g.

node * change2()
{
   return malloc(sizeof(node));
}

...

n2 = change2();

Upvotes: 1

Related Questions