Search code examples
cpointersmallocsingly-linked-list

Why am i not able to initialize the linkedlist?


I was trying to make a single linkedlist but the head pointer keeps pointing at null hence there is not output after taking the size and the elements of the linkedlist. Also when i take the head as an pointer inside of Main function it gives me segmentation fault when i try to call push and display function.

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

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


void push(node *head,int value){
    node * newnode= (node*)malloc(sizeof(node));
    newnode->data = value;
    newnode->next = NULL;
    printf("%d",value);
    if(head==NULL){
        head = newnode;
        return;

    }
    node* iter = head;
    while(iter->next!=NULL){
        iter = iter->next;
    }
    iter->next = newnode;
}

void display(node *head){
    node *iter = head;
    while(iter!=NULL){
        printf("%d->",iter->data);
        iter = iter->next;
    }
    return;
}

int main(){
    node *head = NULL;
    int size;
    scanf("%d",&size);
    for(int i=0;i<size;i++){
        int value;
        scanf("%d",&value);
        push(head,value);
    }
    display(head);
}

Solution

  • The function push deals with a copy of the value of the pointer head defined in main. Changing the copy within the function leaves the original pointer unchanged. That is the function parameter head that is a local variable of the function is initialized by the value of the pointer head defined in main and used as an argument expression.

    You need to pass the original pointer to the function by reference.

    In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer you can get a direct access to the original object.

    The function can look the following way

    int push( node **head, int value )
    {
        node *newnode = malloc( sizeof( node ) );
        int success = newnode != NULL;
    
        if ( success )
        {
            newnode->data = value;
            newnode->next = NULL;
    
            while ( *head ) head = &( *head )->next;
    
            *head = newnode;
        } 
    
        return success;
    }
    

    And the function is called like

    push( &head, value );
    

    Within the function you should check whether memory for the new node was allocated successfully. Otherwise the function can invoke undefined behavior.

    As for the function display then its parameter should be declared with qualifier const because the function does not change nodes of the list

    void display( const node *head){
    

    Pay also attention to that it is inefficient to add new nodes to the end of the singly-linked list. It would be better to define a two-sided singly-linked list that contains two pointers to the begining of the list and its last node.

    That can be achieved by defining one more structure as for example

    typedef struct list
    {
        struct node *head;
        struct node *tail;
    } list;
    

    In this case the function push can look the following way

    int push( list *lst, int value )
    {
        node *newnode = malloc( sizeof( node ) );
        int success = newnode != NULL;
    
        if ( success )
        {
            newnode->data = value;
            newnode->next = NULL;
    
            if ( lst->head == NULL )
            {
                lst->head = newnode;
            }
            else
            {
                lst->tail->next = newnode;
            }
    
            lst->tail = newnode;   
        } 
    
        return success;
    }
    

    and the functoin is called in main like

    int main( void )
    {
        list lst = { .head = NULL, .tail = NULL };
        
        push( &lst, 10 );
    
        // or
    
        if ( !push( &lst, 10 ) ) puts( "Error: not enough memory." );    
    
        //...
    }