Search code examples
clinked-listpass-by-referencesingly-linked-listfunction-definition

Linked list in C cannot add a node in the beginning


I'm having trouble adding an element to the beginning in my linked list.

#include <conio.h>
#include "list.h"

int main () {

nodePtr L;
L = createList();
L = makeNode(20);
display(L);
addFront(L,25);
display(L);

return 0;
}     

and This is my library, it just prints NODE INSERTED instead of being really inserted at the front.

#include <stdlib.h>
#include <stdio.h>
#ifndef list_h
#define list_h


typedef int itemType;
typedef struct node *nodePtr;

struct node{
    itemType item;
    nodePtr next;
};

nodePtr createList();                                   //init list
nodePtr makeNode(itemType x);                           //allocate node 
void display(nodePtr L);                                //print output
void addFront(nodePtr L, itemType x);                   //add as first element

nodePtr createList() {      
    nodePtr L;
    L= (nodePtr) malloc(sizeof(struct node));
    L->next= NULL;
    return L;
}

nodePtr makeNode(itemType x) {
    nodePtr temp = (nodePtr) malloc(sizeof(struct node));
    temp->item=x;
    temp->next=NULL;
    return temp;
}

void display(nodePtr L) {
    nodePtr temp;
    temp = L;
    while (temp!=NULL) {
        printf("%d", temp->item);
        temp = temp->next;
    }
}

void addFront(nodePtr L, itemType x) {
    nodePtr newNode = (nodePtr) malloc(sizeof(struct node));
    if(newNode == NULL) {
        printf("Unable to allocate memory.");
    }
    else {
    newNode->item = x;
    newNode->next = L;
    L=newNode;
    printf("NODE INSERTED");
    }   
}

#endif

I don't really understand what is wrong, I'm trying to follow the format which initializes typedef nodePtr and itemType from my teacher but I can actually understand the concept of adding the element at the front without following my teacher's format, I just need to understand how her format works as an alternative.


Solution

  • This function

    nodePtr createList() {      
        nodePtr L;
        L= (nodePtr) malloc(sizeof(struct node));
        L->next= NULL;
        return L;
    }
    

    does not make sense. It leaves the data member item uninitialized.

    These two calls

    L = createList();
    L = makeNode(20);
    

    produce a memory leak.

    The function addFront accepts the pointer to a node by value. That is the function deals with a copy of the original pointer used as an argument. So changing the copy of the pointer within the function

        L=newNode;
    

    does not influence on the value of the original pointer. You need to pass the pointer by reference through a pointer to it.

    void addFront(nodePtr *L, itemType x) {
        nodePtr newNode = (nodePtr) malloc(sizeof(struct node));
        if(newNode == NULL) {
            printf("Unable to allocate memory.");
        }
        else {
        newNode->item = x;
        newNode->next = *L;
        *L=newNode;
        printf("NODE INSERTED");
        }   
    }
    

    And the function is called like

    addFront( &L,25 );
    

    Pay attention to that the function should output neither message. It is the caller of the function that will decide whether to output a message based on the returned value from the function.

    So it will be better to define it the following way

    int addFront( nodePtr *L, itemType x ) 
    {
        nodePtr newNode = malloc( sizeof( struct node ) );
        int success = newNode != NULL;
    
        if ( success )
        {
            newNode->item = x;
            newNode->next = *L;
            *L = newNode;
        }
    
        return success;   
    }
    

    Another approach to define the function is when the function returns the new value of the pointer to the head node as for example

    nodePtr addFront( nodePtr L, itemType x ) 
    {
        nodePtr newNode = malloc( sizeof( struct node ) );
    
        if ( newNode != NULL )
        {
            newNode->item = x;
            newNode->next = L;
        }
    
        return newNode;   
    }
    

    But such an approach is not flexible. Before assigning the returned pointer to the pointer to the head node in the caller you need to check whether the returned pointer is not equal to NULL as for example

    nodePtr tmp = addFront( L,25 );
    
    if ( tmp != NULL ) L = tmp;