как удалить голову в связанном списке в c? - PullRequest
1 голос
/ 26 января 2020

Эта программа должна удалить N-узел в односвязном списке. Если я поставлю N = 1 или N = 2, все в порядке, программа работает. Но при N = 0 вывод печатает бесконечные узлы со случайными значениями (после удаления узла 0). Я думаю, что программа не может видеть новую голову. Спасибо за помощь!

#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);

}

Я использую current в качестве временного указателя, потому что после сдвига головы на втором узле мне нужен указатель на старую голову и использовать free.

1 Ответ

1 голос
/ 26 января 2020

C всегда проходит по значению, поэтому изменение параметра не влияет на вызывающего.

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

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

Если вы хотите изменить переменную (например, head) вызывающей стороны, вам нужно передать указатель на нее. (Вы все еще можете изменить то, на что ссылается указатель.)

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

deletenode(&head, N);

Теперь вы можете просто заменить каждый экземпляр head в своем коде на (*head), чтобы учесть новое соглашение о вызовах, но это упустило бы возможность для упрощения. Имея указатель на struct node *, нам не нужно обрабатывать head (a struct node *) и prev_node->next (a struct node *) по-разному.

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...