Ошибка в коде из методички. Работа с двусвязным списком - C (СИ)
Формулировка задачи:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{char data[20];
struct spis *v1; // v1 – указатель на предыдущую структуру
struct spis *v2; // v2 – указатель на последующую структуру
} spis;
void create(void); // создание
void list(spis *); // просмотр
void del(void); // удаление
struct spis *head,*tail; // указатели на начало и конец списка
main()
{
clrscr();
create();
list(head); // просмотр с начала списка
list(tail); // просмотр с конца списка
del();
list(head);
free(head);
}
void create(void)
{spis *p,*pred;
pred=NULL;
do { p=(spis *)malloc(sizeof(spis));
printf("Фамилия: "); gets(p->data);
p->v1=pred;
if (pred != NULL)
pred->v2=p;
else
head=p;
pred=p;
puts(" Закончить - <esc>");
}
while (getch()!=27);
tail=p;
tail->v2=NULL;
}
void list(spis *p)
{if (p==head)
while (p != NULL)
{puts(p->data);
p=p->v2;
}
else if (p==tail)
while ( p!= NULL)
{puts(p->data);
p=p->v1;
}
else
puts("Неверный адрес ");
getch();
}
void del(void)
{spis *p,*temp;char f[20]; // f[20] – Строка для удаляемой фамилии
clrscr();
printf("Фамилия: ");gets(f);
p=head;
while (p!=NULL)
{if (strcmp((p->data),f)==0) // если найдена заданная фамилия
{if (p==head) // если найденная запись - первая
{head=p->v2;
head->v1=NULL;
free(p);
p=head;
}
else if (p==tail) // если найденная запись - последняя
{tail=p->v1;
tail->v2=NULL;
free(p);
p=tail;
}
else // удаление из средины списка
{p->v2->v1=p->v1;
p->v1->v2=p->v2;
temp=p;
p=p->v2;
free(temp);
}
}
else // если заданная фамилия не найдена – продвигаемся по списку
p=p->v2;
}
}#include <stdio.h>
#include <conio.h>
#include <alloc.h>
#include <string.h>
struct spis
{char data[20];
struct spis *v1; // v1 – указатель на предыдущую структуру
struct spis *v2; // v2 – указатель на последующую структуру
};
void create(void); // создание
void list(spis *); // просмотр
void del(void); // удаление
struct spis *head,*tail; // указатели на начало и конец списка
main()
{
clrscr();
create();
list(head); // просмотр с начала списка
list(tail); // просмотр с конца списка
del();
list(head);
free(head);
}
void create(void)
{spis *p,*pred;
pred=NULL;
do { p=(spis *)malloc(sizeof(spis));
printf("Фамилия: "); gets(p->data);
p->v1=pred;
if (pred != NULL)
pred->v2=p;
else
head=p;
pred=p;
puts(" Закончить - <esc>");
}
while (getch()!=27);
tail=p;
tail->v2=NULL;
}
void list(spis *p)
{if (p==head)
while (p != NULL)
{puts(p->data);
p=p->v2;
}
else if (p==tail)
while ( p!= NULL)
{puts(p->data);
p=p->v1;
}
else
puts("Неверный адрес ");
getch();
}
void del(void)
{spis *p,*temp;char f[20]; // f[20] – Строка для удаляемой фамилии
clrscr();
printf("Фамилия: ");gets(f);
p=head;
while (p!=NULL)
{if (strcmp((p->data),f)==0) // если найдена заданная фамилия
{if (p==head) // если найденная запись - первая
{head=p->v2;
head->v1=NULL;
free(p);
p=head;
}
else if (p==tail) // если найденная запись - последняя
{tail=p->v1;
tail->v2=NULL;
free(p);
p=tail;
}
else // удаление из средины списка
{p->v2->v1=p->v1;
p->v1->v2=p->v2;
temp=p;
p=p->v2;
free(temp);
}
}
else // если заданная фамилия не найдена – продвигаемся по списку
p=p->v2;
}
}Решение задачи: «Ошибка в коде из методички. Работа с двусвязным списком»
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
typedef struct spis
{char data[20];
struct spis *v1; // v1 – указатель на предыдущую структуру
struct spis *v2; // v2 – указатель на последующую структуру
} spis;
void create(void); // создание
void list(spis *); // просмотр
void del(void); // удаление
struct spis *head,*tail; // указатели на начало и конец списка
int main()
{
fflush(stdin);
fflush(stdout);
create();
list(head); // просмотр с начала списка
list(tail); // просмотр с конца списка
del();
list(head);
free(head);
}
void create(void)
{spis *p,*pred;
pred=NULL;
do { p=(spis *)malloc(sizeof(spis));
printf("Фамилия: "); gets(p->data);
p->v1=pred;
if (pred != NULL)
pred->v2=p;
else
head=p;
pred=p;
puts(" Закончить - <esc>");
}
while (getch()!=27);
tail=p;
tail->v2=NULL;
}
void list(spis *p)
{if (p==head)
while (p != NULL)
{puts(p->data);
p=p->v2;
}
else if (p==tail)
while ( p!= NULL)
{puts(p->data);
p=p->v1;
}
else
puts("Неверный адрес ");
getch();
}
void del(void)
{struct spis *p,*temp;
char f[20]; // f[20] – Строка для удаляемой фамилии
fflush(stdin);
fflush(stdout);
printf("Фамилия: ");gets(f);
p=head;
while (p!=NULL)
{if (strcmp((p->data),f)==0) // если найдена заданная фамилия
{if (p==head) // если найденная запись - первая
{head=p->v2;
head->v1=NULL;
free(p);
p=head;
}
else if (p==tail) // если найденная запись - последняя
{tail=p->v1;
tail->v2=NULL;
free(p);
p=tail;
}
else // удаление из средины списка
{p->v2->v1=p->v1;
p->v1->v2=p->v2;
temp=p;
p=p->v2;
free(temp);
}
}
else // если заданная фамилия не найдена – продвигаемся по списку
p=p->v2;
}
}
Объяснение кода листинга программы
В этом коде реализована работа со связанным списком, который используется для хранения информации о фамилиях. Список представлен с помощью структуры spis, которая содержит строку данных (фамилию), указатель на предыдущую структуру в списке (v1) и указатель на следующую структуру в списке (v2).
В функции create происходит добавление элементов в список. Пользователю предлагается ввести фамилию, после чего создается новый элемент списка, связывается с предыдущим и следующим элементами и добавляется в конец списка.
Функция list позволяет просмотреть список элементов. Если переданный в функцию указатель на начало списка (head), то выводятся все элементы списка. Если переданный указатель находится в середине списка, то выводятся элементы, начиная с этого указателя и до конца списка. Если переданный указатель указывает на последний элемент списка (tail), то выводятся все элементы списка в обратном порядке.
Функция del предназначена для удаления элемента из списка по заданной фамилии. Если фамилия совпадает с фамилией первого элемента списка, то этот элемент удаляется. Если фамилия совпадает с фамилией последнего элемента списка, то этот элемент удаляется. Если фамилия встречается в середине списка, то элемент удаляется путем разрыва связей между элементами.
В основной функции main сначала выполняется функция create для создания списка. Затем функция list вызывается дважды - сначала с указателем на начало списка (head), затем с указателем на конец списка (tail). После этого выполняется функция del, которая удаляет элемент по заданной фамилии. Затем функция list вызывается снова с указателем на начало списка (head), чтобы просмотреть список после удаления элемента. Наконец, память, выделенная под список, освобождается с помощью функции free.