rottingham Temat założony przez niniejszego użytkownika |
» 2019-08-27 17:24:46 Jaka logika stała za tym, że dodajKoniec() alokuje jeden węzeł i zwalnia inny? |
No cóż, patrząc na gafę jaką popełniłem chciałbym wyjaśnić co mi przyświecało w procesie twórczym. Rozpisałem taki kod: #include <iostream>
using namespace std;
struct Wezel { int liczba; Wezel * ogon; };
struct Lista { Wezel * poczatek; Wezel * koniec; };
int main() { Lista * lista = new Lista; Wezel * element = new Wezel; element->liczba = 1; element->ogon = nullptr; lista->poczatek = element; cout << element << endl; delete element; element = nullptr; cout << element << endl; cout << lista->poczatek << " " << lista->poczatek->liczba << endl; }
Patrząc na wyjście tego kodu wyraźnie - ku mojemu zdziwieniu - mogłem wyzerować Wezel * element co nie powodowało zerowania lista->poczatek. Uznałem, że znalazłem dziwną prawidłowość polegającą na tym, że lista->poczatek nabiera poniekąd pewną autonomię co pozwala mi wykorzystać Wezel * element do tymczasowego przechowania adresu i wyzerowania go, ażeby ponownie go wykorzystać. |
|
pekfos |
» 2019-08-27 18:03:09 Uznałem, że znalazłem dziwną prawidłowość polegającą na tym, że lista->poczatek nabiera poniekąd pewną autonomię co pozwala mi wykorzystać Wezel * element do tymczasowego przechowania adresu i wyzerowania go |
Trochę późno na robienie takich odkryć. Tak działają zmienne. lista->poczatek = element;
cout << element << endl;
delete element;
element = nullptr;
cout << element << endl;
cout << lista->poczatek << " " << lista->poczatek->liczba << endl;
|
|
rottingham Temat założony przez niniejszego użytkownika |
» 2019-09-01 19:15:26 Okej, napisałem kod, który wiem, że działa. Pytanie: co mogę w nim ulepszyć? Kod wydaje mnie się trochę karkołomny. Czy mógłbym prosić o wskazówki jak go trochę skrócić? #include <iostream>
using namespace std;
struct Wezel { int liczba; Wezel * nastepny; };
struct Lista { Wezel * glowa, * wezel, * ostatni; };
void utworz( Lista *& lista ) { lista = new Lista; lista->glowa = lista->wezel = lista->ostatni = nullptr; }
void dodajKoniec( Lista *& lista, int liczba ) { Wezel * nowy = new Wezel; nowy->liczba = liczba; nowy->nastepny = nullptr; lista->wezel = nowy; if( !lista->glowa ) { lista->glowa = lista->wezel; lista->ostatni = lista->wezel; } else { lista->ostatni->nastepny = lista->wezel; lista->ostatni = lista->wezel; } }
void wypisz( Lista * lista ) { while( lista->glowa ) { cout << lista->glowa->liczba << " "; lista->glowa = lista->glowa->nastepny; } }
void zniszcz( Lista * lista ) { while( lista->glowa ) { Wezel * tmp = lista->glowa; lista->glowa = lista->glowa->nastepny; delete tmp; } while( lista->wezel ) { Wezel * tmp = lista->wezel; lista->wezel = lista->wezel->nastepny; delete tmp; } while( lista->ostatni ) { Wezel * tmp = lista->ostatni; lista->ostatni = lista->ostatni->nastepny; delete tmp; } lista->ostatni = lista->glowa = lista->wezel = nullptr; }
int main() { int liczba; Lista * lista; utworz( lista ); while( cin >> liczba && liczba ) dodajKoniec( lista, liczba ); wypisz( lista ); zniszcz( lista ); }
|
|
pekfos |
» 2019-09-01 23:43:59 Czy mógłbym prosić o wskazówki jak go trochę skrócić? |
Usuń z niego błędy. Masz w kodzie fragmenty których jedynym zadaniem jest wprowadzenie błędów. Błędów które już tu co najmniej raz opisywałem i tłumaczyłem, więc przeczytaj temat od początku. |
|
rottingham Temat założony przez niniejszego użytkownika |
» 2019-09-02 01:11:48 W tym kodzie jest struct Wezel zamiast Listy. Mamy użyty typedef Wezel * Lista. Czy jest potrzebny tutaj drugi struct? struct Wezel {...}; typedef Wezel * Lista;
void utworz( Lista & lista ) { lista = nullptr; }
int main() { int liczba; Lista lista; utworz( lista ) std::cout << "Podaj liczby, 0 lub blad konczy:\n"; while( std::cin >> liczba && liczba ) dodajKoniec( lista, liczba ); std::cout << "Koniec, oto liczby:\n"; wypisz( lista ); zniszcz( lista ); }
|
|
pekfos |
» 2019-09-02 23:37:51 Pytasz, bo wracasz do punktu wyjścia? Poprzedni kod jest blisko rozwiązania, wystarczy naprawić błędy. Z jakiego innego powodu byś implementował niszczenie listy 2 razy - raz zaczynając od początku i raz od końca? |
Ty niszczysz listę od początku, od końca i od lista->wezel, cokolwiek to oznacza. Czy dodanie tych wskaźników sprawiło, że alokujesz dynamicznie więcej pamięci? Nie? To zostaw je w spokoju. Po prostu je zignoruj. To znaczy, możesz je wyzerować.. ale nie wywołuj na nich delete! |
|
rottingham Temat założony przez niniejszego użytkownika |
» 2019-09-09 00:26:51 Ok. Myślę, że zrozumiałem większość błędów, które popełniałem. Napisałem kod, który chyba jest najlepszym do tej pory. Jednak mam co do niego pytania: jak napisać funkcję wypisz(), tak aby nie modyfikować wskaźnika lista->glowa? On się modyfikuje mimo, że nie ma operatora referencji. W sumie dziwi mnie to, bo dlaczego, żeby wyzerować Lista * lista potrzebuję użyć w funkcji utworz() referencji, a tutaj następuje modyfikacja bez referencji? Gdyby udało mnie się ją wypisać bez modyfikowania wskaźnika, to mógłbym w struct Lista mieć tylko dwie składowe. #include <iostream>
using namespace std;
struct Wezel { int liczba; Wezel * nastepny; };
struct Lista { Wezel * glowa, * ogon, * poczatek; };
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 = lista->poczatek = nowy; } else { lista->ogon = lista->ogon->nastepny = nowy; } }
void wypisz( Lista * lista ) { if( lista ) while( lista->glowa ) { cout << lista->glowa->liczba << " "; lista->glowa = lista->glowa->nastepny; } }
void zniszcz( Lista *& lista ) { if( lista ) { while( lista->poczatek ) { Wezel * tmp = lista->poczatek; lista->poczatek = lista->poczatek->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-09 01:04:22 Gdyby udało mnie się ją wypisać bez modyfikowania wskaźnika, to mógłbym w struct Lista mieć tylko dwie składowe. |
Skopiuj do zmiennej lokalnej? On się modyfikuje mimo, że nie ma operatora referencji. W sumie dziwi mnie to, bo dlaczego, żeby wyzerować Lista * lista potrzebuję użyć w funkcji utworz() referencji, a tutaj następuje modyfikacja bez referencji? |
Wskaźnik i referencja to prawie to samo. Przekazując Lista * lista przekazujesz wskaźnik przez wartość, ale to co jest pod wskazanym adresem możesz modyfikować, tak jakbyś to przekazał przez referencję. W języku C nawet nie było referencji, więc to void f( int & x ) { x = 123; } się robiło tak void f( int * x ) { * x = 123; } |
|
1 2 3 « 4 » 5 6 |