simplify linked list pointer loop - c

was trying to scan numbers from a file and store them as linked list, however the temporary pointer (ptr) used to link nodes runs through a while loop each time a value is scanned and stored. Is there a way to simplify this without using a while loop? My approach doesn't seem to work.
original code:
struct node
{
int data;
struct node *link;
} *head = NULL, *ptr = NULL, *temp = NULL;
int main()
{
-----
-----
for (i = 0; i < n ; ++i)
{
temp = malloc(sizeof(struct node));
fscanf(fptr, "%d", &(temp->data));
temp->link = NULL;
if (head == NULL)
head = temp;
else
{
ptr = head;
while (ptr->link != NULL)
ptr = ptr->link;
ptr->link = temp;
}
}
-----
}
my approach:
struct node
{
int data;
struct node *link;
} *head = NULL, *ptr = NULL, *temp = NULL;
int main()
{
-----
-----
for (i = 0; i < n ; ++i)
{
temp = malloc(sizeof(struct node));
fscanf(fptr, "%d", &(temp->data));
temp->link = NULL;
if (head == NULL)
{
head = temp;
ptr = head;
}
else
{
ptr->link = temp;
ptr->link = ptr->link->link;
}
}
-----
}

In this code snippet
else
{
ptr->link = temp;
ptr->link = ptr->link->link;
}
ptr->link is set to NULL because in fact it is set to temp->link that is equal to NULL due to this assignment
temp->link = NULL;
What you need is to write
else
{
ptr->link = temp;
ptr = temp;
}
Actually you are trying to implement a two-sided sinngly-linked list where the pointer ptr plays the role of the tail pointer..

Related

Circular linked list crashes when displayed

I'm trying to make a circular linked list. When I try to display the list after creating it, the program keeps on crashing. Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node * next;
} node;
node * createList(int);
void display(node * head);
int main() {
struct node * head;
head = createList(5);
display(head);
}
node * createList(int n) {
int i = 0,data = 0;
struct node * head = NULL;
struct node * temp = NULL;
struct node * p = NULL;
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
temp->next = head;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = temp;
}
}
return head;
}
void display(node * head) {
struct node * temp = head->next;
while (temp != head) {
printf("%d-> \t",temp->data);
temp = temp->next;
}
printf("\n");
}
What am I doing wrong?
You have set every temp's next to head in temp->next = head; but did it too early (the first is just NULL). Then you tested p->next against NULL in while (p->next != NULL) { but you should have tested against head. Alternatively, you can continue to test against NULL but then you need to initialize temp->next to NULL and assign head to temp->next only after the for loop.
Your display code started from the second link.
Here is a fixed code using the first option in 1. above:
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != head) {
p = p->next;
}
p->next = temp;
}
temp->next = head;
}
Here is a fixed code using the alternative option in 1. above. You still need to initialize temp->next to NULL since malloc() does not initialize.
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
temp->next = NULL;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = temp;
}
}
if (temp != NULL) {
temp->next = head;
}
But in reality, there is no need to "walk" from the head on every creation. You can simply keep the previous and link it to the next:
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
if (head == NULL) {
head = p = temp;
} else {
p = p->next = temp;
}
}
if (temp != NULL) {
temp->next = head;
}
Here is a fix for the display():
void display(node * head) {
struct node * temp = head;
if (temp != NULL) {
do {
printf("%d-> \t",temp->data);
temp = temp->next;
} while (temp != head);
}
printf("\n");
}
The problem is on the first node you initialize:
struct node *head = NULL;
...
for (i = 0; i < n; i++) {
...
temp->next = head;
So tmp->next == NULL on the first iteration leaving head->next == NULL. That will not work for a circular list. When you attempt to insert the 2nd node:
p = head;
while (p->next != NULL) {
What was head->next again?? (oh, NULL) Dereferencing a NULL pointer (BOOM Segfault!)
Do your circular list correctly. On insertion of the first node set:
if (head == NULL) {
head = temp;
head->next = temp; /* you must set head->next to temp */
} ...
So on the insertion of the remaining nodes you simply need:
} else {
p = head;
while (p->next != head) { /* iterate to last node */
p = p->next;
}
p->next = temp; /* now set p->next = temp */
}
Now, you handle your display() function the same way, e.g.
void display (node *head)
{
if (!head) { /* validate list not empty */
puts ("(list-empty)");
return;
}
struct node *temp = head;
do { /* same loop problem fixed in display() */
printf ("%d-> \t", temp->data);
temp = temp->next;
} while (temp != head);
putchar ('\n');
}
If you make the changes, then you can test your list with:
int main (void) {
struct node *head, *tmp;
head = createList(5);
display (head);
puts ("\niterate from mid-list");
tmp = head;
tmp = tmp->next;
tmp = tmp->next;
display (tmp);
}
Example Use/Output
$ ./bin/lls_circular_fix
0-> 1-> 2-> 3-> 4->
iterate from mid-list
2-> 3-> 4-> 0-> 1->
Lastly, you are not multiplying the type node by head in struct node * head = NULL; Write it as struct node *head = NULL; (the same for all your function declarations as well) Much more readable.
When you go to delete a note from the list, you must create a special case for both head and tail (the last node). In this sense, the singly-linked list takes a bit more effort than a doubly-linked list due to not having a prev node pointer to track the prior node.
Look things over and let me know if you have questions.
A full example would be:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node;
node *createList (int);
void display (node *head);
int main (void) {
struct node *head, *tmp;
head = createList(5);
display (head);
puts ("\niterate from mid-list");
tmp = head;
tmp = tmp->next;
tmp = tmp->next;
display (tmp);
}
node *createList (int n)
{
int i = 0,data = 0;
struct node *head = NULL;
struct node *temp = NULL;
struct node *p = NULL;
for (i = 0; i < n; i++) {
if (!(temp = malloc (sizeof *temp))) {
perror ("malloc-temp");
return NULL;
}
temp->data = data++;
temp->next = head; /* head is NULL on 1st node insertion */
if (head == NULL) {
head = temp;
head->next = temp; /* you must set head->next to temp */
} else {
p = head;
while (p->next != head) { /* iterate to last node */
p = p->next;
}
p->next = temp; /* now set p->next = temp */
}
}
return head;
}
void display (node *head)
{
if (!head) { /* validate list not empty */
puts ("(list-empty)");
return;
}
struct node *temp = head;
do { /* same loop problem fixed in display() */
printf ("%d-> \t", temp->data);
temp = temp->next;
} while (temp != head);
putchar ('\n');
}

linked list program is not functioning properly

The given program is not showing all the elements of the linked list.
I am having problem in identifying the error.
At first I initialized the head with a null value then made a temporary variable and assigned it an integer value and pointer to the next node.
Then I made an another node named temp1 and linked it with the head.
It will only be linked when "i" will be equal to 1.
Then equated temp1 to the next node and did the same.
//Linked list
//Inserting the nodes.
#include <stdio.h>
struct node
{
int n;
struct node *next;
};
struct node *head;
int main ()
{
int i, s, x, y;
i = 0;
struct node *temp;
struct node *temp1;
struct node *cur;
head = NULL;
scanf ("%d", &s); //No. of nodes.
while (i < s)
{
scanf ("%d", &x);
if (head == NULL)
{
temp = (struct node *) malloc (sizeof (struct node));
temp->n = x;
temp->next = NULL;
head = temp;
}
else
{
temp = (struct node *) malloc (sizeof (struct node));
temp->n = x;
temp->next = NULL;
temp1 = temp;
if (i == 1)
{
head->next = temp1;
}
temp1 = temp1->next; //Assigning the next node.i.e. NULL value
}
i = i + 1;
}
cur = head;
while (cur != NULL)
{
printf ("%d", cur->n);
cur = cur->next;
}
return 0;
}
Check the following changed section
{
temp = (struct node *) malloc (sizeof (struct node));
temp->n = x;
temp->next = NULL;
head = temp;
temp1 = head;
}
else
{
temp = (struct node *) malloc (sizeof (struct node));
temp->n = x;
temp->next = NULL;
temp1->next = temp;
temp1 = temp1->next; //Assigning the next node.i.e. NULL value
}
Instead of relying on
if (i == 1) {
head->next = temp1;
}
I assign head on temp1 while creating the head, which is meant to be happen only first time.
There were also some linkage issues in your else portion.
You lose nodes beyond the first two, since you never link them to the list. Use meaningful names for variables: rename temp1 to tail and initialize it to NULL in the beginning. Then the loop body becomes:
if (scanf(" %d", &x) != 1) {
// FIXME: handle error
}
temp = malloc(sizeof(*temp));
temp->n = x;
temp->next = NULL;
if (tail == NULL) {
head = temp;
} else {
tail->next = temp;
}
tail = temp;
++i;
(Untested.)
Rationale: You want to add new nodes to the end (tail) of the list. The easiest way is to keep track of the tail in an appropriately-named variable, and simply link every node to tail->next instead of convoluted logic like checking for the node count, etc. The only special case is the empty list, i.e., both head and tail are NULL, and the difference is just one line, so don't duplicate the whole block of code to set up the new node.
For starters you have to include the header <stdlib.h>.
The problem is in this statement
temp1 = temp;
if i is not equal to 1 then after this statement
temp1 = temp1->next;
temp1 becomes equal to NULL.
So all other nodes are not added to the list because there is a cycling
temp1 = temp;
//...
temp1 = temp1->next;
Change the loop the following way
while (i < s)
{
scanf ("%d", &x);
if (head == NULL)
{
temp = (struct node *) malloc (sizeof (struct node));
temp->n = x;
temp->next = NULL;
head = temp;
temp1 = head;
}
else
{
temp = (struct node *) malloc (sizeof (struct node));
temp->n = x;
temp->next = NULL;
temp1->next = temp;
temp1 = temp;
}
i++;
}
Pay attention to that you should declare variables in a block scope where they are used. Otherwise the program will be unreadable.
The approach you are using can be called as an Java approach.
In C the program can look much simpler. For example
#include <stdio.h>
#include <stdlib.h>
struct node
{
int n;
struct node *next;
};
struct node *head;
int main( void )
{
struct node **temp = &head;
size_t n = 0;
scanf( "%zu", &n );
for ( size_t i = 0; i < n; i++ )
{
*temp = (struct node *) malloc ( sizeof ( struct node ) );
int value = 0;
scanf ( "%d", &value);
( *temp )->n = value;
( *temp )->next = NULL;
temp = &( *temp )->next;
}
for ( struct node *cur = head; cur != NULL; cur = cur->next )
{
printf ("%d -> ", cur->n );
}
puts( "NULL" );
return 0;
}
Its output might look like
1 -> 2 -> 3 -> NULL

C - Popping last item from linked lists

I am learning linked lists and they are causing me a lot of troubles.
I am calling the function with this call:
pop(&list);
ANd here's the code:
void pop(NODE** first) {
if(*first != NULL && first!= NULL){
NODE* ptr = *first;
while(ptr->next->next != NULL){
ptr = ptr->next;
}
free(ptr->next);
ptr->next = NULL;
}
It's also causing memory leak error even if I call it single time..
When calling this function multiple times, there are more memory leak errors.
Thanks in advance, Mimpopo.
EDIT: Definition of NODE
typedef struct node {
int data;
struct node *next;
} NODE;
The full CODE:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} NODE;
NODE* insert(NODE *first, int n){
// create new node
NODE* new = (NODE*)malloc(sizeof(NODE));
new->data = n;
new->next = NULL;
// if first is NULL, this will be the first
if(first == NULL)
return new;
// otherwise, place it correctly
NODE* ptr = first;
// check inserting at the begining
if(ptr->data > new->data){
new->next = ptr;
return new;
}
// insert in the middle
while(ptr->next != NULL){
if(ptr->next->data > n && ptr->data < n){
new->next = ptr->next;
ptr->next = new;
break;
}
ptr = ptr->next;
}
// insert at the end of list
if(ptr->next == NULL){
ptr->next = new;
}
return first;
}
void traverse(NODE *first){
NODE* ptr = first;
while(ptr != NULL){
printf("%d\n", ptr->data);
ptr = ptr->next;
}
}
NODE* search(NODE *first, int n){
NODE* ptr = first;
while(ptr != NULL){
if(ptr->data == n){
printf("FOUND %d\n!", n);
return ptr;
}
ptr = ptr->next;
}
}
int main(){
NODE* first = NULL;
NODE* this = NULL;
first = insert(first, 7);
first = insert(first, 10);
first = insert(first, 11);
first = insert(first, 1);
first = insert(first, 3);
first = insert(first, 5);
first = insert(first, 22);
first = insert(first, 23);
first = insert(first, 24);
first = insert(first, 125);
pop(&first);
}
I have not looked through all your code but as for the function then it can be written the following way
void pop( NODE ** first )
{
if ( *first != NULL )
{
NODE *prev = NULL;
NODE *current = *first;
while ( current->next )
{
prev = current;
current = current->next;
}
if ( prev != NULL ) prev->next = current->next;
else ( *first = NULL );
free( current );
}
}
As for your function implementation then it contains many errors. For example in this statement
if(*first != NULL && first!= NULL){
you shall swap the first and the second comparisons. That is the condition shall look like
if(first != NULL && *first!= NULL){
In this statement
while(ptr->next->next != NULL){
You have to be sure that ptr->nextis not equal to NULL.
Also you do not check whether the deleted node is the first node of the list.
Take into account that function insert is also wrong. You consider only one condition in this code snippet
while(ptr->next != NULL){
if(ptr->next->data > n && ptr->data < n){
new->next = ptr->next;
ptr->next = new;
break;
}
ptr = ptr->next;
}
However it can be that for example
ptr->next->data >= n && ptr->data < n
or
ptr->next->data > n && ptr->data <= n

Inserting in Binary Search Tree (C) using for loop

I'm having trouble inserting in a Binary Search Tree using for loop, when I call the InorderTraversal function, there is no output all I get is a blank line, as far as I think rest of the code is okay the only problem is in the insert function.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct BinaryTree{
int data;
struct BinaryTree *left;
struct BinaryTree *right;
} node;
node* Insert(node* head, int value)
{
_Bool flag = true;
for(node *temp = head; flag == true; (temp = (value >= temp->data)?(temp->right):(temp->left)))
{
if(temp == NULL)
{
temp = (node*)malloc(sizeof(node*));
temp->data = value;
temp->left = NULL;
temp->right = NULL;
flag = false;
}
}
return head;
}
void InorderTraversal(node* head)
{
if(head == NULL)
{
return;
}
InorderTraversal(head->left);
printf("%d ",head->data);
InorderTraversal(head->right);
}
int main(void)
{
node *head = NULL;
for(int i = 0; i < 40; i++)
{
head = Insert(head,i);
}
InorderTraversal(head);
return 0;
}
Here try these changes in your Insert function
node* Insert(node *head, int value)
{
if(!head) //Explicitly insert into head if it is NULL
{
head = malloc(sizeof *head);
head->data = value;
head->left = NULL;
head->right = NULL;
return head;
}
for(node *temp = head,*temp2 = head; ;(temp = (value >= temp->data)?(temp->right):(temp->left)))
{
if(temp == NULL)
{
temp = malloc(sizeof *temp);
temp->data = value;
temp->left = NULL;
temp->right = NULL;
if(value >= temp2->data) //update previous nodes left or right pointer accordingly
temp2->right = temp;
else
temp2->left = temp;
break;
}
temp2 = temp; //Use a another pointer to store previous value of node
}
return head;
}
Call me crazy, but shouldn't that malloc(sizeof(node*)) be malloc(sizeof node)?
I am not that so informed, other than being able to read C, so excuse me if this is simply wrong...
Edit: ... or malloc(sizeof * temp)
When you insert the first node you dereference an uninitialized pointer here:
temp->data
Where temp is head and head in uninitialized and pointing to NULL.
So you first have to make special case when head is NULL:
if( !head )
{
head = malloc(sizeof(node));
head->data = value;
head->left = NULL;
head->right = NULL;
return head ;
}
When you continue adding elements you don't update the pointer of the last node. Your for loop should have an extra pointer to the previous node and when you get to the last node and find NULL update the previous nodes left or right pointer.
if(temp == NULL) //wrong, should be: not equal
{
temp = (node*)malloc(sizeof(node*)); //wrong, should be: sizeof the node not the pointer
temp->data = value;
temp->left = NULL;
temp->right = NULL;
flag = false; //use break instead
}
here the previous node pointer left or right is not updated and when you search you can't find any node.

why is this print linked list function not working?

I have a function as following
void printLinkedList(struct node *head) {
printf("%d-->", head->data);
while(head->ptr != NULL) {
head = head->ptr;
printf("%d-->", head->data);
}
printf("NULL\n");
}
I would like to print the content of a linked list constructed in the following way:
for (int i = 0; i < 10; i++) {
head->data = i+1;
head->ptr = malloc(sizeof(struct node));
head = head->ptr;
}
So ideally this should give me something like:
1-->2-->3-->4-->...-->10-->NULL
If everything is correct, however, valgrind is giving me memory errors. Please tell me what I am doing wrong.
check this.
struct node *temp, *head= NULL, *last = NULL;
for (int i = 0; i < 10; i++) {
temp = malloc(sizeof(struct node));
temp->data = i+1;
temp->ptr = NULL;
if (head == NULL)
head = temp;
if (last != NULL)
last->ptr = temp;
last = temp;
}
printLinkedList(head);
I revised Toms's answer a little:
struct node *head = NULL, **temp = &head;
for (int i = 0; i < 10; i++) {
*temp = malloc(sizeof(struct node));
(*temp)->data = i+1;
(*temp)->ptr = NULL;
temp = &(*temp)->ptr;
}
printLinkedList(head);
The orignal code produces a seg fault because temp is not malloced properly.
If you call print function without constructing the Linked list, it will show error, so change the print function as follows:
void printLinkedList(struct node *head)
{
while(head != NULL)
{
printf("%d-->", head->data);
head = head->ptr;
}
printf("NULL\n");
}
here is the revised code - your construction was faulty.
typedef struct _node {
int data;
struct _node *ptr;
} NODE, *PNODE;
PNODE head;
int main (int argc, char * argv[])
{
head = (PNODE) malloc(sizeof(NODE));
PNODE node = head;
int i = 0;
node->data = ++i;
node->ptr = NULL;
for ( ;i < 10; ) {
PNODE tmp = (PNODE) malloc(sizeof(NODE));
tmp->data = ++i;
tmp->ptr = NULL;
node->ptr = tmp;
node =tmp;
}
printLinkedList(head);
freeLinkedList(head);
return 0;
}

Resources