Очень неожиданная проблема при удалении элемента из односвязных списков - PullRequest
0 голосов
/ 09 марта 2020
void insertbeg(n*head)
{

    n *x,*q=head;
    q=(n*)malloc(sizeof(n));
    printf("Enter the data to be entered: ");
    scanf("%d",&q->data);
    q->link=NULL;
    if(head==NULL)
    {
        head=q;
    }
    else
    {
        q->link=head;
        head=q;
    }
    x=head;
    while(x!=NULL)
    {
        printf("%d\t",x->data);
        x=x->link;
    }
    printf("\n");
}   

Этот код выполняется должным образом, это функция, программа драйвера принимает фактический список и, как только она завершится, вызывает эту функцию. В конце она печатает вывод с введенным пользователем элементом в начале, все хорошо до этого момента , У меня есть серия случаев переключения, где каждый случай вызывает функцию, такую ​​как элемент вставки в начале, удаление из конца и т. Д. c, но когда я go говорю любую другую опцию после любой операции, такой как удаление из конца, она удаляет последний элемент и печатает результат после работы с фактическим, а не с измененным списком, как, например: 1 2 3 4 - это фактический список, который я выбираю для вставки элемента в начале. после того, как я вставил скажем 7, он печатает 7 1 2 3 4. После этого я решаю удалить элемент с конца. Он печатает 1 2 3. **, а скорее он должен печатать 7 1 2 3 ** Это происходит с каждым случаем, когда он выполняет операцию, работает с фактическим списком, а не с измененным списком, и печатает результат.

Любая помощь будет высоко ценится. Добавлены изображения фактической программы драйвера

Ответы [ 2 ]

2 голосов
/ 09 марта 2020

Для начала никогда не предоставляйте ссылки на изображения. Весь соответствующий код должен быть напечатан и представлен в вопросе. Предоставьте минимальную демонстрационную программу, которая воспроизводит проблему.

У меня нет никакого желания видеть изображение, ссылку на который вы поместили в своем вопросе, но уже функция insertbeg, которая, как вы думаете, «работает», является недействительным. Он имеет дело с копией указателя на головной узел списка. Таким образом, это утверждение

head=q;

не изменяет исходный указатель, переданный функции в качестве аргумента. Он изменяет копию исходного указателя.

Обратите внимание, что каждая функция должна думать по-своему. Если вы хотите вывести список, напишите еще одну функцию, которая будет выполнять задачу.

Также функция должна получить данные, которые будут добавлены в список в качестве аргумента.

Это Лучше передать указатель по ссылке на функцию.

Функция может выглядеть следующим образом

int insertbeg( n **head, int data )
{
    n *q = malloc( sizeof( n ) );

    int success = q != NULL;

    if ( success )
    {
        q->data = data;
        q->link = *head;
        *head = q;
    }

    return success;
}

Вот демонстрационная программа, которая показывает, как функции, добавляющие узел в начало списка и удалить узел с его конца можно определить.

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

typedef struct node
{
    int data;
    struct node *link;
} n;

int insert_in_begin( n **head, int data )
{
    n *q = malloc( sizeof( n ) );

    int success = q != NULL;

    if ( success )
    {
        q->data = data;
        q->link = *head;
        *head = q;
    }

    return success;
}

void delete_from_end( n **head )
{
    if ( *head != NULL )
    {
        while ( ( *head )->link != NULL ) head = &( *head )->link;

        free( *head );

        *head = NULL;
    }
}

void output( n *head )
{
    for ( ; head != NULL; head = head->link )
    {
        printf( "%d -> ", head->data );
    }

    puts( "null" );
}

int main(void) 
{
    enum { N = 10 };

    n *head = NULL;

    for ( int i = 0; i < N; i++ )
    {
        insert_in_begin( &head, i );
    }

    while ( head != NULL )
    {
        output( head );
        delete_from_end( &head );
    }

    output( head );

    return 0;
}

Вывод программы:

9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> null
9 -> 8 -> 7 -> 6 -> 5 -> null
9 -> 8 -> 7 -> 6 -> null
9 -> 8 -> 7 -> null
9 -> 8 -> null
9 -> null
null
1 голос
/ 09 марта 2020

Я думаю, что проблема в следующих строках:

head=q;

В то время как логика c того, что вы пытаетесь сделать, это solid проблема здесь в том, что вы меняете значение голова в стеке. Другими словами, то, что вы получаете в этой функции в качестве параметра, является адресом первого элемента списка. Этот адрес помещается в стек, и вы используете его в функции insertbeg.

Теперь вам нужно как-то сообщить коду, вызывающему эту функцию (я думаю, вы обращаетесь к нему в вопрос как водителя) что голова изменилась. Я думаю, что лучший способ сделать это - изменить параметр с n * на n **.

Таким образом, вы получите адрес головки указателя, а не только то, на что он указывает (то есть адрес первого элемента).

Подводя итог, я бы предложил следующие изменения:

1) Измените параметр с n*head на n **addressOfHead

2) Измените каждое вхождение head в вашем коде *addressOfHead

Небольшое объяснение того, что мы только что там сделали:

1) Теперь мы передаем адрес переменной, которая содержит адрес первого элемента вместо адреса самого первого элемента. Таким образом, мы можем распространять информацию о новом адресе первого элемента обратно в код, который вызвал функцию.

2) Из-за того, что мы сделали в пункте 1, у нас больше нет параметра head, содержащего адрес первого элемента списка. Тем не менее, мы можем получить этот адрес, сняв ссылку на двойной указатель, который у нас есть. Вот так *addressOfHead. С этим выражением мы в основном сообщаем компилятору: «Пожалуйста, дайте мне номер, который находится в адресе ячейки памяти по адресу». Это число является адресом первого элемента (то есть главы).

Надеюсь, я мог бы помочь.

...