Kirjautuminen

Haku

Tehtävät

Oppaat: C++-ohjelmointi: Osa 3 - Ehdot, silmukat ja poikkeukset

  1. Osa 1 - Johdanto
  2. Osa 2 - Vakiot, muuttujat ja perustietotyypit
  3. Osa 3 - Ehdot, silmukat ja poikkeukset
  4. Osa 4 - Rakenteet, taulukot ja merkkijonot
  5. Osa 5 - Funktiot
  6. Osa 6 - Esittelyt, määrittelyt ja elinajat
  7. Osa 7 - Viittaukset, osoittimet ja dynaaminen muisti
  8. Osa 8 - Mallit
  9. Osa 9 - Luokkien perusteet
  10. Osa 10 - Luokkien erikoiset jäsenet
  11. Osa 11 - Luokkien perintä
  12. Liite 1 - C++-kehitysympäristöt
  13. Liite 2 - Valmis C++-kääntäjäpaketti

Kirjoittaja: Metabolix. Vuosi: 2009.

Yleensä on suotavaa, ettei ohjelma tee joka kerta täsmälleen samaa asiaa. Edellisen oppaan ympyräohjelma ei osaa laskea kuin ympyröitä, kun taas kunnollisen laskimen pitäisi osata suorittaa eri laskuja sen mukaan, mitä käyttäjä kirjoittaa. Tätä varten C++ sisältää if-lauseen eli ehtolauseen, jonka avulla tietty osa koodista voidaan suorittaa vain tietyn ehdon toteutuessa. Lisäksi on olemassa valintarakenne switch–case, joka liittyy läheisesti ehtolauseisiin, sekä muutama erilainen silmukka, joilla voidaan toistaa jotain koodia monta kertaa.

Ehdot

Ehtolauseeseen tarvitaan jokin ehto, ja myös silmukoita toistetaan niin kauan, kuin niiden ehto on tosi. Sana tosi esiintyi jo aiemmin bool-tietotyypin eli totuusarvon yhteydessä, ja totisesti, ehto onkin aina totuusarvo.

Totuusarvoja saadaan bool-muuttujien lisäksi matemaattisten vertailujen tuloksena. Vertailuoperaattoreita on kuusi.

merkintämerkitystosi esimerkki
a == ba ja b ovat yhtäsuuret1 + 1 == 2
a != ba ja b ovat erisuuret5 != 7
a > ba on suurempi kuin b7.5 > 3.14
a < ba on pienempi kuin b3.14 < 7.5
a >= ba on suurempi tai yhtäsuuri kuin b3 >= 3
a <= ba on pienempi tai yhtäsuuri kuin b5 <= 6

Hyvin usein totuusarvoja täytyy myös yhdistellä aiemmin esiteltyjen loogisten operaattorien avulla. Tärkeimmät merkinnät ovat || eli tai, && eli ja sekä ! eli ei:

merkintämerkitysesimerkki
e1 || e2tosi, jos e1, e2 tai molemmat ovat tosialuku < alaraja || luku > ylaraja
e1 && e2tosi, jos molemmat ehdot ovat tosialuku >= alaraja && luku <= ylaraja
!e1tosi, jos e1 on epätosi!(pii == 3)

if-lause

Tavallista ehtolausetta nimitetään aloittavan sanan mukaisesti if-lauseeksi. Syntaksi on yksinkertainen: alussa on if, tätä seuraa kaarisuluissa tarkistettava ehto, ja sulkujen jälkeen tulee koodi, joka ajetaan, jos ehto on tosi. Yksinkertainen ehtolause voi siis näyttää vaikka tältä:

if (luku % 2 == 1) std::cout << "Luku on pariton!" << std::endl;

Jos ehdon toteuduttua halutaan suorittaa useampi lause, ne täytyy kirjoittaa aaltosulkuihin. Tätä merkintätapaa voi toki käyttää lauseiden määrästä riippumatta; sulut voivat olla vaikka tyhjät tai sisältää vain yhden lauseen. Tässä aaltosulut sisältävät kuitenkin kaksi erillistä lausetta:

if (luku >= 0 && luku <= 10 && luku % 2 == 1) {
	// Tähän päästään, jos ehto toteutuu.
	std::cout << "Luku on pariton ja välillä 0 - 10!" << std::endl;
	std::cout << "Kuinkas nyt suu pannaan?" << std::endl;
}
// Muuten hypätään suoraan tänne.

Usein on tarpeen suorittaa eri koodi siinä tapauksessa, että ehto ei toteutunut. Tätä varten if-lauseeseen voi liittää else-lohkon:

#include <iostream>

int main() {
	std::cout << "Pelataanpa jalkapalloa. Montako pelaajaa on?" << std::endl;
	int pelaajia;
	std::cin >> pelaajia;
	if (pelaajia < 6) {
		// Tähän päästään, jos luku on alle 6.
		std::cout << "Pelaajia on aika vähän!" << std::endl;
	} else if (pelaajia % 2 == 0 || pelaajia > 10) {
		// Nyt else-lohko koostuu vain yhdestä if-lauseesta.
		// Jos siis ensimmäinen ehto ei toteudu, kokeillaan tätä ehtoa:
		// parillinen määrä tai yli 10 pelaajaa.
		std::cout << "Näillä pelaajilla saadaan jo aika tasaiset joukkueet." << std::endl;
	} else {
		// Tämä on jälkimmäisen if-lauseen else-lohko, johon päästään,
		// jos toinenkaan ehto ei toteudu.
		std::cout << pelaajia << " pelaajaa riittää kyllä peliin." << std::endl;
		std::cout << "Toiselle puolelle jää kuitenkin yhden ylivoima." << std::endl;
	}
	// Kaikkien vaihtoehtojen jälkeen päädytään lopulta tänne.
}

Yksinkertainen laskin

Jo yksinkertaisilla if-lauseilla saadaan aikaan paljon parempia ohjelmia kuin aiemmin. Tämä esimerkkilaskin osaa laskea yhteen- ja vähennyslaskun sekä kerto- ja jakolaskun – ja koko komeuteen tarvitaan vain neljä ehtoa!

#include <iostream>

int main() {
	// Ohjelmassa tarvitaan kaksi lukua ja laskutoimituksen merkki.
	double a, b;
	char toimitus;

	// Esitetään pyyntö ja luetaan syötteet.
	std::cout << "Anna kahden luvun lauseke, esim. 5 / 7." << std::endl;
	std::cin >> a >> toimitus >> b;

	// Tarkistetaan, onnistuiko lukeminen.
	if (!std::cin.good()) {
		// Ei onnistunut, lopetetaan ohjelma tähän ja palautetaan 1.
		std::cout << "Virhe lausekkeessa!" << std::endl;
		return 1;
	}
	// Tarkistetaan if-lauseilla, mikä lasku pitää tehdä, ja lasketaan se.
	if (toimitus == '+') {
		std::cout << "Tulos: " << (a + b) << std::endl;
	} else if (toimitus == '-') {
		std::cout << "Tulos: " << (a - b) << std::endl;
	} else if (toimitus == '*') {
		std::cout << "Tulos: " << (a * b) << std::endl;
	} else if (toimitus == '/') {
		std::cout << "Tulos: " << (a / b) << std::endl;
	} else {
		// Mikään aikaisempi lasku ei osunut, aina on jouduttu
		// else-lohkoon. Ilmoitetaan virheestä ja palautetaan 2.
		std::cout << "Tuntematon laskutoimitus!" << std::endl;
		return 2;
	}
}

Esimerkkiohjelmassa käytetty syötteen lukemisen tarkistus (std::cin.good()) käsitellään tarkemmin opassarjan myöhemmissä osissa.

switch-lause

Kun käsiteltävänä on kokonaisluku (tai merkki), jolla voi olla useita eri arvoja, jotka kaikki vaativat oman käsittelynsä, voidaan käyttää switch-lausetta. Sen voi aina korvata if-lauseilla, ja tämän vuoksi se on myös harvemmin tarpeen. Syntaksiltaan switch-lause on tällainen:

// "switch (lauseke)" aloittaa switch-lauseen.
switch (luku) {
// "case arvo:" merkitsee kohdan, johon tietyllä muuttujan arvolla päädytään.
case 0:
	std::cout << "Luku on nolla!" << std::endl;
	// break hyppää ulos switch-lauseesta
	break;
case 1:
	std::cout << "Luku on yksi!" << std::endl;
	break;
// "default:" merkitsee kohdan niille arvoille, joille ei ole omaa paikkaa.
default:
	std::cout << "Luku on " << luku << "!" << std::endl;
}

Saman asian voi esittää if-lauseilla näin:

if (luku == 0) {
	std::cout << "Luku on nolla!" << std::endl;
} else if (luku == 1) {
	std::cout << "Luku on yksi!" << std::endl;
} else {
	std::cout << "Luku on " << luku << "!" << std::endl;
}

Tehtävä: Toteuta if-lauseen yhteydessä esitelty laskin switch-lauseella. Koodista pitäisi näin tulla väljempää ja helppolukuisempaa.

Eniten hyötyä switch-lauseesta on silloin, kun on tarpeen suorittaa koodi tietystä pisteestä eteenpäin siitä riippuen, mikä muuttujan arvo on. Tällöin break-rivejä jätetään tarpeen mukaan pois, jolloin ohjelman suoritus jatkuu seuraavankin case-rivin jälkeiseen koodiin.

#include <iostream>

int main() {
	std::cout << "Mistä asti pitäisi laskea kolmeen?" << std::endl;
	int alku;
	std::cin >> alku;
	switch (alku) {
	default:
		std::cout << "Vai että " << alku << "? Taidanpa aloittaa ykkösestä." << std::endl;
		// Koska break puuttuu, suoritus jatkuu...
	case 1:
		std::cout << "Yksi..." << std::endl;
	case 2:
		std::cout << "Kaksi..." << std::endl;
	case 3:
		std::cout << "Kolme! Laskettu." << std::endl;
		// Vasta break-riviltä hypätään switch-rakenteen loppuun.
		break;
	case 4:
		// Tänne päästään vain, jos alku == 4.
		std::cout << "Nelonenhan tulee kolmosen jälkeen!" << std::endl;
		// Lopussa ei tarvita break-riviä.
	}
}

Todellinen esimerkki tällaisesta tilanteesta ovat SDL:n ja OpenGL:n yhteiskäyttö -opassarjan esimerkkiohjelman funktiot sulje_SDL ja sulje_OGL.

?:-operaattori

Joskus if-lause on liikaa, kun tarvitsee tehdä vain aivan pieni muutos jonkin ehdon mukaan. Tällöin voi käyttää ?:-operaattoria (engl. ternary operator). Ensin tulee ehto, sitten tulee ?, tätä seuraa lausekkeen arvo, jos ehto toteutui, ja kaksoispisteen perään tulee arvo, jos ehto ei toteutunut. Arvot voivat olla mitä tahansa tavallisia lausekkeita, mutta tuloksen tietotyypin pitää kummassakin olla sama.

int a = 1, b = 2, c = 3;
// jos a < 10, d = b, muuten d = c;
int d = (a < 10 ? b : c);
// lasketaan itseisarvo lausekkeen keskellä
std::cout << "Luvun " << d << " itseisarvo on " << (d < 0 ? -d : d) << std::endl;

Eniten hyötyä tästä rakenteesta on yleensä silloin, kun jokin pieni muutos täytyy tehdä pitkän lausekkeen keskellä. Kannattaa kuitenkin varoa, ettei lausekkeesta tule liian sekava! Usein on parempi käyttää välituloksia.

Silmukat

Silmukan ajatuksena on toistaa tiettyä koodia, kunnes päästään haluttuun tilanteeseen. Esimerkiksi laskin voisi pyytää uusia lukuja ja operaatioita, kunnes käyttäjä valitsee operaation "sulje ohjelma", ja C++-kääntäjä lukee kooditiedostoa, kunnes tiedostosta löytyy virheitä tai se loppuu. Jo näistä tapauksista käyvät ilmi silmukan keskeiset osat: toistettava sisältö ja toistamista rajoittava ehto.

while-silmukka

Ajatukseltaan yksinkertaisin C++:n silmukoista on while-silmukka. Se muistuttaa syntaksiltaan if-lausetta, mutta jos ehto on tosi ja koodi suoritetaan, hypätäänkin lopuksi vielä takaisin alkuun. Koodi toistuu niin kauan, kuin ehto pysyy totena. Seuraava koodi kertoo luultavasti kaiken olennaisen tästä:

#include <iostream>

int main() {
	const int luku = 10;
	int arvaus;
	std::cout << "Arvaa luku!" << std::endl;
	std::cin >> arvaus;
	while (luku != arvaus) {
		if (luku < arvaus) {
			std::cout << "Luku on pienempi!";
		} else {
			std::cout << "Luku on suurempi!";
		}
		std::cout << " Arvaa uudestaan." << std::endl;
		std::cin >> arvaus;
	}
	std::cout << "Arvasit oikein, luku oli " << luku << "." << std::endl;
}

Silmukka on mahdollista kirjoittaa myös niin päin, että while ja ehto ovatkin silmukan lopussa. Tällöin silmukan alkuun tulee sana do, minkä vuoksi rakennetta kutsutaan myös do-silmukaksi. Tässä muodossa silmukan koodi suoritetaan yhden kerran jo ennen ehdon tarkistamista. Äskeisen luvunarvausohjelman voisi toteuttaa myös näin:

#include <iostream>

int main() {
	const int luku = 10;
	int arvaus;
	do {
		std::cout << "Arvaa luku!" << std::endl;
		std::cin >> arvaus;
		if (luku < arvaus) {
			std::cout << "Luku on pienempi!" << std::endl;
		} else if (luku > arvaus) {
			std::cout << "Luku on suurempi!" << std::endl;
		}
	} while (luku != arvaus);
	std::cout << "Arvasit oikein, luku oli " << luku << "." << std::endl;
}

for-silmukka

Toinen silmukka, for-silmukka, poikkeaa while-silmukasta siten, että sen alussa annetaan ehdon lisäksi ennen silmukkaa ja kunkin kierroksen lopussa suoritettavat lyhyet koodit. Tyypillisesti alkuun tulee silmukassa käytettävän muuttujan alustus ja loppuun muuttujan arvon muuttaminen. Seuraavassa silmukassa määritellään ja alustetaan ensin muuttuja i. Silmukkaa toistetaan niin kauan, kuin i on alle 10, ja joka kierroksen lopussa arvoa kasvatetaan yhdellä.

for (int i = 0; i < 10; ++i) {
	std::cout << i << std::endl;
}

Mikään for-silmukan osa ei ole välttämätön.

// Jos silmukassa on vain ehto, se vastaa täysin while-silmukkaa.
for (; i < 10;) { }
while (i < 10) { }

// Ilman ehtoa silmukasta tulee ns. ikuinen silmukka.
for (;;) { }
for (; true;) { }
while (true) { }

Minkä tahansa for-silmukan voi korvata while-silmukalla. Seuraavat kaksi silmukkaa toimivat täsmälleen samalla tavalla. (Ylimääräiset sulut while-silmukan ympärillä liittyvät muuttujien elinaikoihin. Asiasta kerrotaan lisää myöhemmin.)

for (alku; ehto; loppu) {
	koodi;
}

{
	alku;
	while (ehto) {
		koodi;
		loppu;
	}
}

Tyypillinen for-silmukan käyttötarkoitus on koodin toistaminen tietylle arvojoukolle tai tietty määrä kertoja. Äskeisessä esimerkissä silmukka toistetaan luvuille 0–9, ja opassarjan myöhemmissä osissa for-silmukalla mm. käydään läpi taulukoita, listoja ja muita tietorakenteita. Seuraavassa esimerkissä silmukkaa käytetään potenssilaskuun: x potenssiin n tarkoittaa, että n kappaletta lukuja x kerrotaan keskenään.

#include <iostream>

int main() {
	double kanta;
	int eksponentti;
	std::cout << "Anna kantaluku ja kokonaiseksponentti: ";
	std::cin >> kanta >> eksponentti;

	// 0 potenssiin 0 on määrittelemätön, joten käsitellään se erikseen.
	if (kanta == 0 && eksponentti == 0) {
		// Tulostetaan virheilmoitus ja lopetetaan ohjelma.
		std::cout << "Laskulle ei ole tulosta!" << std::endl;
		return 0;
	}

	// Lasketaan negatiivinen potenssi käänteisluvun avulla.
	// n**(-e) = (1/n)**e, missä ** on potenssilasku.
	if (eksponentti < 0) {
		eksponentti = -eksponentti;
		kanta = 1 / kanta;
	}

	// Nollas potenssi on aina yksi.
	double tulos = 1;

	// Eksponentti määrää, montako kertaa kantaluku pitää kertoa.
	for (int i = 0; i < eksponentti; ++i) {
		tulos *= kanta;
	}

	std::cout << "Potenssilaskun tulos on " << tulos << std::endl;
}
/**
 * Tehtävä:
 * Keksitkö, miten potenssifunktiota saisi parannettua niin, että silmukassa
 * ei tarvitsisi suurellakaan eksponentilla kiertää kuin muutama kierros?
 *
 * Vihje: a**9  ==  a * a**8  ==  a * (((a**2)**2)**2)
 */

break ja continue

Jos on tarve keskeyttää silmukka kesken kaiken, voi käyttää break-lausetta, joka hyppää suoraan ulos sisimmästä suoritettavasta silmukasta. Tämän pari on continue, joka hyppää silmukan viimeiselle riville eli käytännössä seuraavalle kierrokselle, jos ehto yhä toteutuu. Näiden kahden avulla luvunarvausohjelman voi kirjoittaa taas uudessa muodossa:

#include <iostream>

int main() {
	const int luku = 10;
	while (true) {
		std::cout << "Arvaa luku!" << std::endl;
		int arvaus;
		std::cin >> arvaus;
		if (luku < arvaus) {
			std::cout << "Luku on pienempi!" << std::endl;
			continue;
		}
		if (luku > arvaus) {
			std::cout << "Luku on suurempi!" << std::endl;
			continue;
		}
		std::cout << "Arvasit oikein, luku oli " << luku << "." << std::endl;
		break;
	}
}

Muuttujan määrittely ehtona

Harvemmin käytetty temppu on laittaa if-, switch-, while- tai for-lauseeseen ehdoksi uuden muuttujan määrittely ja alustus. Koodi toimii samalla tavalla kuin silloin, jos muuttuja määriteltäisiin ja alustettaisiin etukäteen ja ehtona olisi vain muuttujan nimi. Ainoa ero on, että ehdossa määritelty muuttuja on olemassa vain lauseen sisällä, aivan kuten for-silmukan alussa määriteltävä muuttuja. Seuraavat kaksi rakennetta ovat siis täsmälleen toisiaan vastaavat:

if (int luku = 10) {
	koodi;
}

{
	int luku = 10;
	if (luku) {
		koodi;
	}
}

try, catch ja throw

C++ sisältää välineet myös virhetilanteiden käsittelyyn. Ohjelma voi ongelmatilanteessa heittää poikkeuksen (engl. exception) eli eräänlaisen virheilmoituksen throw-lauseella, ja jos tämä tapahtuu try-lohkon sisällä, ohjelma hyppää suoraan sopivaan catch-lohkoon eli virheenkäsittelijään. Usein poikkeus on standardikirjaston exception-luokasta peritty olio, mutta myös tavalliset luvut ja tekstit sopivat. Jokainen virheenkäsittelijä käsittelee yhden poikkeustyypin, ja lisäksi on mahdollista kirjoittaa yleinen käsittelijä, joka ajetaan, jos muut eivät sovi. Jos try-lohkoja on monta sisäkkäin, virheenkäsittelijää etsitään ensin sisimmästä, ja jos siitä ei löydy, siirrytään ulompiin try-lohkoihin. Jos missään ei ole sopivaa käsittelijää, ohjelman suoritus loppuu.

Samaa rakennetta on mahdollista käyttää myös tietynlaiseen paikasta toiseen siirtymiseen, mutta se on huono ohjelmointitapa, koska rakenteen on tarkoitus auttaa juuri virheiden käsittelyssä. Seuraavassa esimerkissä tätä huonoa tapaa on kuitenkin käytetty, jotta tähän mennessä opetetuilla asioilla saataisiin esiteltyä komentorakennetta mahdollisimman kattavasti. Virheenkäsittelyyn palataan vielä pikaisesti funktioiden yhteydessä ja tarkemmin vasta, kun tutustutaan standardikirjaston exception-luokkaan.

#include <iostream>

// Aivan kuten tulostusta (std::cout yms.) varten tarvitaan iostream-otsikko,
// matemaattisia funktioita (sqrt eli neliöjuuri, pow eli potenssilasku yms.)
// varten tarvitaan cmath-otsikko. Esimerkissä käytetään funktioita std::floor
// ja std::pow.
#include <cmath>

int main() {
	double a, b;
	char m;
	try {
		std::cout << "Kirjoita lasku, esim. 1.4 / 2.2." << std::endl;
		std::cin >> a >> m >> b;
		if (!std::cin.good()) {
			// Suoritus siirtyy throw-riviltä sopivaan catch-lohkoon.
			throw "viallinen syöte";
		}
		std::cout << a << ' ' << m << ' ' << b << std::endl;
		switch (m) {
			// Palautetaan laskun tulos heittämällä.
			// Tämä ei ole hyvä ohjelmointitapa!
			case '+': throw a + b;
			case '-': throw a - b;
			case '*': throw a * b;
			case '/':
				// Virhetilanteissa heitetään virheteksti.
				// Tämä on järkevä tapa käyttää poikkeuksia.
				if (b == 0) {
					throw "jakaja on nolla";
				}
				throw a / b;
			case '^':
				if (a == 0 && b == 0) {
					throw "nolla potenssiin nolla, määrittelemätön";
				}
				// std::floor pyöristää luvun alaspäin
				if (a < 0 && std::floor(b) != b) {
					throw "negatiivinen luku ja desimaalieksponentti";
				}
				// std::pow(a, b) laskee laskun a potenssiin b.
				throw std::pow(a, b);
			default:
				throw "tuntematon lasku";
		}
		// Suoritus siirtyy try-lohkon lopusta rakenteen loppuun,
		// eli seuraava suoritettava rivi on lopun tulostusrivi.
	} catch (double vastaus) {
		// Otetaan double-arvo kiinni.
		// Tätä nyt käytettiin vastauksen toimittamiseen.
		std::cout << "Tulos: " << vastaus << std::endl;
		// Suoritus siirtyy catch-lohkosta rakenteen loppuun,
		// eli seuraava suoritettava rivi on lopun tulostusrivi.
	} catch (const char* teksti) {
		// Otetaan tekstivakio eli const char* kiinni.
		// Tulostetaan virheilmoitus ja lopetetaan. Kun main-funktiossa
		// suoritetaan return-lause, koko ohjelma sulkeutuu.
		// Paluuarvo 1 viestii, että ohjelmassa on tapahtunut virhe.
		std::cout << "Virhe: " << teksti << std::endl;
		return 1;
	} catch (...) {
		// Tämä käsittelijä käsittelee poikkeukset, jotka eivät
		// sopineet muiden käsittelijöiden tyyppeihin.
		std::cout << "Tuntematon virhe tuntemattomasta lähteestä!" << std::endl;

		// Poikkeuksen voi aina heittää eteenpäin tyhjällä throw'lla.
		// Jos try-lohkoja on monta sisäkkäin, sopivaa käsittelijää
		// etsitään seuraavaksi ulommista try-lohkoista.
		// Nyt ollaan kuitenkin uloimmassa (ainoassa) try-lohkossa,
		// joten ohjelman suoritus päättyisi virheeseen. Tänne ei
		// kuitenkaan tässä ohjelmassa jouduta, koska kaikki heitetyt
		// poikkeukset ovat double- tai const char* -tyyppisiä.
		throw;
	}
	std::cout << "Jos haluat laskea lisää, aja ohjelma uudestaan." << std::endl;
}

goto

Vanhoissa kielissä on yleensä myös hyppykäsky, jolla pääsee mihin tahansa ohjelmassa. Myös C++ sisältää hyppykäskyn goto. Sillä voi hypätä toiseen kohtaan ohjelmassa tietyin rajoituksin: Hyppykohde täytyy nimetä ja sen täytyy olla samassa funktiossa. Hyppy ei myöskään saa ohittaa muuttujan määrittelyä, jos muuttujalle annetaan samalla alkuarvo (tai jos kyseessä on olio; näistä kerrotaan myöhemmin).

Holtiton hyppiminen on huono ohjelmointitapa, ja on ensisijaisen tärkeää muistaa, että goto-lauseen ei ole tarkoitus korvata silmukoita puhumattakaan funktioista, vaan sitä tulee käyttää vain silloin, kun muut tavat eivät ole loogisia tai tuottavat huomattavasti ylimääräistä koodia.

Yksi toisinaan mielekäs käyttötarkoitus on useasta silmukasta pois hyppääminen:

#include <iostream>

int main() {
	// Taulukko; näistä kerrotaan lisää myöhemmin.
	int taulu[10][10] = {{0}, {0, 0, 13}};

	int i, j;
	for (i = 0; i < 10; ++i) {
		for (j = 0; j < 10; ++j) {
			// Verrataan taulukon lukua kohdassa (i, j) lukuun 13.
			if (taulu[i][j] == 13) {
				// Hypätään pois, jos luku on 13.
				goto loytyi_13;
			}
		}
	}
	// Tämä ehtolause on aina epätosi.
	if (false) {
		// Sisään pääsee kuitenkin hyppäämällä.
		loytyi_13:
		std::cout << "Luku 13 löytyi kohdasta (" << i << ", " << j << ")!" << std::endl;
	}
}

Kommentit

alottelijaa [18.08.2009 22:35:47]

Lainaa #

Hyvä opas ^^

Tajusin vihdoin miten poikkeuksia käytetään esimerkin ansiosta.

ZuuZou [05.01.2010 03:31:40]

Lainaa #

Tämähän on uutta että olen pysynyt kärryillä! Kiitos hyvästä oppaasta tästä oli paljon hyötyä.

anton1234 [18.05.2010 18:02:50]

Lainaa #

#include <iostream>

int main()
{

mina:
std::cout << "oon paras" << std::endl;
goto mina;
}

Epätoivoinen [07.01.2011 18:20:37]

Lainaa #

Kiitos hyvästä oppaasta, jonka ansiosta olen päässyt nopeasti alkuun!
Minua jäi kuitenkin askarruttamaan eräs, ehkä vielä tässä vaiheessa täysin merkityksetönkin seikka: Mitä toi #include tarkottaa? Tai millon ohjelman alkuun pitää lisätä vaikkapa #include <cmath>?

Metabolix [07.01.2011 21:19:55]

Lainaa #

Epätoivoinen kirjoitti:

Mitä toi #include tarkottaa?

#include-rivistä mainitaan ensimmäisessä oppaassa ja kerrotaan tarkemmin oppaassa C:n esikääntäjästä. Se liittää lähdekoodin sekaan toisen tiedoston sisällön. (Tässä käytetyt tiedostot ovat tulleet kääntäjän mukana.)

Epätoivoinen kirjoitti:

Tai millon ohjelman alkuun pitää lisätä vaikkapa #include <cmath>?

Eri otsikkotiedostoissa on eri asioita. Esimerkiksi otsikossa cmath esitellään (ks. osa 6) matemaattisia funktioita (sin, cos, tan, pow) ja otsikossa iostream esitellään tekstin lukemiseen ja tulostamiseen liittyviä asioita kuten std::cout ja std::endl. Tarkempaa tietoa eri otsikkotiedostoista löytyy mm. sivustolta cplusplus.com, ja joitain tärkeimpiä on tarkoitus joskus koota tämän opassarjan liitteeksikin.

Epätoivoinen [08.01.2011 18:19:08]

Lainaa #

Ok kiitos!

erkki4 [07.08.2011 23:09:23]

Lainaa #

Mitäs tuossa pidemmässä laskin-esimerkissä meinaa tuo tähtimerkki kun lopussa mainitaan tuo const char*?

Metabolix [11.08.2011 19:44:29]

Lainaa #

Se tarkoittaa osoitinta. Merkkijonoista kerrotaan opassarjan seuraavassa osassa ja osoittimista laajemmin pari osaa myöhemmin. Asiaa ei siis tarvitse vielä ymmärtää; pääasia on, että tuo merkintä sopii merkkijonon käsittelyyn.

TVdata [30.11.2011 18:20:07]

Lainaa #

Voiko eteenpäin hypätä goto:lla?

Metabolix [01.12.2011 00:13:24]

Lainaa #

TVdata: No mitähän tuossa oppaan esimerkissä juuri tehdään? Voisit edes lukea ennen kysymistä.

TVdata [01.12.2011 13:42:02]

Lainaa #

Antaa olla, en ajatellut loppuun.

sakkeboy [17.12.2011 12:31:21]

Lainaa #

Goto-käyskyä ei olisi hyvä käyttää, koska sillä on helppo tehdä sekavaa koodia ja rikkoo (c-kielen) rakenteisen tavan tehdä koodia, sanoo minua viisaammat koodarigurut. Parempi ois käyttää muita ehtolauseita.

ljlassi [11.04.2012 20:40:02]

Lainaa #

sakkeboy kirjoitti:

Goto-käyskyä ei olisi hyvä käyttää, koska sillä on helppo tehdä sekavaa koodia ja rikkoo (c-kielen) rakenteisen tavan tehdä koodia, sanoo minua viisaammat koodarigurut. Parempi ois käyttää muita ehtolauseita.

Noh, goto voi helpottaa tekemistä todella paljon joissain tilanteissa. Etenkin jos joudut hyppimään paljon koodissa saman funktion sisällä tulee goton käyttäminen paljon helpommaksi kuin tehdä lukematon määrä "kertakäyttöisiä" funktioita.

Ohjelmointigurujen varoitukset johtuvatkin varmaan juuri siitä, että vanhimmissa kielissä ei ollut funktioita, vaan sama toiminnallisuus haettiin käyttämällä gotoa, joten monet vanhan kaartin koodarit rupeasivat luonnostaan tekemään kaiken goto:lla ellei siitä erikseen varotettaisi.

Jopoxi [16.04.2017 15:55:18]

Lainaa #

Arvaa luku koodiin, mikset tehnyt randomia esimerkkiin vaan kiinteän luvun jonka ohjelmoija antaa?

Metabolix [16.04.2017 20:16:09]

Lainaa #

Jopoxi kirjoitti:

Arvaa luku koodiin, mikset tehnyt randomia esimerkkiin vaan kiinteän luvun jonka ohjelmoija antaa?

Koodissa esitellään while-silmukkaa. On helpompi keskittyä koodin olennaiseen asiaan (eli while-silmukkaan), kun koodissa ei ole ylimääräisiä ominaisuuksia. Koodin ei ole tarkoitus esitellä mitään optimaalista arvauspeliä.

Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea keskustelun ohjeet.
Tietoa sivustosta