Denise Tan Denise Tan - 2 years ago 80
C Question

Linked List removeNode C Programming

I was having some confusion between ListNode and LinkedList. Basically my question was divided into 2 parts. For first part, I was supposed to do with ListNode. The function prototype as such:

int removeNode(ListNode **ptrHead, int index);


All function were working fine for the ListNode part. Then as for the second part, I was supposed to change the function above to this:

int removeNode(LinkedList *11, int index);


My code for part 1 which is working fine look like this:

int removeNode(ListNode **ptrHead, int index) {
ListNode *pre, *cur;
if (index == -1)
return 1;
else if (findNode(*ptrHead, index) != NULL) {
pre = findNode(*ptrHead, index - 1);
cur = pre->next;
pre->next = cur->next;
return 0;
}
else
return 1;
}

ListNode *findNode(ListNode *head, int index) {
ListNode *cur = head;
if (head == NULL || index < 0)
return NULL;
while (index > 0) {
cur = cur->next;
if (cur == NULL) return NULL;
index--;
}
return cur;
}


And here is my entire code for the part 2 which is not working:

#include "stdafx.h"
#include <stdlib.h>

typedef struct _listnode {
int num;
struct _listnode *next;
}ListNode;

typedef struct _linkedlist {
ListNode *head;
int size;
}LinkedList;

void printNode2(ListNode *head);
int removeNode2(LinkedList *ll, int index);

int main()
{
int value, index;
ListNode *head = NULL, *newNode = NULL;
LinkedList *ptr_ll = NULL;

printf("Enter value, -1 to quit: ");
scanf("%d", &value);
while (value != -1) {
if (head == NULL) {
head = malloc(sizeof(ListNode));
newNode = head;
}
else {
newNode->next = malloc(sizeof(ListNode));
newNode = newNode->next;
}
newNode->num = value;
newNode->next = NULL;
scanf("%d", &value);
}

printNode2(head);

printf("\nEnter index to remove: ");
scanf("%d", &index);
removeNode2(ptr_ll, index);
printNode2(head);

return 0;
}

void printNode2(ListNode *head) {
printf("Current list: ");
while (head != NULL) {
printf("%d ", head->num);
head = head->next;
}
}

int removeNode2(LinkedList *ll, int index) {
ListNode *head = ll->head;
if (head == index)
{
if (head->next == NULL)
{
printf("There is only one node. The list can't be made empty ");
return 1;
}

/* Copy the data of next node to head */
head->num = head->next->num;

// store address of next node
index = head->next;

// Remove the link of next node
head->next = head->next->next;

return 0;
}


// When not first node, follow the normal deletion process

// find the previous node
ListNode *prev = head;
while (prev->next != NULL && prev->next != index)
prev = prev->next;

// Check if node really exists in Linked List
if (prev->next == NULL)
{
printf("\n Given node is not present in Linked List");
return 1;
}

// Remove node from Linked List
prev->next = prev->next->next;

return 0;
}


When I try to run the part 2, the cmd just not responding and after a while, it just closed by itself and I have no idea which part went wrong. I was thinking am I in the correct track or the entire LinkedList part just wrong?

When I tried to run in debug mode, this error message popped up:

Exception thrown at 0x01201FD1 in tut.exe: 0xC0000005: Access violation reading location 0x00000000.

If there is a handler for this exception, the program may be safely continued.


Thanks in advance.

Answer Source

You say that you got the linked list to work wihen the list is defined via the head pointer only. In this set-up, you have to pass a pointer to the head pointer when the list may be updated, and just the head pointer when you only inspect the list without modifying, for example:

int removeNode(ListNode **ptrHead, int index);
ListNode *findNode(ListNode *head, int index);

Here, the head pointer is the handle for the list that is visible to the client code.

The approach with the list struct defines a new interface for the linked list. While the head node is enough, it might be desirable to keep track of the tail as well for easy appending or of the number of nodes. This data can be bundles in the linked list struct.

What that means is that the handling of the nodes is left to the list and the client code uses only the linked list struct, for example:

typedef struct ListNode ListNode;
typedef struct LinkedList LinkedList;

struct ListNode {
    int num;
    ListNode *next;
};

struct LinkedList {
    ListNode *head;
    ListNode *tail;
    int size;
};

void ll_print(const LinkedList *ll);
void ll_prepend(LinkedList *ll, int num);
void ll_append(LinkedList *ll, int num);
void ll_remove_head(LinkedList *ll);

int main()
{
    LinkedList ll = {NULL};

    ll_append(&ll, 2);
    ll_append(&ll, 5);
    ll_append(&ll, 8);
    ll_print(&ll);

    ll_prepend(&ll, 1);
    ll_prepend(&ll, 0);
    ll_print(&ll);

    ll_remove_head(&ll);
    ll_print(&ll);

    while (ll.head) ll_remove_head(&ll);

    return 0;
}

There's also one difference: In the head-node set-up, the head node might be null. Here, the list cannot be null, it must exist. (Its head and tail members can be null, though.) Here the list is allocated on the stack, its address &ll must be passed to the functions.

In the linked list set-up, the distinction between modifying and read-only access is done via the const keyword:

void ll_print(const LinkedList *ll);
void ll_prepend(LinkedList *ll, int num);

In your example, you take a mixed approach with two independent structures, a head node and a list. That can't work, one single list is described by one struct, pick one.

The advantage to the linked list structure approach is that all required data like head, tail and size are always passed together to a function. You can also hide the implementation from the user by not disclosing the struct members, so that theb user can only work on pointers to that struct.

Finally, here's an example implementation of the above interface for you to play with:

void ll_print(const LinkedList *ll)
{
    ListNode *node = ll->head;

    while (node != NULL) {
        printf("%d ", node->num);
        node = node->next;
    }

    putchar('\n');
}

void ll_prepend(LinkedList *ll, int num)
{
    ListNode *nnew = malloc(sizeof *nnew);

    nnew->next = ll->head;
    nnew->num = num;

    ll->head = nnew;
    if (ll->tail == NULL) ll->tail = ll->head;
    ll->size++;
}

void ll_append(LinkedList *ll, int num)
{
    ListNode *nnew = malloc(sizeof *nnew);

    nnew->next = NULL;
    nnew->num = num;

    if (ll->tail == NULL) {
        ll->tail = ll->head = nnew;
    } else {
        ll->tail->next = nnew;
        ll->tail = nnew;
    }
    ll->size++;
}

void ll_remove_head(LinkedList *ll)
{
    if (ll->head) {
        ListNode *ndel = ll->head;

        ll->head = ll->head->next;
        ll->size--;

        free(ndel);
    }
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download