user9848591
user9848591

Reputation:

C structure and malloc function

I am new to programming.The other day I was playing around with structures and pointers...I was getting errors.I tried to rectify them.It got rectified...But I cant justify why there was an error at the first place.Please help me...

struct node{
   int data;
   struct node*next;    
};  

int main(){
   struct node *newnode=NULL;
   struct node *start=NULL;
   newnode=start=(struct node*)malloc(sizeof(struct node));
   newnode->data=1;

   //code snippet 
   newnode->next=NULL;
   newnode=newnode->next;
   newnode=(struct node*)malloc(sizeof(struct node));
   newnode->data=2;
   start=start->next;//error probably as start->next is perceived as NULL Address
   printf("%d",start->data);
   return 0;    
}

when replacing code snippet with this code

newnode->next=(struct node*)malloc(sizeof(struct node));
newnode=newnode->next;
newnode->data=2;
start=start->next;
printf("%d",start->data);

error dissapers..How does one justify this ?

Upvotes: 2

Views: 229

Answers (5)

samuelnj
samuelnj

Reputation: 1637

You are correct that the error comes from printf("%d",start->data); where you are trying to dereference a pointer to NULL.

Let me explain it graphically: with the firs 4 lines you get this:

             _____________
newnode ->  | data = 1    |
start   ->  | next = null |
            |_____________|

This line newnode->next=NULL; does nothing. Then, newnode=newnode->next; does this:

             _____________
            | data = 1    |
start   ->  | next = null |      newnode -> NULL
            |_____________|

Then,

 newnode=(struct node*)malloc(sizeof(struct node));
 newnode->data=2;`

does this:

             _____________                    _____________
            | data = 1    |                  | data = 2    |
start   ->  | next = null |      newnode ->  | next = null | 
            |_____________|                  |_____________|

Finally, start=start->next; sets the state like this, and clearly you try to access a field of a pointer to NULL as a result.

                                              _____________
                                             | data = 2    |
start   ->  null                 newnode ->  | next = null | 
                                             |_____________|

Upvotes: 0

Stephan Lechner
Stephan Lechner

Reputation: 35164

Let me comment what the first version does:

newnode=start=(struct node*)malloc(sizeof(struct node));
...
// at this point, newnode and start point to the same node

newnode->next=NULL; 
// since start points to the same node as newnode, this means that also 
// start->next will be NULL 
...
start=start->next; // since start->next is null, start will be null after this statement

printf("%d",start->data);  // start is null, so start->null dereferences NULL (undefined behaviour, e.g. a crash or something dubious)

Your second version is different, because...

newnode->next=(struct node*)malloc(sizeof(struct node));
// this lets newnode->next point to a valid (new) node
// since start==newnode, also start->next will point to this valid (new) node

start=start->next;  // afterwards, start will point to the valid (new) node
printf("%d",start->data); // OK; should print 2 then. 

I think you might confuse an assignment expression with "defining an alias":

newnode=newnode->next;
newnode=(struct node*)malloc(sizeof(struct node)); 

is very different from

newnode->next = (struct node*)malloc(sizeof(struct node));

because

newnode = newnode->next 

is not defining a macro or a replacement text for newnode such that text newnode is replaced with text newnode->next henceforth. It's rather that the variable newnode will get a new value, i.e. the value that member next of this node points to.

Upvotes: 0

John Bollinger
John Bollinger

Reputation: 181849

In the first of your two codes, you have

newnode=newnode->next;
newnode=(struct node*)malloc(sizeof(struct node));

. The first of those assignments is useless: whatever value is thereby assigned to newnode is in the next line replaced by a different one. Moreover, nothing is assigned to the next member of the structure to which newnode initially pointed. The first assignment to newnode does not somehow bind it to that next pointer, as an alias for the pointer itself. It just makes newnode point to the same thing.

In the second code, you instead have:

newnode->next=(struct node*)malloc(sizeof(struct node));
newnode=newnode->next;

That makes a lot more sense. You first allocate memory and assign newnode->next to point to it, then you update newnode to point to the new memory, too. Furthermore, up to that point you still have start pointing to the first dynamically-allocated block, so you can still access that, and since newnode and start initially pointed to the same structure, the same value can afterward be obtained via the expression start->next, too.

Upvotes: 0

Barmar
Barmar

Reputation: 782693

In the first code, newnode and start both start off pointing to the same node that you allocated. You then set newnode->next = NULL;, so that also sets start->next to NULL.

You then do:

newnode = newnode->next;
newnode = (struct node*)malloc(sizeof(struct node));

so newnode now points to a different node, but start still points to the original node. So start->next is still NULL. Then you do:

start = start->next;

This sets start to NULL, so trying to print start->data is invalid because you can't dereference a null pointer.

The first assignment before malloc() is pointless, because you're immediately replacing the variable with something else. I'm guessing you thought that by first reassigning newnode, the malloc() call would update both newnode and newnode->next because you've declared them to be equivalent. But that's not how assignments work -- all it does is copy the value of newnode->next into newnode, it doesn't link those two places together.

Your second version gets this right by assigning to newnode->next rather to newnode. This also assigns to start->next because newnode and start initially point to the same structure. Then you assign

newnode = newnode->next;

This updates newnode, but start is still OK and points to the first node. When you then do

start = start->next;

it updates start to point to the second node as well. In this case, start->data is valid, it contains the same thing that you assigned to newnode->data a few lines earlier.

Upvotes: 1

David Ranieri
David Ranieri

Reputation: 41055

You are overwritting the address of newnode here

newnode = newnode->next;

You probably want:

start = malloc(sizeof(struct node));
start->data = 1;

newnode = malloc(sizeof(struct node));
newnode->data = 2;
newnode->next = NULL;

start->next = newnode;

printf("%d", start->data);

Upvotes: 2

Related Questions