lista dwukierunkowa ID i usuwanie wiersza z ciągu znaków

0

Po raz kolejny mam problem z moim projektem. Przy dodawaniu obiektu muszę zainicjować unikalne ID zaczynające się od 1. Tutaj fragment polecenia: "Program automatycznie przypisuje pierwszy wolny ID do nowego obiektu". Indeksy wierszy są prawidłowe, bo testowałam przy usuwaniu, jednak wyświetla mi nieprawidłowe ID w funkcji wyświetlania. Próbowałam z funkcją zwracającą wielkość listy, ale nie mam pojęcia jak się stamtąd odnieść do ID.
Kolejny problem, to usuwanie obiektu za pomocą tytułu. W jaki sposób mam wyszukać dany tytuł i zarazem usunąć cały wiersz?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct ObiektWypozyczenia
{
    int ID; //unikalna liczba całkowita - przypisywane automatycznie przez program, najlepiej od 1
    char tytul[40];
    char imie_autor[20];
    char nazwisko_autor[25];
    char kategoria[3]; //ksiazka/film/gra planszowa;
    char imie_osoba[20];
    char nazwisko_osoba[25];
    int ilosc_wyp; //ile razy przedmiot zostal wypozyczony

    struct data_wyp
    {
        int rok, miesiac, dzien;
    };

    struct ObiektWypozyczenia *next;
    struct ObiektWypozyczenia *prev;
}dane;

dane *head = NULL;
dane *tail = NULL;

int wielkosc(dane *head)
{
    int d = 0;
    dane *el = head;
    while(el != NULL)
    {
        d++;
            el = el->next;
    }
    return d;
}

void dodaj(int ID)
{
    unsigned int m, n;
    dane *el = head;
    el = new dane;

//Pytania o dane
        printf("\nPodaj dane obiektu\n");
            printf("\tKategoria (1.ksiazka/2.film/3.gra planszowa): ");
                scanf("%d", &m);
                fflush(stdin);

                    if(m == 1)
                    {
                        strcpy(el->kategoria, "ksiazka");
                    }
                    else if(m == 2)
                    {
                        strcpy(el->kategoria, "film");
                    }
                    else if(m == 3)
                    {
                        strcpy(el->kategoria, "gra planszowa");
                    }
                    else
                    {
                        printf("Nieprawidlowy znak.");
                    }

            printf("\tTytul: ");
                scanf(" %[^\n]s", el->tytul);
                fflush(stdin);
            printf("\tImie autora: ");
                scanf(" %[^\n]s", el->imie_autor);
                fflush(stdin);
            printf("\tNazwisko autora: ");
                scanf(" %[^\n]s", el->nazwisko_autor);
                fflush(stdin);

//Dodawanie elementu
        if(head == NULL)
        {
            head = el;
            ID = 1;
            el->ID = ID;
            el->next = NULL;
            el->prev = NULL;
            tail = el;

        }
        else
        {
            ID++;
            el->ID = ID;
            el->next = NULL;
            el->prev = tail;
            tail->next = el;
            tail = el;
        }
//Pytanie o kolejny element
    printf("\n------------------------------------------\n");
        printf("\n1)Dodaj nowy element\t\t2)Wroc do menu\nWybor:");
            scanf("%d", &n);
            fflush(stdin);
        if(n == 1)  {dodaj(ID);}
        else if(n == 2) {}
        else    {printf("Nieprawidlowy znak");}
}
void usun()
{
    int ID, x;
    char tytul[40];

    dane *el = head;
    dane *wsk;

    if(head == NULL)
    {
        return;
    }

        printf("Usun wedlug\n1) ID\t\t2) tytul\nWybor: ");
            scanf("%d", &x);
            fflush(stdin);

        switch(x)
        {
        case 1:
            unsigned int n;
            printf("Podaj ID: ");
                scanf("%d", &n);
                fflush(stdin);

            if(n == 1)
            {
                if(el->prev == el->next)
                {
                    head = NULL;
                    free(el);
                }
                else
                {
                    head = el->next;
                    el->prev = NULL;
                    el->next->ID = el->ID;
                    free(el);
                }
            }
            else if(n > 1 && n <= wielkosc(head))
            {
                wsk = el->next;
                el->next = wsk->next;
                el->next->prev = el;
                el->next->ID = el->ID;
                el = el->next;
                free(wsk);
            }
            else
            {
                printf("\nObiekt o podanym ID nie istnieje.\n");
            }
            break;

        case 2:
            char m[40];
            printf("Podaj tytul: ");
                scanf("%[^\n]s", m);
                fflush(stdin);

            while(el != NULL)
            {
                if(el->tytul = m)
                {
                    if(el->prev == el->next)
                    {
                        head = NULL;
                        free(el);
                    }
                    else
                    {
                        head = el->next;
                        el->prev = NULL;
    //                    el->next->tytul = el->tytul;
                        free(el);
                    }

                    break;
                }
                else if(m == tytul)
                {
                    while(el != NULL)
                    {
                        el = el->next;
                    }
                    wsk = el->next;
                    el->next = wsk->next;
                    el->next->prev = el;
    //                el->next->tytul = el->tytul;
                    free(wsk);
                    break;
                }
                else
                {
                    printf("\nObiekt o podanym tytule nie istnieje.\n");
                }

                el = el->next;
            }
            break;
        default:
            printf("\nNieprawidlowy znak.\n");
        }
}
void wyswietl_nazwa(dane *head) //po nazwie obiektu
{
    int ID;
    dane *el = head;
    if(el == NULL)
    {
        printf("Brak elementow.\n");
    }
    else
    {
        while (el != NULL)
        {
            printf("\nTytul: %s\tImie i nazwisko autora: %s %s\tKategoria: %s\tID: %d", el->tytul, el->imie_autor, el->nazwisko_autor, el->kategoria, el->ID);
            el = el->next;
        }
    }
}
1

@Moniia:

  1. Usuwanie po tytule, stringi porównujesz funkcją strcmp:
if(strcmp(el->tytul, m) == 0)
  1. Dodawanie elementu:
        if(n == 1)  {dodaj(ID);}

Nie bardzo rozumiem, dlaczego funkcję dodaj wywołujesz rekurencyjnie?

Skoro funkcja 'wielkosc' zwraca int to możesz ID przypisać w taki sposób:

el->ID = wielkosc() + 1;
0

@Moniia:

  1. Ta funkcja w ogóle mi się kupy nie trzyma. Skąd pobierasz ID które przekazujesz jako argument tej funkcji?
0

@Eldorad O.:
Myślałam, ze może mi się przydać, a obecność ID w argumencie, czy jego brak nie wpływa w żaden sposób na działanie mojego programu, gdy to sprawdzałam.

0

@Moniia:

Moniia napisał(a):

@Eldorad O.:

a obecność ID w argumencie, czy jego brak nie wpływa w żaden sposób na działanie mojego programu

Jakim cudem, przecież nie przekazując argumentu dostałabyś błąd kompilacji.

0

@Eldorad O.: Żadne błędy mi się nie pokazują, a program pomimo tego argumentu działał mi sprawnie. Przyznam, że sama do końca nie wiem, bo robię ten program metodą prób i błędów, aż nie zadziała.

1

@Moniia: Dobra, zacznijmy od tego, że funkcja ma za zadanie wykonywać jedną określoną czynność, w tym przypadku dołączenie elementu do listy,
ty wywołujesz w niej też menu wyboru które powinno być składową innej funkcji, ale dobra na razie niech zostanie tak jak jest, po kolei wszystko:

void dodaj()
{
    unsigned int next_id = wielkosc(head) + 1;
    unsigned int m, n;
    dane *el = head;
    el = new dane;

//Pytania o dane
        printf("\nPodaj dane obiektu\n");
            printf("\tKategoria (1.ksiazka/2.film/3.gra planszowa): ");
                scanf("%d", &m);
                fflush(stdin);

                    if(m == 1)
                    {
                        strcpy(el->kategoria, "ksiazka");
                    }
                    else if(m == 2)
                    {
                        strcpy(el->kategoria, "film");
                    }
                    else if(m == 3)
                    {
                        strcpy(el->kategoria, "gra planszowa");
                    }
                    else
                    {
                        printf("Nieprawidlowy znak.");
                    }

            printf("\tTytul: ");
                scanf(" %[^\n]s", el->tytul);
                fflush(stdin);
            printf("\tImie autora: ");
                scanf(" %[^\n]s", el->imie_autor);
                fflush(stdin);
            printf("\tNazwisko autora: ");
                scanf(" %[^\n]s", el->nazwisko_autor);
                fflush(stdin);

//Dodawanie elementu
        el->ID = next_id;

        if(head == NULL)
        {
            head = el;
            el->next = NULL;
            el->prev = NULL;
            tail = el;

        }
        else
        {
            el->next = NULL;
            el->prev = tail;
            tail->next = el;
            tail = el;
        }

//Pytanie o kolejny element
    printf("\n------------------------------------------\n");
        printf("\n1)Dodaj nowy element\t\t2)Wroc do menu\nWybor:");
            scanf("%d", &n);
            fflush(stdin);
        if(n == 1)  {dodaj();}
        else if(n == 2) {}
        else    {printf("Nieprawidlowy znak");}
}

na razie wstaw to

1

@Eldorad O.: Okej, działa super, dziękuję za pomoc.

1

@Moniia:

//Pytanie o kolejny element
    printf("\n------------------------------------------\n");
        printf("\n1)Dodaj nowy element\t\t2)Wroc do menu\nWybor:");
            scanf("%d", &n);
            fflush(stdin);
        if(n == 1)  {dodaj();}
        else if(n == 2) {}
        else    {printf("Nieprawidlowy znak");}

Przenieś ten fragment do nowej funkcji, np "inserting_menu" czy coś.

0

@Eldorad O.: Przeniosłam, działa bez zarzutu. Mogłabym jeszcze prosić o sprawdzenie funkcji usuwającej?

0

@Moniia: A co nie działa?

Btw. Ten fragment:

        printf("\nPodaj dane obiektu\n");
            printf("\tKategoria (1.ksiazka/2.film/3.gra planszowa): ");
                scanf("%d", &m);
                fflush(stdin);

                    if(m == 1)
                    {
                        strcpy(el->kategoria, "ksiazka");
                    }
                    else if(m == 2)
                    {
                        strcpy(el->kategoria, "film");
                    }
                    else if(m == 3)
                    {
                        strcpy(el->kategoria, "gra planszowa");
                    }
                    else
                    {
                        printf("Nieprawidlowy znak.");
                    }

            printf("\tTytul: ");
                scanf(" %[^\n]s", el->tytul);
                fflush(stdin);
            printf("\tImie autora: ");
                scanf(" %[^\n]s", el->imie_autor);
                fflush(stdin);
            printf("\tNazwisko autora: ");
                scanf(" %[^\n]s", el->nazwisko_autor);
                fflush(stdin);

też możesz przenieść do osobnej funkcji, będzie ona zwracała "wypełniony" nowy element, który możesz przekazać jako parametr do funkcji dodaj

0

@Eldorad O.: przy usuwaniu ID dla 1 elementu wszystko jest ok. W sytuacji, gdy chcę usunąć element np. 3, jest usuwany drugi. Dodatkowo moje ID Nie zmienia wartości w odpowiedni sposób. Element przechodzący na miejsce usuniętego zyskuje ID = 1.

0

@Moniia: Tak w sumie myślę, że nadawanie elementowi ID na podstawie wielkości listy jest błędne, ponieważ ID będą się mogły powtarzać jeżeli wcześniej usuniesz jakiś, przykładowo
masz 8 elementów w liście, czyli ostatnie ID to 8, usuwasz element 7, masz ich teraz siedem, dodajesz kolejny i ostatni element znów ma ID 8.
Lepiej to ogarnąć zmienną statyczną, chociaż nie wiem jak to w C wygląda.

Edit:
Ok, w C nie ma zmiennych statycznych, czyli zostaje jeszcze jedna opcja. Każdy nowy element ma id o 1 większe od ostatniego, więc za każdym razem gdy nadajesz nowe ID sprawdzasz wartość tej zmiennej dla "tail" i nowemu elementowi nadajesz ID o 1 większe od "tail".

0

@Eldorad O.: hm, w funkcji dodaj spróbowałam więc zapisać :

static int ID = 1;
   el->ID = ID++;

i działa tak samo jak wielkość. W funkcji usun, wciąż niestety występuje ten sam problem

1

@Moniia:

else if(n > 1 && n <= wielkosc(head))
         {
                wsk = el->next;
                el->next = wsk->next;
                el->next->prev = el;
                el->next->ID = el->ID;
                el = el->next;
                free(wsk);
         }

Nie za bardzo wiem co tu chciałaś uzyskać?

Nigdzie nie przeszukujesz listy w poszukiwaniu elementu o wskazanym ID, tylko od razu chwytasz się za element następujący po "head".

0

@Eldorad O.: rzeczywiście zabrakło pętli. Już działa, dziękuję!

0

@Moniia: spoko

1 użytkowników online, w tym zalogowanych: 0, gości: 1