linked list displays extra zero item - c

I am creating a list with 3 elements but when I print the list , it shows an extra zero element.I can't figure where this comes from.
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
int data;
struct node *next;
} node;
void Push(struct node **head, int data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node));
newNode-> data = data;
newNode-> next = *head;
*head = newNode;
}
void createList(struct node **head)
{
Push(head, 1);
Push(head, 2);
Push(head, 3);
}
void printList(struct node *head)
{
struct node *ptr = head;
while(ptr != NULL)
{
printf("%d \n", ptr-> data);
ptr = ptr-> next;
}
return;
}
int main() {
struct node *head = NULL;
head = (struct node*) malloc(sizeof(struct node));
createList(&head);
printList(head);
printf("\n");
return 0;
}
Output:
3
2
1
0

It's actually displaying an indeterminate value. Because right here:
head = (struct node*) malloc(sizeof(struct node));
Is where you create the first real node, which everything is inserted before. You are (un)lucky the run-time is zeroing out the memory for you. Because that's the only thing stopping you from accessing some random address. In general, the content of the memory returned from malloc is indeterminate.
Remove that line and you'll see only the items added by createList. Plus your program will be with well defined behavior.

You have four nodes in your list: the original that you malloc in "main()” plus the three added via "Push" in "createList". Presumably the data in the extra one is zero because you haven’t set it in main (although I’d expect it to be gibberish since it’s allocated memory but not cleared).

Related

Where is logical error in the given code?

I am trying to add a new node to the linked list. Online tutorials(http://www.geeksforgeeks.org/linked-list-set-2-inserting-a-node/) uses a pointer to a pointer and I am not able to understand how it works. So I decided to write my own code but I am having a problem with the push() function. Here is the code.
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node* next;
};
void print_list(struct node *head_ptr)
{
while(head_ptr!=NULL)
{
printf("%d->",head_ptr->data);
head_ptr = head_ptr->next;
}
}
void push(struct node *head_ptr, int data_val)
{
struct node *new_node = (struct node*)malloc(sizeof(struct node));
new_node -> data = data_val;
new_node->next = head_ptr;
head_ptr = new_node;
}
int main()
{
struct node *head = (struct node*)malloc(sizeof(struct node));
struct node *second = (struct node*)malloc(sizeof(struct node));
struct node *third = (struct node*)malloc(sizeof(struct node));
head -> data = 1;
head -> next = second;
second -> data = 2;
second -> next = third;
third -> data = 3;
third -> next = NULL;
print_list(head);
push(head,0);
printf("\n");
print_list(head);
return 0;
}
It compiles without error. However, the expected node with value 0 does not get inserted in the beginning of my linked list.
Current Output
1->2->3->
Expected Output
0->1->2->3->
Please help me get the required output without using pointer to a pointer in push() function. Also, share a link to a source which has a good explanation of pointer to a pointer and it relates to the linked list.
You are doing it wrong way.
The thing is when you pass head in push a copy of it is passed to push. The content of them are same. Now what you are doing?
Creating new node. Then you make changes to that copy of the variable. Then the function ends and the lifetime of that variable ends and so is the access to the allocated memory (creating memory leak). And the original head in main() still is same. That's why it prints 1-2-3.
Solution-1
head = push(head,0);
And
struct node* push(struct node *head_ptr, int data_val)
{
struct node *new_node = (struct node*)malloc(sizeof(struct node));
new_node -> data = data_val;
new_node->next = head_ptr;
head_ptr = new_node;
return head_ptr;
}
Solution-2
void push(struct node **head_ptr, int data_val)
{
struct node *new_node = (struct node*)malloc(sizeof(struct node));
new_node -> data = data_val;
new_node->next = *head_ptr;
*head_ptr = new_node;
}
And call it like
push(&head,0);
Explanation of solution-2
Now here you pass &head to the function meaning you pass the address of it to the function push(). Now in push() you have a variable named head which is a contains the address of the head. Now by dereferencing it you are basically the head of main()and any changes you make to *head will retain because you are changing to the actual variable, whose address was passed.
Explanation of solution-1
Here we don't pass the address. But rather we pass the content of the head variable of main(). Now you allocate memory and you get it's address. You make changes to it. And then you put in the next the address of the head and then you point head to the newnode. And you may ask so it changes the origibal head? Nope. that's why we return it and we store it in the originbal head in main().
Note:
The dynamically allocated memory is have lifetime beyond the scope of the function. That's why you can return it's address and there will not be any problem.
You don't need to cast the return type of malloc. That's not needed.
struct node *new_node = malloc(sizeof(struct node));
Or
more clearly
struct node *new_node = malloc(sizeof *new_node));
Also check the return value of malloc.
Free the dynamically allocated memory when you are done working with it.
Where is logical error in the given code?
In C function arguments are always "call by value".
A function can change the function arguments but this has no impact on the argument in the calling function. Example:
void x(int a)
{
a = a + 10;
printf("%d\n", a);
}
void y(void)
{
int b = 9;
x(b); /* Line 1 */
x(123); /* Line 2 */
}
The line a = a + 10; will have the effect that 19 and 133 are printed instead of 9 and 123.
However it will not have the effect that b is changed to 19 in "line 1"; for "line 2" it should be clear that such an effect is even impossible.
In your code the line head_ptr = ... has the same effect.
Please help me get the required output ...
As the C language does not provide real "call by reference" arguments you use pointers to variables as "call by value" arguments to simulate "call by reference" arguments:
void x(int *a)
{
(*a) = (*a) + 10;
printf("%d\n", *a);
}
...
x(&b);
Or, in your example:
/* Note the two "**"s in this line: */
void push(struct node **head_ptr, int data_val)
{
...
*head_ptr = new_node; /* Note the "*" */
}
...
push(&head,0);
Of course you can only pass variables to functions this way.
Everything in C is passed by value. Even the pointers
So
I have two pointers
void swap(char* first, char* second)
{
//take temp var and swap
}
main(){
char *first, *second;
first = 0x1;
second = 0x2;
printf("%x, %x", first, second);
swap(first, second);
printf("%x, %x", first, second);
}
this code will not swap the values, since in swap(), the locally created values on stack are being swapped.
Realize that pointers are behaving just like another normal variables there.
Yes but if you dereference them you can swap the values pointed by the pointers inside the swap().
Catch is: head you passed is passed by value, the push() function does its job but assignment to head is done LOCALLY.
***SOLVED***
#include <stdio.h>
#include <stdlib.h>
struct node{
int data;
struct node* next;
};
void print_list(struct node *head_ptr)
{
while(head_ptr!=NULL)
{
printf("%d->",head_ptr->data);
head_ptr = head_ptr->next;
}
}
void push(struct node *head_ptr, int data_val, ***struct node *new_node***)
{
new_node -> data = data_val;
new_node->next = head_ptr;
head_ptr = new_node;
}
int main()
{
struct node *head = (struct node*)malloc(sizeof(struct node));
struct node *second = (struct node*)malloc(sizeof(struct node));
struct node *third = (struct node*)malloc(sizeof(struct node));
***struct node *new_node = (struct node*)malloc(sizeof(struct node));***
head -> data = 1;
head -> next = second;
second -> data = 2;
second -> next = third;
third -> data = 3;
third -> next = NULL;
print_list(head);
push(head,0,new_node);
printf("\n");
print_list(***new_node***);
return 0;
}

Node pointer to current Node during mutile function call

I have declared a global pointer ptr and want that it should point to current node during different function call.
This is a sample code where I am creating a new node in fun1 and inserting in link list. In func2 I want to update the other members of newNode in linklist with a different value.
Currently I am traversing the link list to get the current Node or last Node which I dont want since during insertion of new Records already we have to traverse to reach to last Node thus storing the address of last Node.
But by doing the below I am not getting the proper values. Kindly someone suggest where I went wrong.
I am doing like this :
#include<stdio.h>
#include <stdlib.h>
struct Node
{
int data1;
int data2;
struct Node* next;
};
struct Node* head=NULL;
struct Node* ptr =NULL; /* Global pointer */
void insertNode(struct Node ** , struct Node* );
void fun1();
void fun2();
void fun1()
{
struct Node* ptr1 =NULL;
ptr1 = (struct Node*)malloc(sizeof(struct Node*));
ptr1->data1=1; /* intilaizing with some values */
insertNode(&head,ptr1);
}
void fun2()
{
/* Updating the current Node in the linklist with new value . */
ptr->data2=2;
}
void insertNode(struct Node ** head, struct Node* NewRec)
{
if(*head ==NULL )
{
NewRec->next = *head;
*head = NewRec;
ptr=*head;
}
else
{
/* Locate the node before the point of insertion */
struct Node* current=NULL;
current = *head;
while (current->next!=NULL )
{
current = current->next;
}
NewRec->next = current->next;
current->next = NewRec;
ptr=current->next;
}
}
int main ()
{
fun1();
fun2();
while(head!=NULL)
{
printf("%d", head->data1);
printf("%d",head->data2);
head=head->next;
}
return 0;
}
You made a classic mistake.
This is wrong:
ptr1 = (struct Node*)malloc(sizeof(struct Node*));
The allocated space here is sizeof(struct Node*) which is the size of a pointer (usually 4 or 8 bytes depending on the platform). But you need to allocate space for the whole struct Node structure, whose size is sizeof(struct Node).
So you simply need this:
ptr1 = (struct Node*)malloc(sizeof(struct Node));
BTW: in C you don't cast the return value of malloc so you actually should write this:
ptr1 = malloc(sizeof(struct Node));

Trouble in insertion of string in linked list

I am writing a program to insert data to linked list and print it.
LinkedList.c
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
struct node
{
char *data;
struct node *next;
};
void insert(struct node** head_ref,char *new_data)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
struct node *last = *head_ref;
strcpy(new_node->data,new_data);
new_node->next = NULL;
if (*head_ref == NULL)
{
*head_ref = new_node;//assigning head node
return;
}
while (last->next != NULL)
last = last->next;//this helps to traverse to last node
last->next = new_node;
return;
}
void printList(struct node *node)//function to print the linked list
{
while (node != NULL)
{
printf(" %s ", node->data);
node = node->next;
}
}
int main() {
int t;
char datas[1000];
scanf("%d",&t);
struct node* head=NULL;
int i;
for(i=0;i<t;i++)
{
scanf("%s",datas);//this data should be added into the linkedlist
insert(&head,datas);
}
printList(head);
return 0;
}
This program works well for integer but if i use character string instead it showing that there is no response on stdout
I have been trying to debug the code for more hours.
Your code gives undefined behavior.
Have a look at the documentation of strcpy().
Long story short, strcpy() requires the destination (your new_node->data) to be an allocated char array, but you have not allocated the data for it, and you are writing to an undefined (and unallocated) memory.
To overcome it, either allocate space dynamically for the new string (and don't forget to free it when a node is released), or make data a char[] instead of a char*.
In addition, just remember buffer overflow weakness. Since it seems like educational purpose code, just think about it - don't try to solve it, IMO.
You have missed memory allocation, try this:
void insert(struct node** head_ref,char *new_data)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
struct node *last = *head_ref;
// you should allocate memory because you use data as char *
new_node->data = malloc(strlen(new_data)+1);
/* you can use new_node->data = strdup(new_data);
instead of new_node->data = malloc(strlen(new_data)); and strcpy(new_node->data,new_data);
because strdup allocate and copy string with exact size */
strcpy(new_node->data,new_data);
new_node->next = NULL;
if (*head_ref == NULL)
{
*head_ref = new_node;//assigning head node
return;
}
while (last->next != NULL)
last = last->next;//this helps to traverse to last node
last->next = new_node;
return;
}

Passing a linked list head through a function as address in C

I have a question regarding passing the head of a linked list in C through a function. So the code goes something like this:
#include <stdio.h>
//Defining a structure of the node
struct node {
int data;
struct node* next;
};
void insert (struct node* rec, int x) {
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = NULL;
rec = temp; // head and rec is now pointing to the same node
}
void print(struct node* rec){
printf("%d", rec->data); //error occurs here
puts("");
}
main(){
struct node *head = NULL; //head is currently pointing to NULL
insert (head, 5); //Passing the head pointer and integer 5 to insert()
print(head);
}
So as you see, the error occurs when I tried printing rec->data. Why did the error occur? I thought since the pointer rec and head are all pointing to the same node in the heap, there should not be any problem?
Thank you.
You could pass a struct node** as suggested by #sje397.
However, I would suggest the following design (which, in my opinion is easier to reason about too):
/* returns the new head of the list */
struct node *insert (struct node* current_head, int x) {
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = current_head;
return temp;
}
and use it like
head = insert(head, 5);
In this case I would also rename the function something like push_front.
Just for completeness, I think #sje397 meant something like the following (Typical linked list code rewritten again and again by every C programmer...):
void insert(struct node **head, int x) {
struct node* new_head = (struct node*)malloc(sizeof(struct node));
new_head->data = x;
new_head->next = *head;
*head = new_head;
}
In C there is no pass by reference.
Your insert function isn't inserting a node in the list, its just changing the node which the head points to. Because of temp->next = NULL the list will always contain two nodes.
Another error is that you're just modifying a local copy of the head node.
To fix this You have 3 choices:
-You can make the head node global
-You can pass a pointer to the head node(pointer to pointer) to the function.
-You can return the modified head node by the function.
Redefine the insert function to:
void insert (struct node** rec, int x) {
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = NULL;
*rec = temp; // head and rec is now pointing to the same node
}

Append an element at the end of a linked-List in C programming

I've been studying linked lists in C and regarding the append function, I came across the following code:
struct node
{
int data;
struct node *next;
}*head;
void append(int num)
{
struct node *temp,*right;
temp= (struct node *)malloc(sizeof(struct node));
temp->data=num;
right=(struct node *)head;
while(right->next != NULL){
right=right->next;
}
right->next =temp;
right=temp;
right->next=NULL;
}
In order to save a line of code, wouldn't it be possible to just add NULL to the temp's next atribute? like so:
void append(int num)
{
struct node *temp,*right;
temp= (struct node *)malloc(sizeof(struct node));
temp->data=num;
temp -> next = NULL;
right=(struct node *)head;
while(right->next != NULL){
right=right->next;
}
right->next =temp;
}
Yes you are correct. In-fact I will further reduce the length of code by writing separate function that allocate and intialize data as follows:
struct node * getnode(int date){
struct node *temp = malloc(sizeof(struct node));
temp->data = data;
temp->next = NULL;
return temp;
}
// assuming list have more than one elements: demo code
void append(struct node *head, int num){
struct node *right = head;
while(right->next != NULL){
right=right->next;
}
right->next = getnode(num);
}
This get node function can be useful in other part of code e.g insertatfist(), insert()
Btw: Don't cast the returned address of malloc() and calloc().
May be you like to write struct node* getnode(int data, struct node* next) function that also set next node address.
call it as:
To insert last node:
curt->next = getnode(num, NULL);
To insert between curt node and curt->next.
curt->next = getnode(num, curt->next);
It certainly is possible to do it that way in this way, However, I see that the code in the first approach is more readable(very small more) to my eyes. However you aren't going to save much.
But don't try to do these kind of optimizations for all programs, give readability more importance than saving a few lines of code. Reason is that compiler is anyways going to do the optimization.
If you want to "save lines", you could also use calloc, instead of malloc, which zeros your bytes,
but that would be LESS clear.
It does save you a line of code, and it is arguable clearer.
I think your proposed code change is an improvement in that it separates creation of the new node from placing it.
If this is production code I would probably let sleeping dogs lie. But while we are all chiming in here is how I would implement the same function.
struct node
{
int data;
struct node *next;
};
struct node* init_node(int num)
{
struct node * temp = malloc(sizeof(struct node));
temp->data = num;
return temp;
}
void append(struct node* n, struct node* list)
{
while(list->next != NULL){
list=list->next;
}
list->next =n;
n->next=NULL;
}

Resources