Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Pino aliohjelmilla

Sivun loppuun

Zmyrgel [17.11.2005 09:33:29]

#

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";
}

coaster [17.11.2005 13:37:57]

#

Kysyisin mikä merkitys noilla &-merkeillä on tuolla funktioiden parametreissä tässä tapauksessa? Eikös pelkkä *-merkki riitä?

kuulostaa vaan aika oudolta *&-yhdistelmä.

Zmyrgel [17.11.2005 20:53:18]

#

Osoitin tyyppinen muuttujaparametri viittauksen avulla? On myös esitetty tuohon malliin Hietasen kirjassa.

rutkis [18.11.2005 10:13:16]

#

Viittauksen käyttöön riittää pelkkä &.

Metabolix [18.11.2005 16:33:54]

#

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.

Zmyrgel [19.11.2005 09:29:09]

#

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.

Metabolix [19.11.2005 12:23:37]

#

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.

Zmyrgel [19.11.2005 15:48:14]

#

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.

Metabolix [19.11.2005 19:50:55]

#

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.

rutkis [19.11.2005 20:30:47]

#

Metabolixin kanssa samoilla linjoilla.

Kaatuminen kuulostaa kovasti siltä, että yrität lukea jotakin joka on jo poistettu muistista.

uffis [19.11.2005 21:31:13]

#

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.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta