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 шт):
Ошибка может возникать, когда вы пытаетесь получить доступ к удалённым узлам или когда указатели не обновляются должным образом.
Возможные причины:
Неправильное обновление указателей: Когда вы удаляете узел, вам нужно убедиться, что указатели prev и next обновляются правильно, чтобы не потерять доступ к остальным элементам списка.
Доступ к уже удалённым узлам: Если вы пытаетесь получить доступ к узлам после их удаления, это может привести к ошибкам. Например, если delete_node(node) освобождает память, а затем вы пытаетесь использовать node или prev, это может вызвать неопределённое поведение.
Условия выхода из цикла: Если вы удаляете текущий узел, вам нужно правильно установить node на следующий элемент.
Вот несколько изменений, которые могут помочь:
- Обновление указателей: Убедитесь, что вы правильно обновляете указатели при удалении узлов. Например:
if (node == head->first) {
head->first = nxt; // Обновляем голову списка
} else {
prev->next = nxt; // Соединяем предыдущий узел с следующим
}
- Безопасное удаление узлов: Перед вызовом delete_node(node) сохраните следующий узел:
ALBUM_NODE *to_delete = node;
node = nxt; // Сохраняем следующий узел
delete_node(to_delete); // Удаляем текущий узел
head->cnt--;
- Изменение логики цикла: Проверьте порядок операций в вашем цикле. Например, лучше сначала сохранить следующий узел, прежде чем выполнять какие-либо операции с текущим узлом.
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; // Переход к следующему узлу
}
Думаю на этом все