• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Problem z metodą printAll() (wypisz wszystko) listy jednokierunkowej

Object Storage Arubacloud
0 głosów
453 wizyt
pytanie zadane 3 stycznia 2023 w C i C++ przez Noizz00 Użytkownik (910 p.)

Witam, zacząłem ćwiczyć używanie dynamicznych struktur, metod struktur, konstruktorów, inicjalizatorów itd. Chciałem stworzyć listę jednokierunkową (struct LinkedList) przechowującą dane studentów (struct Student). Metoda printAll() struktury LinkedList służy do wypisania całej listy. W poniższym kodzie próbuję wypisać listę, usunąć pierwszy element listy (lista.deleteHead()) i wypisać listę ponownie. Problem w tym, że na konsoli wyświetla mi się jedna pofragmentowana lista, niektóre pola struktur są zastąpione pustymi liniami, co uruchomienie jest inaczej. Nie wyświetla mi się informacja o zakończonym programie. Poniżej kod:

#include <iostream>

using namespace std;

struct Student
{
    string imie;
    string email;
    int id;
    double srednia;
    Student* nastepny;
    void print();
    Student(string imie, string email, int id, double srednia);
};

struct LinkedList
{
    Student* pierwszy;
    Student* ptr;
    void printAll();
    void addHead(Student* student);
    void deleteAll();
    void deleteHead();
    LinkedList();
};

Student::Student(string imie, string email, int id, double srednia)
    : imie(imie)
    , email(email)
    , id(id)
    , srednia(srednia)
{
    nastepny = NULL;
}

LinkedList::LinkedList()
{
    pierwszy = NULL;
}

void Student::print()
{
    cout << "Imie: " << imie << endl;
    cout << "Email: " << email << endl;
    cout << "ID: " << id << endl;
    cout << "Srednia: " << srednia << endl;
}

void LinkedList::printAll()
{
    ptr = pierwszy;
    while(ptr)
    {
        ptr->print();
        ptr=ptr->nastepny;
    }
}

void LinkedList::addHead(Student* nowy)
{
    if(pierwszy == 0)
        pierwszy = nowy;
    else
    {
        nowy->nastepny = pierwszy;
        pierwszy = nowy;
    }
}

void LinkedList::deleteAll()
{
    while(pierwszy)
    {
        ptr = pierwszy;
        pierwszy = pierwszy->nastepny;
        delete ptr;
    }
}

void LinkedList::deleteHead()
{
    if(pierwszy != 0)
    {
        ptr = pierwszy;
        pierwszy = ptr->nastepny;
        delete ptr;
    }
}

int main()
{
    LinkedList lista;
    Student* A = new Student("Maciej", "maciej@gmail.com", 247682, 4.5);
    Student* B = new Student("Kamil", "kamil@gmail.com", 247683, 5.0);
    Student* C = new Student("Adam", "adam@gmail.com", 247684, 4.0);
    Student* D = new Student("Jan", "jan@gmail.com", 247689, 3.5);
    Student* E = new Student("Piotr", "piotr@gmail.com", 247690, 3.0);
    lista.addHead(A);
    lista.addHead(B);
    lista.addHead(C);
    lista.addHead(D);
    lista.addHead(E);
    lista.printAll();
    cout << endl;
    lista.deleteHead();
    lista.printAll();
    lista.deleteAll();
    return 0;
}

Kiedy wypisuję listę jednokrotnie w całym programie, to wyświetla się ona prawidłowo. Jak wspominałem, problem pojawia się, gdy próbuję wypisać listę więcej razy.

Jak na razie niepewnie poruszam się w temacie wskaźników jeżeli chodzi o listy, więc myślę że problem może być związany z jakąś błędną operacją na wskaźniku, chociaż, oczywiście, mogę myśleć źle :)

komentarz 3 stycznia 2023 przez j23 Mędrzec (194,920 p.)

To jest dokładnie ten kod, który pokazuje złe wyniki? Ja tu nie widzę problemów, poza może tym, że wskaźnik ptr powinien być zmienną lokalną, a nie polem klasy.

komentarz 3 stycznia 2023 przez j23 Mędrzec (194,920 p.)
Ciekawe. Co to za kompilator?
komentarz 3 stycznia 2023 przez Noizz00 Użytkownik (910 p.)
GNU GCC Compiler, pracuję w Codeblocks. Jakiś czas temu programy po kompilacji otwierają się mi w jakieś innej, nowej wersji Windowsowego wiersza poleceń, również po tym czasie zauważyłem takie błędy, miałem wcześniej podobny błąd wyświetlania tylko już przy zwyczajnym wypisywaniu liczb. Szukałem w internecie rozwiązania tego problemu ale nie znalazłem, może szukałem w złych miejscach.
komentarz 3 stycznia 2023 przez j23 Mędrzec (194,920 p.)
No to pewnie jest problem z tą "inną" konsolą a nie kodem. Jak pisałem, kod wygląda OK pod kątem potencjalnych błędów.
komentarz 3 stycznia 2023 przez Noizz00 Użytkownik (910 p.)
Na szczęście udało mi się zmienić domyślny terminal w systemie, teraz wszystko działa.
komentarz 3 stycznia 2023 przez adrian17 Ekspert (344,860 p.)

To jest dokładnie ten kod, który pokazuje złe wyniki? Ja tu nie widzę problemów, poza może tym, że wskaźnik ptr powinien być zmienną lokalną, a nie polem klasy.

Popieram, AddressSanitizer też niczego podejrzanego nie znalazł.

2 odpowiedzi

0 głosów
odpowiedź 3 stycznia 2023 przez Noizz00 Użytkownik (910 p.)
edycja 3 stycznia 2023 przez Noizz00
EDIT. Udostępniłem zdjęcia poprzez onedrive, bo tutaj mocno psuje się rozdzielczość.

j23, to dokładnie ten sam kod. Może zamieszczę zdjęcia:

jednokrotne użycie printAll():

https://1drv.ms/u/s!ArXsHRnUrtHfrzdKAx84Ho5AkUn2?e=JWc8Ap

dwukrotne:

https://1drv.ms/u/s!ArXsHRnUrtHfrzlQFothoFcmpt-s?e=z4XSCM

Sprawdziłem jeszcze w powershellu i tutaj uruchomienie programu jest prawidłowe. Więc co jest nie tak?

https://1drv.ms/u/s!ArXsHRnUrtHfrzj9Il_tPKxa0rQb?e=MM6cgG
–1 głos
odpowiedź 3 stycznia 2023 przez Wiciorny Ekspert (269,710 p.)
edycja 3 stycznia 2023 przez Wiciorny

Jeśli problem pojawia się tylko wtedy, gdy wyświetlasz całą listę i próbujesz to zrobić ponownie, może to oznaczać, że wskaźnik pierwszy nie jest ustawiany na NULL po usunięciu pierwszego elementu. Możesz to naprawić poprzez dodanie następującej linii kodu do funkcji deleteHead():

if(!pierwszy) pierwszy = NULL;

Dzięki temu, jeśli pierwszy element zostanie usunięty, to pierwszy zostanie ustawiony na NULL, co powinno rozwiązać problem.

np.

void LinkedList::deleteHead()
{
    if(pierwszy)
    {
        ptr = pierwszy;
        pierwszy = pierwszy->nastepny;
        delete ptr;
        ptr = NULL;
        if(!pierwszy) pierwszy = NULL;
    }
}

Funkcja ta usuwa pierwszy element z listy i ustawia wskaźnik pierwszy na następny element w liście. Następnie ustawia wskaźnik ptr na NULL i sprawdza, czy pierwszy element jest równy NULL. Jeśli tak, to ustawia wskaźnik pierwszy na NULL.

komentarz 3 stycznia 2023 przez j23 Mędrzec (194,920 p.)
if(!pierwszy) pierwszy = NULL;

Przecież to bez sensu jest. Skoro pierwszy jest null, to po co mu przypisywać jeszcze raz null?

Podobne pytania

+1 głos
1 odpowiedź 127 wizyt
0 głosów
0 odpowiedzi 560 wizyt
0 głosów
1 odpowiedź 466 wizyt
pytanie zadane 8 maja 2020 w C i C++ przez Dyali56 Nowicjusz (150 p.)

92,555 zapytań

141,403 odpowiedzi

319,553 komentarzy

61,939 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...