segmentation fault (core dumped) при обработке односвязного списка

void filter(ALBUM_HEAD *head)
{
    ALBUM_NODE *prev = NULL;
    ALBUM_NODE *node = NULL;
    ALBUM_NODE *nxt = NULL;
    char str[MAXLEN];
    char substr[MAXLEN];
    short mode;
    int i;

    mode = 0;

    printf("Do you want to filter by:\n1)Album\n2)Artist\n3)Year\n");
    while (mode != 1 && mode != 2 && mode != 3)
    {
        printf("Enter: ");
        scanf("%hd", &mode);
        getchar();
    }

    if (mode == 1 || mode == 2) printf("Enter the substring to filter: ");
    else printf("Enter the year to filter: ");

    fgets(substr, MAXLEN, stdin);
    substr[strlen(substr)-1] = '\0';

    for (i = 0; i < strlen(substr); i++) substr[i] = tolower(substr[i]);

    node = head->first;

    while(node)
    {
        nxt = node->next;

        if (mode < 3)
        {
            if (mode == 1) strcpy(str, node->aname);
            else if (mode == 2) strcpy(str, node->name->name);

            for (i = 0; i < strlen(str); i++) str[i] = tolower(str[i]);

            if (!strstr(str, substr))
            {
                if (node == head->first) head->first = nxt;
                else if (node == head->last)
                {
                    if (prev) head->last = prev;
                    else head->last = NULL;
                    prev->next = NULL;
                }
                else prev->next = nxt;

                delete_node(node);
                head->cnt--;

            } else prev = node;
        }
        else
        {
            if (node->year != atoi(substr))
            {
                if (node == head->first) head->first = nxt;
                else if (node == head->last)
                {
                    if (prev) head->last = prev;
                    else head->last = NULL;
                    prev->next = NULL;
                }
                else prev->next = nxt;

                delete_node(node);
                head->cnt--;
            } else prev = node;
        }

        node = node->next;
    }
}

Односвязный список создается из файла. Если в файле 13 строк, то при вводе некоторых значений substr при mode=2 (из-за которых удаляется большое кол-во элементов списка) вылетает ошибка. Если вводить значения, при которых удалений не много, то все работает. Если сделать в файле на несколько строк меньше, то уже начинает работать удаление при mode = 1/2. Но при mode=3 ошибки нет, только когда в файле буквально пара строк, то есть ошибка зависит именно от кол-ва элементов списка, которые надо удалить, но притом удаляет верно, так как при уменьшении кол-ва строк все работает. С чем это может быть связано?


Ответы (1 шт):

Автор решения: Damir Hakimof

Ошибка может возникать, когда вы пытаетесь получить доступ к удалённым узлам или когда указатели не обновляются должным образом.

Возможные причины:

  1. Неправильное обновление указателей: Когда вы удаляете узел, вам нужно убедиться, что указатели prev и next обновляются правильно, чтобы не потерять доступ к остальным элементам списка.

  2. Доступ к уже удалённым узлам: Если вы пытаетесь получить доступ к узлам после их удаления, это может привести к ошибкам. Например, если delete_node(node) освобождает память, а затем вы пытаетесь использовать node или prev, это может вызвать неопределённое поведение.

  3. Условия выхода из цикла: Если вы удаляете текущий узел, вам нужно правильно установить node на следующий элемент.

Вот несколько изменений, которые могут помочь:

  1. Обновление указателей: Убедитесь, что вы правильно обновляете указатели при удалении узлов. Например:
   if (node == head->first) {
       head->first = nxt; // Обновляем голову списка
   } else {
       prev->next = nxt; // Соединяем предыдущий узел с следующим
   }
  1. Безопасное удаление узлов: Перед вызовом delete_node(node) сохраните следующий узел:

   ALBUM_NODE *to_delete = node;
   node = nxt; // Сохраняем следующий узел
   delete_node(to_delete); // Удаляем текущий узел
   head->cnt--;
  1. Изменение логики цикла: Проверьте порядок операций в вашем цикле. Например, лучше сначала сохранить следующий узел, прежде чем выполнять какие-либо операции с текущим узлом.
while (node) {
    nxt = node->next; // Сохраняем следующий узел

    if (mode < 3) {
        if (mode == 1) strcpy(str, node->aname);
        else if (mode == 2) strcpy(str, node->name->name);

        for (i = 0; i < strlen(str); i++) str[i] = tolower(str[i]);

        if (!strstr(str, substr)) {
            // Удаляем узел
            if (node == head->first) {
                head->first = nxt; // Обновляем голову списка
            } else {
                prev->next = nxt; // Соединяем предыдущий узел с следующим
            }
            delete_node(node); // Удаление узла
            head->cnt--;
        } else {
            prev = node; // Обновляем предыдущий узел только если не удаляем
        }
    } else {
        // Логика для year
        if (node->year != atoi(substr)) {
            // Удаляем узел
            if (node == head->first) {
                head->first = nxt; // Обновляем голову списка
            } else {
                prev->next = nxt; // Соединяем предыдущий узел с следующим
            }
            delete_node(node); // Удаление узла
            head->cnt--;
        } else {
            prev = node; // Обновляем предыдущий узел только если не удаляем
        }
    }

    node = nxt; // Переход к следующему узлу
}

Думаю на этом все

→ Ссылка