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;
}
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;
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With