Как вернуться в начало однонаправленного списка на Си?
Имеется такой код:
#include <stdio.h>
#include <stdlib.h>
struct door {
int id;
int status;
};
typedef struct node {
int door_id;
int door_status;
struct node *Next;
} doorNode;
doorNode* init(struct door door) {
doorNode *NewNode = (doorNode*)malloc(sizeof(doorNode));
NewNode -> door_id = door.id;
NewNode -> door_status = door.status;
NewNode -> Next = NULL;
return(NewNode);
};
void add_door(doorNode *elem, struct door door) {
doorNode *new_element = init(door);
elem -> Next = new_element;
}
doorNode* find_door(int id_d, doorNode *doors) {
doorNode *tmp = doors;
while (tmp != NULL) {
if (id_d == tmp -> door_id)
break;
}
return(tmp);
}
int main() {
struct door doors[3];
doors[0].id = 1;
doors[0].status = 2;
doors[1].id = 2;
doors[1].status = 4;
doors[2].id = 3;
doors[2].status = 5;
doorNode *forDoor = init(doors[0]);
for (int i = 1; i <= 3; i++) {
add_door(forDoor, doors[i]);
printf("%d, %d", forDoor->door_id, forDoor->door_status);
forDoor = forDoor -> Next;
if (i != 3) {
printf("\n");
}
}
return 0;
}
После цикла for получается, что я нахожусь в конце списка, а нужно еще провести по нему поиск по id, ну либо повторно вывести на экран. Где я что не так делаю? Знаю, что можно добавлять по другому элементы и быть всегда в начале списка, но хочу понять как вернуться в начало, если после добавления элемента ты будешь в конце.
Ответы (2 шт):
Сохранить указатель на первый элемент списка, а потом обратно присвоить его вашей forDoor
#include <stdio.h>
#include <stdlib.h>
struct door {
int id;
int status;
};
typedef struct node {
int door_id;
int door_status;
struct node *Next;
} doorNode;
doorNode* init(struct door door) {
doorNode *NewNode = (doorNode*)malloc(sizeof(doorNode));
NewNode -> door_id = door.id;
NewNode -> door_status = door.status;
NewNode -> Next = NULL;
return(NewNode);
};
void add_door(doorNode *elem, struct door door) {
doorNode *new_element = init(door);
elem -> Next = new_element;
}
doorNode* find_door(int id_d, doorNode *doors) {
doorNode *tmp = doors;
while (tmp != NULL) {
if (id_d == tmp -> door_id)
break;
}
return(tmp);
}
int main() {
struct door doors[3];
doors[0].id = 1;
doors[0].status = 2;
doors[1].id = 2;
doors[1].status = 4;
doors[2].id = 3;
doors[2].status = 5;
doorNode *forDoor = init(doors[0]);
doorNode *firstListElem = forDoor;
for (int i = 1; i <= 3; i++) {
add_door(forDoor, doors[i]);
printf("%d, %d", forDoor->door_id, forDoor->door_status);
forDoor = forDoor -> Next;
if (i != 3) {
printf("\n");
}
}
forDoor = firstListElem;
return 0;
}
Чтобы меньше путаться, создайте ещё одну структуру, отвечающую за список. И держите в ней указатели на начало и конец списка.
Начало нужно всегда, а конец нужен чтобы можно было в конец списка добавить элемент, при этом не пробегать каждый раз по списку, т.к. список однонаправленный. И тогда сразу изменить функцию добавления узла в список.
Например:
struct MyList
{
node *head = nullptr;
node *tail = nullptr;
} List;
void add_door(struct door &door)
{
doorNode *new_element = init(door);
if(List.head == nullptr)
{ // если список пустой
List.head = new_element;
List.tail = new_element;
}
else
{ // добавить элемент в конец списка
List.tail->Next = new_element;
List.tail = new_element;
}
}
int main()
{
struct door doors[3];
doors[0].id = 1;
doors[0].status = 2;
add_door(doors[0]);
}
Поскольку у вас в элементах списка по-сути хранятся элементы структуры объекты door, то проще её и объявить с объектом door, а не 2 интами. Также упростится init():
struct node
{
door Door;
node *Next;
} doorNode;
doorNode* init(struct door &door)
{
doorNode *NewNode = (doorNode*) malloc( sizeof(doorNode) );
NewNode->Door = door;
NewNode->Next = NULL;
return(NewNode);
};
Также, чтобы избежать дополнительного копирования, передавайте в функцию init() и add_door() параметр по ссылке/указателю:
doorNode* init(struct door &door) {}
void add_door(struct door &door) {}