rottingham Temat założony przez niniejszego użytkownika |
» 2019-09-10 00:59:18 Ok. Poprawiłem funkcję void wypisz(). Kod jest już chyba dobrze zrobiony? Nie lepiej byłoby w mainie wyzerować Lista * lista zamiast tworzyć dodatkową funkcję void utworz()? #include <iostream>
using namespace std;
struct Wezel { int liczba; Wezel * nastepny; };
struct Lista { Wezel * glowa, * ogon; };
void utworz( Lista *& lista ) { lista = nullptr; }
void dodajogon( Lista *& lista, int liczba ) { Wezel * nowy = new Wezel; nowy->liczba = liczba; nowy->nastepny = nullptr; if( !lista ) { lista = new Lista; lista->glowa = lista->ogon = nowy; } else { lista->ogon = lista->ogon->nastepny = nowy; } }
void wypisz( Lista * lista ) { if( lista ) { Lista * tmp; tmp->glowa = lista->glowa; while( tmp->glowa ) { cout << tmp->glowa->liczba << " "; tmp->glowa = tmp->glowa->nastepny; } tmp = nullptr; } }
void zniszcz( Lista *& lista ) { if( lista ) { while( lista->glowa ) { Wezel * tmp = lista->glowa; lista->glowa = lista->glowa->nastepny; delete tmp; } lista->ogon = nullptr; } }
int main() { int liczba; Lista * lista; utworz( lista ); while( cin >> liczba && liczba ) dodajogon( lista, liczba ); wypisz( lista ); zniszcz( lista ); }
Mam jeszcze pytanie w związku z tym kodem, który napisałem na początku. Czy on jest z jakichś powodów gorszy niż ten, który stworzyłem teraz? #include <iostream>
using namespace std;
struct Lista { Lista * ogon; int liczba; };
void wypisz( Lista * lista ) { if( lista ) { cout << lista->liczba << ", "; wypisz( lista->ogon ); } }
Lista * dodajKoniec( Lista *& lista, int liczba, Lista * ostatni ) { Lista * nowy = new Lista; nowy->liczba = liczba; nowy->ogon = nullptr; if( lista ) { ostatni->ogon = nowy; return nowy; } else lista = nowy; return lista; }
void zniszcz( Lista *& lista ) { while( lista ) { Lista * tmp = lista; lista = lista->ogon; delete tmp; } lista = nullptr; }
int main() { Lista * lista = nullptr, * ostatni; int liczba; while( cin >> liczba && liczba ) ostatni = dodajKoniec( lista, liczba, ostatni ); wypisz( lista ); zniszcz( lista ); }
|
|
pekfos |
» 2019-09-10 06:32:02 Jest prawie dobrze. Teraz tylko niepotrzebnie alokujesz Lista. Jeśli coś nie musi być alokowane dynamicznie, to nie powinno. A jeśli już koniecznie chcesz, to musisz przynajmniej zwalniać tę alokację, a tworzenie listy to kompetencje utworz(), nie dodajKoniec(). Mam jeszcze pytanie w związku z tym kodem, który napisałem na początku. Czy on jest z jakichś powodów gorszy niż ten, który stworzyłem teraz? |
Tak. Wszystko przez to: Lista * dodajKoniec( Lista *& lista, int liczba, Lista * ostatni )
Masz 2 argumenty, które muszą być spójne. To szczegóły implementacyjne, które powinny być opakowane, w taką na przykład strukturę. Pomyśl choćby o przypadku tworzenia wielu list. Nie jest to chyba wielkie wymaganie, w zadaniu do lekcji o strukturach? |
|
rottingham Temat założony przez niniejszego użytkownika |
» 2019-09-12 17:07:21 Rozumiem. Teraz zamiast zerować Lista * lista to zeruję tylko jej dwa wskaźniki na początek i na koniec w ramach funkcji utworz(). Czy teraz jest lepiej? #include <iostream>
using namespace std;
struct Wezel { int liczba; Wezel * nastepny; };
struct Lista { Wezel * glowa, * ogon; };
void utworz( Lista *& lista ) { lista->glowa = lista->ogon = nullptr; }
void dodajogon( Lista *& lista, int liczba ) { Wezel * nowy = new Wezel; nowy->liczba = liczba; nowy->nastepny = nullptr; if( !lista->glowa ) { lista->glowa = lista->ogon = nowy; } else { lista->ogon = lista->ogon->nastepny = nowy; } }
void wypisz( Lista * lista ) { if( lista->glowa ) { Lista * tmp; tmp->glowa = lista->glowa; while( tmp->glowa ) { cout << tmp->glowa->liczba << " "; tmp->glowa = tmp->glowa->nastepny; } tmp = nullptr; } }
void zniszcz( Lista *& lista ) { if( lista->glowa ) { while( lista->glowa ) { Wezel * tmp = lista->glowa; lista->glowa = lista->glowa->nastepny; delete tmp; } lista->ogon = nullptr; } }
int main() { int liczba; Lista * lista; utworz( lista ); while( cin >> liczba && liczba ) dodajogon( lista, liczba ); wypisz( lista ); zniszcz( lista ); }
|
|
pekfos |
» 2019-09-12 17:55:07 Teraz kod w ogóle nie działa. Używasz niezainicjalizowanego wskaźnika. |
|
rottingham Temat założony przez niniejszego użytkownika |
» 2019-09-14 21:03:08 Czy teraz jest dobrze? #include <iostream>
using namespace std;
struct Wezel { int liczba; Wezel * nastepny; };
struct Lista { Wezel * glowa, * ogon; };
void utworz( Lista *& lista ) { lista->glowa = lista->ogon = nullptr; }
void dodajogon( Lista *& lista, int liczba ) { Wezel * nowy = new Wezel; nowy->liczba = liczba; nowy->nastepny = nullptr; if( !lista->glowa ) { lista->glowa = lista->ogon = nowy; } else { lista->ogon = lista->ogon->nastepny = nowy; } }
void wypisz( Lista * lista ) { if( lista->glowa ) { Wezel * tmp = lista->glowa; while( tmp ) { cout << tmp->liczba << " "; tmp = tmp->nastepny; } tmp = nullptr; } }
void zniszcz( Lista *& lista ) { if( lista->glowa ) { while( lista->glowa ) { Wezel * tmp = lista->glowa; lista->glowa = lista->glowa->nastepny; delete tmp; } lista->ogon = nullptr; } }
int main() { int liczba; Lista * lista; utworz( lista ); while( cin >> liczba && liczba ) dodajogon( lista, liczba ); wypisz( lista ); zniszcz( lista ); }
Odnośnie poprzedniego kodu napisałeś, że: Teraz kod w ogóle nie działa |
Dlaczego dostawałem dobre dane na wyjściu? Problem nie powinien ujawnić się podczas kompilacji? Albo chociaż w trakcie wyrzucania danych? |
|
pekfos |
» 2019-09-14 22:23:36 Jest lepiej.. ale musiałem zrobić diffa żeby wiedzieć co w ogóle zmieniłeś. Ja miałem na myśli ten fragment Lista * lista; utworz( lista ); Nie ma żadnego powodu, by lista było wskaźnikiem. Problem nie powinien ujawnić się podczas kompilacji? |
Kompilator nie weryfikuje sensu programu. Albo chociaż w trakcie wyrzucania danych? |
Błędne użycie wskaźnika ma niezdefiniowane zachowanie. Może stać się cokolwiek, w tym może zadziałać poprawnie. U mnie program wysypuje się już na utworz(). |
|
rottingham Temat założony przez niniejszego użytkownika |
» 2019-09-15 15:09:42 Teraz chyba jest już ok? Napisałeś, że tworzenie listy to kompetencje utworz(). W ramach utworz tworzę wskaźnik na początek i na koniec listy. Czyli de facto tam powstaje "szkielet" listy, który jeszcze nie ma elementów(?). Cały późniejszy proces w ramach dodajKoniec to tylko dodawanie n-tego elementu. Z tego wnioskuję, że utworz() i dodajKoniec() wypełniają dokładnie taki zakres funkcjonalności jaki mają wykonywać. Czy dobrze myślę? #include <iostream>
using namespace std;
struct Wezel { int liczba; Wezel * nastepny; };
struct Lista { Wezel * glowa, * ogon; };
void utworz( Lista & lista ) { lista.glowa = lista.ogon = nullptr; }
void dodajogon( Lista & lista, int liczba ) { Wezel * nowy = new Wezel; nowy->liczba = liczba; nowy->nastepny = nullptr; if( !lista.glowa ) { lista.glowa = lista.ogon = nowy; } else { lista.ogon = lista.ogon->nastepny = nowy; } }
void wypisz( Lista lista ) { if( lista.glowa ) { Wezel * tmp = lista.glowa; while( tmp ) { cout << tmp->liczba << " "; tmp = tmp->nastepny; } tmp = nullptr; } }
void zniszcz( Lista & lista ) { if( lista.glowa ) { while( lista.glowa ) { Wezel * tmp = lista.glowa; lista.glowa = lista.glowa->nastepny; delete tmp; } lista.ogon = nullptr; } }
int main() { int liczba; Lista lista; utworz( lista ); while( cin >> liczba && liczba ) dodajogon( lista, liczba ); wypisz( lista ); zniszcz( lista ); }
|
|
pekfos |
» 2019-09-15 17:07:44 W ramach utworz tworzę wskaźnik na początek i na koniec listy. Czyli de facto tam powstaje "szkielet" listy, który jeszcze nie ma elementów(?). |
Nie. Dzieje się tam dokładnie to, co napisałeś w kodzie - przypisujesz nullptr do dwóch wskaźników. W żaden sposób ich to nie 'tworzy'. Wygląda ok. |
|
1 2 3 4 « 5 » 6 |