Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

R. 45 - zadanie domowe - pytanie do ppkt b

Ostatnio zmodyfikowano 2019-09-17 20:14
Autor Wiadomość
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()?

C/C++
#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?

C/C++
#include <iostream>

using namespace std;

struct Lista
{
    Lista * ogon;
    int liczba;
};

// Wypisz wszystkie elementy listy
void wypisz( Lista * lista )
{
    // Przechodzenie po liœcie *rekurencyjnie*
    if( lista )
    {
        cout << lista->liczba << ", ";
        wypisz( lista->ogon );
    }
}

// Dodaj element na koniec listy
Lista * dodajKoniec( Lista *& lista, int liczba, Lista * ostatni )
{
    // Tworzymy nowy element listy
    Lista * nowy = new Lista;
    nowy->liczba = liczba;
    nowy->ogon = nullptr;
   
    // Dopisujemy na koniec
    if( lista )
    {
        ostatni->ogon = nowy;
        return nowy;
    }
    else
         lista = nowy;
   
    return lista;
}


// Usuwa listê
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 );
}
P-175181
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:
C/C++
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?
P-175182
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?

C/C++
#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 );
}
P-175190
pekfos
» 2019-09-12 17:55:07
Teraz kod w ogóle nie działa. Używasz niezainicjalizowanego wskaźnika.
P-175191
rottingham
Temat założony przez niniejszego użytkownika
» 2019-09-14 21:03:08
Czy teraz jest dobrze?

C/C++
#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?
P-175202
pekfos
» 2019-09-14 22:23:36
Czy teraz jest dobrze?
Jest lepiej.. ale musiałem zrobić diffa żeby wiedzieć co w ogóle zmieniłeś. Ja miałem na myśli ten fragment
C/C++
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().
P-175203
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ę?

C/C++
#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 );
}
P-175208
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'.

Teraz chyba jest już ok?
Wygląda ok.
P-175209
1 2 3 4 « 5 » 6
Poprzednia strona Strona 5 z 6 Następna strona