Как вернуться в начало однонаправленного списка на Си?

Имеется такой код:

#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 шт):

Автор решения: rusgeli

Сохранить указатель на первый элемент списка, а потом обратно присвоить его вашей 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;
}
→ Ссылка
Автор решения: DmitryK

Чтобы меньше путаться, создайте ещё одну структуру, отвечающую за список. И держите в ней указатели на начало и конец списка.
Начало нужно всегда, а конец нужен чтобы можно было в конец списка добавить элемент, при этом не пробегать каждый раз по списку, т.к. список однонаправленный. И тогда сразу изменить функцию добавления узла в список. Например:

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) {}
→ Ссылка