Abhinav Sharma
Abhinav Sharma

Reputation: 13

Head keeps getting set to NULL

I made a doubly link list and ran it a couple times with functions to add nodes at end, output the length of the list and to print all the elements. It was working fine. Then I made a function to add a node at a specific location called AddNodeAt(). and since then, it no longer works. head keeps getting set to NULL. After AddNode() is done the other functions work as if head points to NULL instead of the list.

This is the full code:

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

struct node {
    node *prev;
    int val;
    node *next;
};
typedef struct node node;

node *head;

node *AddNode(node *head, int value)
{
    node *ptr = (node *)malloc(sizeof(node));

    if (!ptr) {
        printf("No Memory Available");
    } else
    if (!head) {
        ptr->val = value;
        ptr->next = NULL;
        ptr->prev = NULL;
        head = ptr;
    } else {
        node *temp = head;
        while (temp->next) {
            temp = temp->next;
        }
        temp->next = ptr;
        ptr->prev = temp;
        ptr->next = NULL;
        ptr->val = value;
    }
    return head;
}

int ListLength(node *head)
{
    int count = 0;
 
    if (head == NULL) {
        printf("\nEmpty List\n");
    } else {
        node *temp = head;
        count = 1;
        while (temp->next != NULL) {
            temp = temp->next;
            count++;
        }
        printf("\n%d nodes\n", count);
    }
    return count;
}

node *AddNodeAt(node *head, int position, int value)
{
    int i = 0;
    node *temp = head;
    node *ptr = (node *)malloc(sizeof(node));
    if (head == NULL && position != 1) {
        printf("Empty Linklist, cannot insert node at the given position");
    } else
    if (position > ListLength(head) + 1) {
        printf("list too short, cannot insert node at the given position");
    } else
    if (position == ListLength(head) + 1) {
        while (temp->next) {
            temp = temp->next;
        }
        temp->next = ptr;
        ptr->next = NULL;
        ptr->val = value;
        ptr->prev = temp;
    } else {
        while (i < position) {
            i++;
            temp = temp->next;
        }
        ptr->next = temp->next;
        temp->next = ptr;
        ptr->prev = temp;
        ptr->val = value;
        temp = ptr->next;
        temp->prev = ptr;
    }
    return head;
}

void PrintList(node *head)
{
    node *temp = head;
    if (!head) {
        printf("list empty");
    } else {
        while (temp->next != NULL) {
            printf("%d->", temp->val);
            temp = temp->next;
        }
        printf("%d", temp->val);
    }
}

int main() {
    int value = 0;
    int num = 0;
    int position = 0;
    printf("Number of nodes to be made: ");
    scanf("%d", &num);
    for (int i = 1; i <= num; i++) {
        printf("value in node number %d: ", i);
        scanf("%d", &value);
        AddNode(head, value);
    }
    PrintList(head);
    ListLength(head);

    printf("\nPosition of new node: ");
    scanf("%d", &position);
    printf("\nNumber of nodes:");
    scanf("%d", &value);
    AddNodeAt(head, position, value);

    PrintList(head);
    ListLength(head);

    return 0;
}

Any guidance would be appreciated. I tried commenting out the sections which I added right before this issue occurred. I expected others to start working as they were working before, but they didn't. head keeps getting set to NULL.

Upvotes: 1

Views: 134

Answers (3)

arfneto
arfneto

Reputation: 1765

As written AddNode is wrong, or at least used wrong. In main, as provided, AddNode is called twice:

    for (int i = 1; i <= num; i++)
        {
            printf("value in node nummber %d : ", i);
            scanf("%d", &value);
            AddNode(head, value);
        }
    PrintList(head);
    ListLength(head);

    printf("\nPosition of new node:");
    scanf("%d", &position);
    printf("\nNumber of node :");
    scanf("%d", &value);
    AddNodeAt(head, position, value);

And the return value is ignored. If you change it to

    for (int i = 1; i <= num; i++)
        {
            printf("value in node nummber %d : ", i);
            scanf("%d", &value);
            head = AddNode(head, value);
        }
    PrintList(head);
    ListLength(head);

    printf("\nPosition of new node:");
    scanf("%d", &position);
    printf("\nNumber of node :");
    scanf("%d", &value);
    head = AddNodeAt(head, position, value);

It will work. But there are other bugs.

Also you need to change

struct node
{
    node* prev;
    int val;
    node* next;
};

to

struct node
{
    struct node* prev;
    int val;
    struct node* next;
};

To compile this in C, or at least place the typedef before the struct declaration, as

typedef struct node node;
struct node
{
    node* prev;
    int val;
    node* next;
};

more about the code

I will not go deep into the bugs. Instead I will provide some discussion and add a complete example (and some more discussion) at the end. It is a long post and you can jump to TL;DR or just ignore all this...

AddNode()

Inside AddNode head is a local node*, but just above we see node as a global node* thing. Not good at all. And in main the return value is just ignored.

node* head;

node* AddNode(node* head, int value)
{
    node* ptr = (node*)malloc(sizeof(node));

    if (!ptr)
        {
            printf("No Memory Available");
        }
    else if (!head)
        {
            ptr->val  = value;
            ptr->next = NULL;
            ptr->prev = NULL;
            head      = ptr;
        }
    else
        {
            node* temp = head;
            while (temp->next)
                {
                    temp = temp->next;
                }
            temp->next = ptr;
            ptr->prev  = temp;
            ptr->next  = NULL;
            ptr->val   = value;
        }
    return head;
}

You could just delete this argument, or just start using the return value to update the head of the list.

node* AddNodeAt(node* head, int position, int value)

This one also has bugs.

As an example if this condition is true:

    node* ptr  = (node*)malloc(sizeof(node));
    if (head == NULL && position != 1)
    {
        printf(
            "Empty Linklist,cant insert node at the "
            "given position");
    }

the function will print the message and return head unchanged. But the allocated memory in ptr is gone for good...

Also it does not work is position is 1, where it should add the node at the head.

Anyway, since the value returned from the function is just ignored in main there is no future for the list anyway.

more about the code

  • use prototypes. main should be the first function in the code file. Or if possible in a separate file. This way you can write many small test programs and test everything faster.
  • do not write interactive code. It will just slows you down. A lot. Use files, constants, factory functions, generators, anything but prompting the user for item count and then items.
  • scanf returns and int for a reason. read the manual. Tes the return value against the number of expected items. scanf is --- hence the name --- a scanner, and it is normal to read nothing. As for your program... Just enter e insted of 4 just above and boom: there goes your program.
  • never use globals, like head in your case. It is a disaster. Use arguments.

more about the data

linked lists are containers. All lists are equal: just a --- possibly empty --- sequence of nodes. Not data, just nodes. Each node contains (your case) or points to a single unit of data, let us name it a record. So operations on the list does not depend on what is being listed at he moment. Or should not. This way your code can be reused for the next classical exercise, like the list of movie tickes, the music playlist, the library booklist, the list for parking lot management :D and all the other usual suspects.

the list in the provided code

typedef struct node node;
struct node
{
    node* prev;
    int val;
    node* next;
};

node* head;

This is just a node and a global pointer to a node. There is not even a mention to a list.

TL;DR an EXAMPLE

a possible list alternative

// this is a node
typedef struct st_node
{
    Info*           info;
    struct st_node* prev;  // links
    struct st_node* next;
} Node;

// this is a list
typedef struct
{
    size_t size;
    Node*  head;
    Node*  tail;
} List;

Now we have a linked list. And the list has metadata: the minimum expected: pointers to head and tail and a size counter. And you see that life can be easier: each List has its own head, tail and size thing.

What about the node? Each node has the links and a pointer to some Info thing. These way you can have lists of anything: the data itself is not even mentioned in the node except for the name.

You can declare

    List one;
    List other = { 0, NULL, NULL };
    List* set[30];

and have lists one and other and an array of 30 pointers to lists from set[0] to set[29].

List operations

List* so_create_list(void);
List* so_delete_list(List*);
int   so_insert(Info*, List*, int (*compare)(void*, void*));
int   so_insert_at(int position, Info* value, List* list);
int   so_insert_back(Info*, List*);
int   so_insert_front(Info*, List*);
int   so_print_list(FILE*,List*,const char*);
int   so_sort_nodes(List*, int (*compare)(void*, void*));

Writing this way we see that nodes are internal to the list, not present in any argument list. We use only pointers to List and Info so if the list changes or even if Info changes completely, from the int in this example to a complex dynamically allocated multi-level struct, it will make no difference for the list itself.

In fact if each node contains a pointer to a data record, all the list need to know is how to

  • copy a record, so the list does not depend on non-owning (user provided) data or pointers. This is called a copy constructor in C++ for example
  • delete a record, since the record can allocated memory. This is called a destructor in C++.
  • show a record on screen, since there is a function to print the list and the list does not know a thing about the records. This is called a toString method in java.
  • compare two records, if we may need to sort the list or insert records in some order. This is like the compare function in C's qsort function.

If we provide this to the list it can be a list of anything. Generic and useful. I will not implement it now, but I hope you can get the idea from the code: it is just a matter of writing these node operations as functions and using them in the proper places.

insert_at(int position, int value, List* list);

This function is seen mostly in student's tasks. Makes not much sense access data in linked lists by position. If this is important we probably would be using arrays or hash tables. Linked Lists are built for navegation, well, by links.

Anyway, a possible implementation is in the example code, alog with some use cases.

building a simple example based on the original code

Using an int inside the node as the data, an example follows

list.h: list functions for the example

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

// these are operations on data
int so_cmp_info(void* a, void* b);
int so_print_info(int, const char*);

// this is a node
typedef struct st_node
{
    int             info;
    struct st_node* prev;  // links
    struct st_node* next;
} Node;

// this is a list
typedef struct
{
    size_t size;
    Node*  head;
    Node*  tail;
} List;

// operations on List
List* so_create_list(void);
List* so_delete_list(List*);
int   so_insert(int, List*, int (*compare)(void*, void*));
int   so_insert_at(int position, int value, List* list);
int   so_insert_back(int, List*);
int   so_insert_front(int, List*);
int   so_print_list(List*, const char*);
int   so_print_list_r(List*, const char*);
int   so_sort_nodes(List*, int (*compare)(void*, void*));

As so_insert_at() is not a common operation for linked lists, so_sort_nodes() is also not a common thing. It is here just to show that all we need to sort is:

  • a comparison function
  • the ability to navigate on the items, a thing that linked lists do very well. Anyway, the source code is below.

The presence of the comparison function for 2 records makes it easy to write

int   so_insert(int, List*,int (*compare)(void*, void*));

to insert records in some determined order, like ISBN for a book list, or song duration for the playlists. We can have many compare functions with different criteria. If we change the criteria it is needed to sort the list using the new criteria before inserting using the new comparison function, and this is the reason for the sort function.

A possible implementation for so_insert is in the example.

A few examples:

List* so_create_list(void)
{
    List* list = malloc(sizeof(List));
    if (list == NULL) return NULL;
    list->head = NULL;
    list->tail = NULL;
    list->size = 0;
    fprintf(stderr, "list created\n");
    return list;
}

This is a possible way to create a list. Using it is as simple as in the example:

        List* list = so_create_list();

NULL is returned in case of error.

// inserts 'info' at the tail of the list
int so_insert_back(int info, List* list)
{
    if (list == NULL) return -1;  // no list
    Node* node = (Node*)malloc(sizeof(Node));
    if (node == NULL) return -2;  // no alloc

    // copy the record pointed by 'info'
    node->info = info;

    if (list->size == 0)  // first node
    {
        node->next = NULL;
        node->prev = NULL;
        list->size = 1;
        list->head = node;
        list->tail = node;
        return 0;  // 1st node
    };
    node->next       = NULL;
    node->prev       = list->tail;
    list->tail->next = node;
    list->tail       = node;
    list->size += 1;
    return 0;
}

This is a simple implementaton for insert_back() that inserts a record at the end of the list. insert_front() is similar, since the list keeps pointers for head and tail.

    List* list = so_create_list();
    if (list == NULL) return -1;
    for (int info = 1; info <= 10; info += 2)
        so_insert_back(info, list);
    so_print_list(list, "\tinserted 1 to 9 ==>\n\n");
    for (int info = -1; info >= -10; info -= 2)
        so_insert_front(info, list);
    so_print_list(list, "\tinserted -1 to -9 ==>\n\n");

This lines from the example inserts some records at head and tail of the list, and print it. Output is

list created

        inserted 1 to 9 ==>

5 data points:
First: 1    Last: 9
   1    3    5    7    9


        inserted -1 to -9 ==>

10 data points:
First: -9    Last: 9
  -9   -7   -5   -3   -1    1    3    5    7    9

And we see the convenience of non-interacive code and of accepting an optional title message in so_print_list()

As an example of ordering, these lines in the example

    so_sort_nodes(list, so_cmp_info);
    so_print_list(list, "\tsorted descending value ==>\n\n");

are all we need to sort the list in-place in descending order --- based on the compare function anyway.

list.c an example implementation for these functions

#include "List.h"

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

Node* so_locate_at(List* list, size_t pos);
int   so_swap_info(Node* one, Node* other);

// list related functions

List* so_create_list(void)
{
    List* list = malloc(sizeof(List));
    if (list == NULL) return NULL;
    list->head = NULL;
    list->tail = NULL;
    list->size = 0;
    fprintf(stderr, "list created\n");
    return list;
}

List* so_delete_list(List* del)
{
    if (del == NULL) return NULL;  // no list
    Node* save = NULL;
    for (size_t i = 0; i < del->size; i += 1)
    {  // delete nodes, 1 by 1
        save = del->head->next;
        // delete the record pointed by 'head'
        free(del->head);
        del->head = save;
    };
    free(del);  // delete list
    fprintf(stderr, "list deleted\n");
    return NULL;
}

int so_insert(
    int value, List* list, int (*cmp)(void*, void*))
{
    if (list == NULL) return -1;  // no list
    Node* p = list->head;
    for (size_t i = 0; i < list->size; i += 1)
    {   // cmp() > 0 marks the insertion point
        if (cmp(&value, &p->info) > 0)
        {
            Node* node = (Node*)malloc(sizeof(Node));
            if (node == NULL) return -4;  // no alloc
            node->info = value;
            // link the new node before 'p'
            if (p == list->head)
                return so_insert_front(value, list);
            p->prev->next = node;
            node->next    = p;
            node->prev    = p->prev;
            p->prev       = node;
            // update size
            list->size += 1;
            return 0;
        }
        p = p->next;
    }
    // all nodes ordered. insert at the end
    return so_insert_back(value, list);
}

// inserts 'val' at 'position' in 'List'
// first position is 1
int so_insert_at(int position, int val, List* list)
{
    if (list == NULL) return -1;
    // insert at head?
    if (position == 1) return so_insert_front(val, list);
    if (list->size == 0) return -2;  // empty list
    if (position > list->size) return -3;
    if (position == list->size)
        return so_insert_back(val, list);
    // ok: just advance pointer 'position'-1 times
    Node* p = list->head;
    for (int i = 1; i < position; i += 1) p = p->next;
    Node* node = (Node*)malloc(sizeof(Node));
    if (node == NULL) return -4;  // no alloc
    node->info = val;
    // link the new node before 'p'
    p->prev->next = node;
    node->next    = p;
    node->prev    = p->prev;
    p->prev       = node;
    // update size
    list->size += 1;
    return 0;
}

// inserts 'info' at the tail of the list
int so_insert_back(int info, List* list)
{
    if (list == NULL) return -1;  // no list
    Node* node = (Node*)malloc(sizeof(Node));
    if (node == NULL) return -2;  // no alloc

    // copy the record pointed by 'info'
    node->info = info;

    if (list->size == 0)  // first node
    {
        node->next = NULL;
        node->prev = NULL;
        list->size = 1;
        list->head = node;
        list->tail = node;
        return 0;  // 1st node
    };
    node->next       = NULL;
    node->prev       = list->tail;
    list->tail->next = node;
    list->tail       = node;
    list->size += 1;
    return 0;
}

// inserts 'info' at the head of the list
int so_insert_front(int info, List* list)
{
    if (list == NULL) return -1;  // no list
    Node* node = (Node*)malloc(sizeof(Node));
    if (node == NULL) return -2;  // no alloc

    // copy the record pointed by 'info'
    node->info = info;

    if (list->size == 0)
    {
        node->next = NULL;
        node->prev = NULL;
        list->size = 1;
        list->head = node;
        list->tail = node;
        return 0;  // 1st node
    };
    node->next       = list->head;
    node->prev       = NULL;
    list->head->prev = node;
    list->head       = node;
    list->size += 1;
    return 0;
}

int so_print_list(List* list, const char* msg)
{
    FILE* out = stdout;
    if (list == NULL)
    {
        fprintf(out, "No valid list!\n");
        return 0;
    }
    if (list->size == 0)
    {
        fprintf(out, "list is empty\n");
        return 0;
    }
    if (msg != NULL)
        printf(
            "\n%s%zd data points:\nFirst: %d    Last: %d\n",
            msg, list->size, list->head->info,
            list->tail->info);
    else
        printf(
            "\n%zd data points:\nFirst: %d    Last: %d\n",
            list->size, list->head->info, list->tail->info);
    Node* p = list->head;
    for (size_t i = 0; i < list->size; i += 1)
    {
        so_print_info(p->info, NULL);
        p = p->next;
    }
    printf("\n\n");
    return 0;
}

int so_print_list_r(List* list, const char* msg)
{
    FILE* out = stdout;
    if (list == NULL)
    {
        fprintf(out, "No valid list!\n");
        return 0;
    }
    if (list->size == 0)
    {
        fprintf(out, "list is empty\n");
        return 0;
    }
    if (msg != NULL)
        printf(
            "\n%s%zd data points (reverse order):\nFirst: "
            "%d    Last: %d\n",
            msg, list->size, list->head->info,
            list->tail->info);
    else
        printf(
            "\n%zd data points (reverse order):\nFirst: %d "
            "   Last: %d\n",
            list->size, list->head->info, list->tail->info);

    Node* p = list->tail;
    for (size_t i = 0; i < list->size; i += 1)
    {
        so_print_info(p->info, NULL);
        p = p->prev;
    }
    printf("\n[-----]\n\n");
    return 0;
}

// return a pointer to a copy of the record
// at such 'pos', or 'NULL'. 'pos'starts at 0
Node* so_locate_at(List* list, size_t pos)
{
    if (list == NULL) return NULL;
    if (list->size < 1 + pos) return NULL;
    Node* nd = list->head;
    for (size_t i = 0; i < pos; i += 1) nd = nd->next;
    return nd;
}

int so_sort_nodes(List* list, int (*cmp)(void*, void*))
{
    if (list == NULL) return -1;
    if (list->size < 2) return -2;
    if (cmp == NULL) return -3;
    for (int i = 0; i < list->size - 1; i += 1)
        for (int j = 0; j < list->size - i - 1; j += 1)
        {
            Node* one = so_locate_at(list, j);
            if (cmp((void*)one, (void*)one->next) < 0)
                so_swap_info(one, one->next);
        }
    return 0;
}

// swap data from these 2 nodes
int so_swap_info(Node* one, Node* other)
{
    if (one == NULL) return -1;
    if (other == NULL) return -1;
    int temp    = one->info;
    one->info   = other->info;
    other->info = temp;
    return 0;
}

int so_cmp_info(void* a, void* b)
{
    if (a == NULL) return 0;
    if (b == NULL) return 0;
    int ta = ((Node*)a)->info;
    int tb = ((Node*)b)->info;

    if (ta > tb) return +1;
    if (ta < tb) return -1;

    return 0;
};

int so_print_info(int info, const char* msg)
{
    if (msg != NULL) printf("%s", msg);
    printf("%4d ", info);
    return 0;
}

main for the example

This code creates a list and tests some of the functions. The list is printed at each step. At the end the list is sorted, displayed and deleted.

#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int main(void)
{
    List* list = so_create_list();
    if (list == NULL) return -1;
    for (int info = 1; info <= 10; info += 2)
        so_insert_back(info, list);
    so_print_list(list, "\tinserted 1 to 9 ==>\n\n");
    for (int info = -1; info >= -10; info -= 2)
        so_insert_front(info, list);
    so_print_list(list, "\tinserted -1 to -9 ==>\n\n");
    // insert at the tail using so_insert_at()
    so_insert_at((int)list->size, 10, list);
    so_insert_at((int)list->size, 11, list);
    so_print_list(
        list, "\tinserted 10 & 11 at the end ==>\n\n");
    // inser at head  using so_insert_at()
    so_insert_at(1, -10, list);
    so_insert_at(1, -11, list);
    so_print_list(
        list, "\tinserted -10 & -11 at the head ==>\n\n");

    so_insert_at(9,2, list);
    so_print_list(list, "\tinserted 2 at pos 9 ==>\n\n");
    so_insert_at(11,4, list);
    so_print_list(list, "\tinserted 4 at pos 11 ==>\n\n");
    so_insert_at(13,6, list);
    so_print_list(list, "\tinserted 6 at pos 13 ==>\n\n");

    so_sort_nodes(list, so_cmp_info);
    so_print_list(list, "\tsorted descending value ==>\n\n");
    so_delete_list(list);
    return 0;
}

output for the example

list created

        inserted 1 to 9 ==>

5 data points:
First: 1    Last: 9
   1    3    5    7    9


        inserted -1 to -9 ==>

10 data points:
First: -9    Last: 9
  -9   -7   -5   -3   -1    1    3    5    7    9


        inserted 10 & 11 at the end ==>

12 data points:
First: -9    Last: 11
  -9   -7   -5   -3   -1    1    3    5    7    9   10   11


        inserted -10 & -11 at the head ==>

14 data points:
First: -11    Last: 11
 -11  -10   -9   -7   -5   -3   -1    1    3    5    7    9   10   11


        inserted 2 at pos 9 ==>

15 data points:
First: -11    Last: 11
 -11  -10   -9   -7   -5   -3   -1    1    2    3    5    7    9   10   11


        inserted 4 at pos 11 ==>

16 data points:
First: -11    Last: 11
 -11  -10   -9   -7   -5   -3   -1    1    2    3    4    5    7    9   10   11


        inserted 6 at pos 13 ==>

17 data points:
First: -11    Last: 11
 -11  -10   -9   -7   -5   -3   -1    1    2    3    4    5    6    7    9   10   11


        sorted descending value ==>

17 data points:
First: 11    Last: -11
  11   10    9    7    6    5    4    3    2    1   -1   -3   -5   -7   -9  -10  -11

list deleted

inserting nodes in order

This small example shows how to insert data ordered by some criteria:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"
int main(void)
{
    srand(240605);
    List* list = so_create_list();
    if (list == NULL) return -1;
    for (int i = 0; i < 20; i += 1)
        so_insert(rand()%100, list, so_cmp_info);
    so_print_list(list, "\tinserted 20 elements with values from [0..99] ==>\n");
    // force insert at the end
    so_insert(1000, list, so_cmp_info);
    so_print_list(list, "\tinserted 1000 ==>\n");
    // force insert at the head
    so_insert(-1000, list, so_cmp_info);
    so_print_list(list, "\tinserted -1000 ==>\n");
    so_delete_list(list);
    return 0;
}

output

list created

        inserted 20 elements with values from [0..99] ==>
20 data points:
First: 99    Last: 3
  99   94   91   89   86   85   84   83   79   79   72   62   61   42   37   36   35   22   12    3


        inserted 1000 ==>
21 data points:
First: 1000    Last: 3
1000   99   94   91   89   86   85   84   83   79   79   72   62   61   42   37   36   35   22   12    3


        inserted -1000 ==>
22 data points:
First: 1000    Last: -1000
1000   99   94   91   89   86   85   84   83   79   79   72   62   61   42   37   36   35   22   12    3 -1000

list deleted

It is a bit off-topic, here only for completeness

Upvotes: 0

chqrlie
chqrlie

Reputation: 145277

head does not get set to NULL: the global variable head is initialized to NULL before the program starts and is never updated to point to the allocated list.

You should make head a local variable in main and update it to the return value of functions AddNode and AddNodeAt.

Note these other problems:

  • always check the return value of scanf() and report input errors.
  • always check for allocation errors and report failures.
  • use ancillary functions to make this simple and systematic.
  • move the typedef before the struct node definition so node is available for the member definitions. As posted, your code does not compile as C, but is valid C++.
  • ListLength should not output anything. Use separate functions to compute the list length and to print the list length.
#include <stdio.h>
#include <stdlib.h>

typedef struct node node;
struct node {
    node *prev;
    int val;
    node *next;
};

int get_integer(void) {
    for (;;) {
        int value;
        int c;
        switch (scanf("%d", &value)) {
          case 1:
            /* read and discard the rest of the input line */
            while ((c = getchar()) != EOF && c != '\n')
                continue;
            printf("\n");
            return value;
          case EOF:
            fprintf(stderr, "unexpected end of file, aborting\n");
            exit(1);
          default:
            /* read and discard the rest of the input line */
            while ((c = getchar()) != EOF && c != '\n')
                continue;
            fprintf(stderr, "invalid input, try again\n");
            break;
        }
    }
}

node *AddNode(node *head, int value) {
    node *ptr = (node *)malloc(sizeof(node));

    if (!ptr) {
        fprintf(stderr, "No Memory Available\n");
        exit(1);
    }
    ptr->val = value;
    ptr->next = NULL;
    ptr->prev = NULL;

    if (!head) {
        head = ptr;
    } else {
        node *temp = head;
        while (temp->next) {
            temp = temp->next;
        }
        temp->next = ptr;
        ptr->prev = temp;
    }
    return head;
}

int ListLength(const node *head) {
    int count = 0;
 
    while (head != NULL) {
        count++;
        head = head->next;
    }
    return count;
}

void PrintListLength(const node *head)  {
    if (head == NULL) {
        printf("Empty List\n");
    } else {
        printf("%d nodes\n", ListLength(head));
    }
}

node *AddNodeAt(node *head, int position, int value) {

    if (position > ListLength(head) + 1) {
        printf("list too short, cannot insert node at the given position\n");
        return head;
    }

    node *ptr = (node *)malloc(sizeof(node));
    if (!ptr) {
        fprintf(stderr, "No Memory Available\n");
        exit(1);
    }
    /* initialize the new node */
    ptr->value = value;
    ptr->next = NULL;
    ptr->prev = NULL;

    if (position <= 1) {
        /* insert at front */
        if (head) {
            ptr->next = head;
            head->prev = ptr;
        }
        head = ptr;
    } else {
        node *temp = head;

        for (int i = 1; i < position; i++) {
            temp = temp->next;
            i++;
        }
        ptr->prev = temp;
        temp->next = ptr;
        ptr->next = temp->next;
        if (ptr->next) {
            ptr->next->prev = ptr;
        }
    }
    return head;
}

void PrintList(const node *head) {
    const node *temp = head;
    if (!head) {
        printf("list empty\n");
    } else {
        while (temp->next != NULL) {
            printf("%d->", temp->val);
            temp = temp->next;
        }
        printf("%d\n", temp->val);
    }
}

void FreeList(node *head) {
    while (head) {
        node *next = head->next;
        free(head);
        head = next;
    }
}
        
int main(void) {
    int value = 0;
    int num = 0;
    int position = 0;
    node *head = NULL;

    printf("Number of nodes to be made: ");
    num = get_integer();

    for (int i = 1; i <= num; i++) {
        printf("value in node number %d: ", i);
        value = get_integer();
        head = AddNode(head, value);
    }
    PrintList(head);
    PrintListLength(head);

    printf("Position of new node: ");
    position = get_integer();
    printf("Node value: ");
    value = get_integer();
    head = AddNodeAt(head, position, value);

    PrintList(head);
    PrintListLength(head);

    FreeList(head);
    return 0;
}

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409422

The problem is the assignment head=ptr in the AddNode function. That will only modify the local variable head. It will not modify the global variable of the same name, that global variable will stay NULL.

The simple solution to this is to use the pointer that AddNode returns:

head = AddNode(head,value);

You have the same problem with the AddNodeAt function.


On a related note, please don't use global variables. You could define head locally inside the main function.

Upvotes: 3

Related Questions