Yritän osoittimien käyttöä ja muistin varaamista harjoitella. Tein ohjelmaa joka tallentaa henkilön nimen ja iän muistiin sitä mukaan kun uusia henkilöitä syötetään.
#include <cstdlib> #include <iostream> #include <string> using namespace std; class Jono { public: Jono(); ~Jono(); void lisaaHenkilo(string nimi, int ika); void tulosta() const; private: struct Henkilo { string nimi; int ika; Henkilo* seuraava; }; Henkilo* eka; }; Jono::Jono() { eka = new Henkilo; } Jono::~Jono() { } void Jono::lisaaHenkilo(string nimi, int ika) { eka -> nimi = nimi; eka -> ika = ika; } //pitäisi tulostaa kaikki henkilöt void Jono::tulosta() const { cout << "Nimi: " << eka -> nimi << " Ikä: " << eka -> ika << endl; } int main() { string nimi; int ika = 0; Jono uusi; while (true) { cout << "Nimi: "; cin >> nimi; cout << "Ikä: "; cin >> ika; uusi.lisaaHenkilo(nimi, ika); uusi.tulosta(); } return EXIT_SUCCESS; }
Miten tuota saisi laajennettua niin että tulostaisi kaikki syötetyt henkilöt?
Katsopa linkitettyihin listoihin mallia matopelioppaasta. Etsi kohdat, joissa mainitaa lista tai jaoke. (Jaoke tarkoittaa yhtä madon osaa.)
Nyt ohjelmassasi on tasan yksi henkilö. Oikeasti kuuluisi aina lisätessä luoda uusi henkilö ja muokata osoittimet järkevästi – kannattaa suunnitella paperilla. Linkitetyn listan päättymisen tunnistaa 0-osoittimesta. Muista myös tuhota kaikki henkilöt lopussa, nyt delete näyttää puuttuvan.
Ohjelmasi toimii virheellisesti. Nyt et varaa lainkaan uudelle henkilölle muistia, vaan korvaat eka
-henkilön tiedot aina kun uusi henkilö "lisätään" eli vanha henkilö korvaantuu aina uudella. Tämän voi korjata niin, että varaat henkilön lisäyksessä muistin uudelle henkilölle (kuten olet konstruktorissa jo tehnyt), asetat uuden seuraava
-osoittimeksi NULL ja etsit listasta paikan, johon uusi henkilö voidaan lisätä (eli alkion, jonka seuraava
on NULL [tällöin alkio menee listan viimeiseksi]). Samalla periaatteella voit käydä myös listan läpi eli siirryt ensimmäisestä alkiosta lähtien aina seuraavaan alkioon niin kauan kunnes seuraava
on NULL.
Edellä kuvattu toiminnallisuus on oikeastaan linkitetty lista, koska jonossa on tiedossa ensimmäinen ja viimeinen alkio, mutta periaate on sama. Muista vapauttaa myös jokaisen alkion muisti, se voidaan hoitaa samalla tavalla käymällä lista läpi.
Kiitos avusta!
Tulostaminen hieman vielä epäselvää. Eli miten "liikun" seuraavaan osoittimeen.
void Jono::tulosta() const { //sain alla olevan toimimaan ok cout << "Nimi: " << eka -> nimi << endl; cout << "Nimi: " << eka -> seuraava -> nimi << endl; //miten nuo käydään silmukassa läpi? while (eka->seuraava != 0) { } }
Sinun ei kuulu muokata eka-osoitinta vaan käyttää väliaikaista muuttujaa, kuten oppaani for-silmukassa.
for (Henkilo* h = eka; h != 0; h = h->seuraava) { // Tulosta h. } Henkilo* h = eka; while (h != 0) { // Tulosta h. h = h->seuraava; }
Lisäksi tuon voi ensin toteuttaa ihan standardikirjaston std::list rakenteella toimivaksi ohjelmaksi, jonka jälkeen toteuttaa itse listan jollekin rakenteelle, ja lopuksi vaikka geneerisesti "kaikille" tyypeille. Tärkeintä kai olisi saada ensin rungoltaan toimiva rakenne, jotta opettelu olisi mielekästä.
Osoittimet vaikeita ymmärtää minulle, mutta sain tuon toimimaan niin kuin halusin =) Kiitos
Aihe on jo aika vanha, joten et voi enää vastata siihen.