Tälläinen ongelma. Eli pinon käyttö aliohjelmilla aiheena. Tälläiset funktiot olen saanut kyhättyä ja ongelmaksi on muodostunut pinosta poistaminen. Tämän hetkisiksi ongelmiksi on jäänyt seuraavat asiat jotka johtaa ohjelman kaatumiseen:
1) Tulostaa tyhjän pinon
2) Tulostaa pinon johon on tyhjennyksen jälkeen lisätty jotain
3) Poistaa tyhjästä pinosta
Virheet johtuvat noista p_alku osoittimesta lähes 100% mutta nyt kyselisinkin näkyykö tuosta suoraan mikä on pielessä?
struct Alkio { int luku; Alkio *seuraava; }; Alkio *alku = NULL; //tulosta pino if(alku) TulostaPino(alku); else cout << "Pino on tyhj\x84!\n";
Alkio Pop(Alkio *&p_alku) { //Poista pinon päällimmäinen tieto Alkio *kohdalla; kohdalla = p_alku; if (kohdalla) { if(kohdalla->seuraava) p_alku = kohdalla->seuraava; delete kohdalla; } else { cout << "Ei ole poistettavaa lukua!\n"; } return(*p_alku); } void TulostaPino(Alkio *& p_alku) { //Tulosta pinon sisältö Alkio *kohdalla; if(p_alku) { kohdalla = p_alku; //Laitetaan osoitin osoittamaan alkuun while(kohdalla) { cout << "\nLuku: " << kohdalla->luku; //tulostetaan kohdan luku kohdalla = kohdalla->seuraava; //siirrytään seuraavaan kohtaan } } else cout << "Pino on tyhj\x84!\n"; }
Kysyisin mikä merkitys noilla &-merkeillä on tuolla funktioiden parametreissä tässä tapauksessa? Eikös pelkkä *-merkki riitä?
kuulostaa vaan aika oudolta *&-yhdistelmä.
Osoitin tyyppinen muuttujaparametri viittauksen avulla? On myös esitetty tuohon malliin Hietasen kirjassa.
Viittauksen käyttöön riittää pelkkä &.
Kyllä tuossa nimenomaan tarvitaan osoitinta. Viittaus on puolestaan aivan turha ainakin jälkimmäisessä. Ensimmäisessäkin korvaisin sen kaksinkertaisella osoituksella.
Käy paperilla läpi kaiken toiminta niin kuin se koodissa on, niin löydät varmasti puutteen jos toisenkin. Lähinnä asioiden käsittelyjärjestykseen viittaan; Pop näyttäisi palauttavan sen, joka on päällimmäisenä poiston jälkeen.
Muista ensimmäistä alkiota varatessa alustaa sen "seuraava" nollaksi. Se ei mene itsestään. Luulen, että se ratkaisee melkein kaikki ongelmat.
Metabolix kirjoitti:
Käy paperilla läpi kaiken toiminta niin kuin se koodissa on, niin löydät varmasti puutteen jos toisenkin. Lähinnä asioiden käsittelyjärjestykseen viittaan; Pop näyttäisi palauttavan sen, joka on päällimmäisenä poiston jälkeen.
Eikö sen nimenomaan pidä se palauttaa? Ainakin omassa koodissani. Pistän tuon Push-funktion niin näkee että lisään arvot pinon alkuun enkä sen päähän.
lainaus:
Muista ensimmäistä alkiota varatessa alustaa sen "seuraava" nollaksi. Se ei mene itsestään. Luulen, että se ratkaisee melkein kaikki ongelmat.
Eikö tuokin tapahdu ihan oikein tuossa push funktiossa mutta tuossa varmaan piilee se ongelma. Jos pinon tyhjentää ja siihen lisää arvoja niin se antaa pinon ensimmäiseksi arvoksi jonkun -5 miljoonaa ja loput arvot tulevat sitten oikein mutta ohjelma kaatuu sillä p_alku osoittaa minne sattuu.
void Push(Alkio *&p_alku, int tieto) { // Tallenna tieto pinon päälle Alkio *uusi = new Alkio; if (uusi) //Jos tilanvaraus onnistuu { uusi->luku = tieto; uusi->seuraava = NULL; if (!p_alku) p_alku = uusi; else { uusi->seuraava = p_alku; p_alku = uusi; } } }
tuo Pop-funktion if-lause on tätä nykyä muotoa
if (kohdalla){ p_alku = kohdalla->seuraava; // Siiretään alkion arvo talteen delete kohdalla; // ja poistetaan ko. alkio ja }
edit: Coutilla kun selvittelee tilannetta niin ohjelma kaatuu jos yrittää sijoittaa p_alkuun NULL arvon minkä se tarvitsee että muut aliohjelmat osaa tarkistaa oikein saako ne suorittaa.
edit: Pitäisikö tuo Push-funktion palautusarvo saada sijoitettua alku- pointteriksi? Ei ainakaan suoraan huoli tälläistä operaatiota.
Tuo uudenlainen if-lause auttaa jo paljon.
Jos p_alku on Pop-funktion lopussa NULL, et voi palauttaa sen osoittamaa alkiota.
Tulostusfunktio on minusta ristiriidassa noiden muiden kanssa sen pällimmäisen alkion osalta. En kylläkään testannut, mutta siltä se minusta näyttää.
Kun ohjelma kaatuu, kannattaa lukea sen antama virhe ja kertoa se täällä. Se auttaa ihmeesti.
Metabolix kirjoitti:
Tuo uudenlainen if-lause auttaa jo paljon.
Jos p_alku on Pop-funktion lopussa NULL, et voi palauttaa sen osoittamaa alkiota.
Eli kannattaa palauttaa virhekoodi ja sijoittaa pääohjelmassa alku-pointterin arvoon NULL suoraan?
Metabolix kirjoitti:
Tulostusfunktio on minusta ristiriidassa noiden muiden kanssa sen pällimmäisen alkion osalta. En kylläkään testannut, mutta siltä se minusta näyttää.
Metabolix kirjoitti:
Kun ohjelma kaatuu, kannattaa lukea sen antama virhe ja kertoa se täällä. Se auttaa ihmeesti.
jep, ohjelma kaatuu juuri ennen tuon p_alku arvon palautusta. Se näyttäisi nollaantuvan ihan oikein mutta sen jälkeen ohjelma kaatuu ja kysyy haluaako lähettää Microsoftille virheraportin.
Kokeilen nyt tuota virhekoodi tapaa jos sen saisi toimimaan toivotulla tavalla.
Edit: Jep, homma toimii mallikkaasti kun muutti pop-funktion paluuarvoksi integerin jonka mukaan pääohjelmassa sitten muutetaan alku pointterin arvo NULLiin.
Kai XP sentään kertoo, mikä meni vikaan? Käsky osoitteessa ... viittasi muistiin osoitteessa X. Muisti ei voi olla "read". Suunnilleen tuollainen sieltä yleensä tulee, ja silloin tuosta muistin osoitteesta voi päätellä seuraavaa:
0x00000000: Jokin osoitin on NULL ja yrität lukea sieltä.
Muu arvo: Poistit muuttujan ja yrität vielä käyttää sitä tai olet asettanut osoittimen osoittamaan jonkin funktion palautusarvoon.
Metabolixin kanssa samoilla linjoilla.
Kaatuminen kuulostaa kovasti siltä, että yrität lukea jotakin joka on jo poistettu muistista.
Osoitinviittauksen käyttö osoittimen osoittimen sijaan on C++:n ollessa kyseessä kannattavampaa mielestäni jo senkin takia, että sen tarkoitus on helpommin ymmärrettävissä: parametrina annettu osoitin on sellainen, jonka sisältöä halutaan muuttaa aliohjelmassa.
Tuota kun vertaa siihen, miten osoittimen osoittimen käyttö ymmärretään, mikä on oman kokemukseni mukaan erityisesti aloittelijoille hankalaa, on mielestäni osoitinviittauksen käyttö perusteltua.
Muistan myös kuulleeni, että ainakin tietyissä ympäristöissä viittauksen käyttö olisi selkeästi nopeampaa kuin osoittimen.
Aihe on jo aika vanha, joten et voi enää vastata siihen.