Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesnt the following programm prints the list?

I am currently learnig single lined lists and i am trying to write the basic functions and I tried to print my list after i initialized few elements but my programm has a logical bag because i am not gettin compile errors but instead it return only a non zero value.I dont know where the bug/bus is .Probably it has something to do with the print function but i am not sure

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

  typedef struct person{
       int age;
       struct person*next_generation;
  }person;

  struct person*head=NULL;


  void insert_start(int tage){

    struct person*next_gen=(person*) malloc(sizeof(person));
    next_gen->age=tage;
    next_gen->next_generation=head;
    head=next_gen;
  }

 void insert_end(int x){
     person*next_gen=(person*) malloc(sizeof(person));
     next_gen->age=x;
     next_gen->next_generation=NULL;

     if(head==NULL)
         head=next_gen;
     else{
           struct person*find=head;

           while(find!=NULL){
             find=find->next_generation;
           }
           find->next_generation=next_gen;
    }
}

void insert_whenever(int x,person*p,int position){

   person*next_gen=(person*)malloc(sizeof(person));
   next_gen->age=x;
   next_gen->next_generation=NULL;
   int i=1;
   while(i<position){
        p=p->next_generation;
        i++;
   }
   next_gen->next_generation=p;
   p->next_generation=next_gen;

}


void print_list(person *p){
    printf("[");
    while(p!=NULL){
        printf("%d",p->age);
        p=p->next_generation;
    }
    printf("]");
}



int main(){
    insert_start(75);
    insert_end(45);
    insert_end(12);
    insert_whenever(32,head,3);
    print_list(head);

    return 0;
   }
like image 885
JOHN BOURAS Avatar asked Oct 21 '25 10:10

JOHN BOURAS


2 Answers

The following code in the function insert_end has a bug:

while(find!=NULL){
    find=find->next_generation;
}
find->next_generation=next_gen;

After the while loop has completed, find will have the value NULL. In the first line after the loop, you dereference find. Dereferencing a NULL pointer is not allowed and will invoke undefined behavior.

In order to solve this problem, you can either introduce a second variable which remembers the previous value of find, or better, you can rewrite the function to use a pointer to a pointer:

void insert_end( int age )
{
     person **pp_next = &head;
     person *new_node = malloc( sizeof *new_node );

     new_node->age = age;
     new_node->next_generation = NULL;

     while ( *pp_next != NULL )
     {
         pp_next = &(*pp_next)->next_generation;
     }

     // The pointer "pp_next" now points to the pointer
     // where the address of the new node should be written,
     // in order to link it with the linked list. This will
     // be the address of the "next_generation" pointer of
     // the last node, or if there are no nodes, it will be
     // the address of "head".

     // link new node to the linked list
     *pp_next = new_node;
}

Also, your function insert_whenever has a bug, too. The lines

next_gen->next_generation=p;
p->next_generation=next_gen;

will create a cycle in the linked list, because the new node next_gen will point to the node p, and the node p will point to the new node next_gen.

In order to fix this, you should change the line

next_gen->next_generation=p;

to:

next_gen->next_generation = p->next_generation;
like image 181
Andreas Wenzel Avatar answered Oct 24 '25 02:10

Andreas Wenzel


  • insert_end is broken because while(find!=NULL) will go on until find == NULL and then you dereference find with undefined behavior as a result.
  • insert_whenever is broken because it breaks the linked list at the insertion point and creates a loop in the list.

I also suggest not having head as a global variable since you then can only have one linked list. Send in a person** to the functions (like &head) and let the functions modify the list to which head is the pointer to the first element.

Instead of insert_start, you could make it insert_at to insert a node anywhere in the list. By sending in &head to this function, it would be the same as inserting at the start:

void insert_at(person **p, int age) {
    person *next_gen = malloc(sizeof *next_gen);
    *next_gen = (person) {age, *p};
    *p = next_gen;
}

Then instead of insert_whenever, you could create a support function, get_pos which returns a pointer the the next_generation pointer at a certain position:

// use pos >= 0 to find the next_generation pointer at that position
// use pos < 0 to find the last next_generation pointer
person **get_pos(person **head, int pos) {
    // make head point at the next_generation pointer at position pos
    // or at the last next_generation pointer in case we find the last
    // node 
    while(*head && pos--) head = &(*head)->next_generation;
    return head;
}

With those functions, if you still want insert_start and insert_end, they just become special cases of using insert_at:

void insert_start(person **head, int age) {
    insert_at(head, age);
}

void insert_end(person **head, int age) {
    insert_at(get_pos(head, -1), age);
}

Demo

like image 43
Ted Lyngmo Avatar answered Oct 24 '25 02:10

Ted Lyngmo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!