Jokey
Jokey

Reputation: 71

how to delete head in a linked list in c?

This program should delete the N-node in a singly linked list. If i put N = 1 or N = 2 it's ok, the program works. But with N = 0 the output prints infinite nodes with random values (after deleting the node 0). I think the program can't see the new head. Thx for the help!

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

#define N 0

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


void printlist(struct node *head){
    struct node *current=head;
    int i=0;
    while (current!=NULL){
        printf("node number %d \t : %d\n", i, current->data);
        current=current->next;
        i++;
    }
}


int deletenode(struct node *head,int n){
    struct node *current=head;
    struct node *previous=head;

    int i=0;

    while(current!= NULL){

        if (n==i && i!=0){
            previous->next=current->next;
            free(current);
            return 1;
        }
        else if (n==i && i==0){
            head=head->next;
            free(current);
            return 1;
        }
        i++;
        previous=current;
        current=current->next;
        return 0;
    }

    printf("error\n");
    exit(EXIT_FAILURE);
}


void main(){

    struct node *n1=malloc(sizeof(struct node));
    struct node *n2=malloc(sizeof(struct node));
    struct node *n3=malloc(sizeof(struct node));

    struct node *head=n1;
    n1->data=5;
    n1->next=n2;
    n2->data=10;
    n2->next=n3;
    n3->data=15;
    n3->next=NULL;

    printf("\n\nbefore\n");
    printlist(head);
    deletenode(head,N);
    printf("\n\nafter\n");
    printlist(head);

}

I'm using currentas a temp pointer , because after the head shift on the second node i need a pointer to the old head and use free.

Upvotes: 1

Views: 1175

Answers (1)

ikegami
ikegami

Reputation: 385565

C always passes by value, so changing a parameter has no effect on the caller.

void foo(int i) {
   i = 1234;  // No effect on caller.
}

void foo(int *p) {
   p = NULL;  // No effect on caller.
}

If you want to modify a variable (such as the caller's head), you need to pass a pointer to it. (You can still change that to which a pointer references.)

int deletenode(struct node **head, int n) {
   ...
}

deletenode(&head, N);

Now, you could simply replace every instance of head in your code with (*head) to account for the new calling convention, but that would waste an opportunity for simplification. By having a pointer to a struct node *, we don't need to handle head (a struct node *) and prev_node->next (a struct node *) differently.

int delete_node_n(struct node **ptr, unsigned n) {
    // Make `ptr` point to the pointer we want to modify.
    // This will either be the `head` variable
    // or the `next` field of some node.
    while (1) {
       if (!*ptr)
          return 0;

       if (!n)
          break;

       ptr = &( (*ptr)->next );
       --n;
    }

    struct node *to_free = *ptr;
    *ptr = (*ptr)->next;
    free(to_free);
    return 1;
}

Upvotes: 1

Related Questions