2. Ohjausrakenteet Ohjausrakenteiden avulla ohjataan ohjelman suoritusta. peräkkäisyys valinta toisto Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin. 25
Ehtorakenne Ehtolause ilmaistaan loogisen lausekkeen avulla, tuloksena totuusarvo. C99-standardissa tuli mukaan oma tietotyyppi bool. Totuusarvot on määritelty: true false Toteutettu kokonaisluvuilla (true saa arvon 1 ja false arvon 0): bool ok = false; printf("ok = %d\n", ok); tulostaa: ok = 1 26
C-kielen vertailuoperaattorit Operaattori Merkitys < pienempi kuin > suurempi kuin <= pienempi tai yhtäsuuri >= suurempi tai yhtäsuuri == sama kuin!= eri kuin 27
Loogiset operaattorit C-kielessä on käytössä kolme loogista operaattoria && looginen JA ( AND ) looginen TAI ( OR )! looginen negaatio (NOT) 28
JA-operaattorin totuustaulu (&&) operandi1 operandi2 operandi1 && operandi2 true (1) true(1) true (1) true (1) false (0) false (0) false (0) true (1) false (0) false (0) false (0) false (0) 29
TAI -operaattorin totuustaulu ( ) operandi 1 operandi 2 operandi1 operandi2 true (1) true (1) true (1) true (1) false (0) true (1) false (0) true (1) true (1) false (0) false (0) false (0) 30
EI-operaattori totuustaulu (! ) operandi1!operandi true (1) false (0) false (0) true (1) DeMorganin teoreema: lausekkeen expr1 && expr2 komplementti kirjoitetaan muotoon comp1 comp2, jossa comp1 on expr1:n komplementti ja comp2 on expr2:n komplementti. lausekkeen expr1 expr2 komplementti kirjoitetaan muotoon comp1 && comp2, jossa comp1 on expr1:n komplementti ja comp2 on expr2:n komplementti. 31
Esimerkkejä: lausekkeen ika > 25 && ( status == 'S' status == 'E' ) komplementti voidaan kirjoittaa muodossa ika <= 25 ( status!= 'S' && status!= 'E' ) jos 'S' tarkoittaa sinkkua ja E eronnutta niin ylempi lauseke voidaan tulkita siten, että ehto on tosi, jos henkilön ikä on yli 25 vuotta ja hän joko sinkku tai eronnut alempi lauseke voidaan tulkita siten, että ehto on tosi, jos henkilön ikä on 25 tai vähemmän tai jos hän on avioliitossa. 32
Operaattoreiden laskentajärjestys C-kielen operaattoreiden laskentajärjestys on seuraava Operaattori suoritusjärjestys funktion kutsu korkein! + - (unaarit) * / % + - < <= >= > ==!= && = alhaisin Sulkuja käyttämällä voidaan suoritusjärjestystä muuttaa. 33
Merkkien vertailu C-kielessä voidaan merkkitietoa vertailla Esimerkiksi Lauseke '9' >= '0' 'a' < 'e' 'B' <= 'A' 'Z' == 'z' arvo true true false false 34
Looginen sijoituslause on_valilla = (n > -10 && n < 10); on_kirjain = ('A'<=ch && ch<='z') ('a' <= ch && ch <= 'z'); parillinen = (n % 2 == 0); 35
if-rakenne if-rakenteen avulla valitaan ehdon perusteella toinen kahdesta vaihtoehdosta C-kielen if-lauseen rakenne if(ehto ){ lauseita } else{ lauseita } 36
Esimerkkiohjelma if-rakenteen käytöstä #include <stdio.h> /* syöttö- ja tulostusfunktiot */ int main(void){ int luku; printf("anna kokonaisluku :"); scanf("%d", &luku ); if(luku == 100){ printf("luku on sata"); } else{ printf("luku ei ole sata\n"); printf("luku on %d", luku ); } }/* main-funktion loppu */ 37
if-rakenteesta voi puuttua else-haara. Koska C-kielessä totuusarvot kuitenkin ovat lukuja, voi helposti syntyä hankalasti havaittava virhe int tulos = 0; if(tulos = 100){ printf("sait täydet sata pistettä ja papukaijamerkin!"); } Ohjelma tulostaa aina tekstin "Sait sata pistettä...", koska muuttujaan tulos sijoitetaan luku 100. Koska luku 100 on eri kuin 0, tulkitaan lausekkeen arvoksi aina true! 38
Esimerkkiohjelma, jossa käytetään funktion kutsua ehtolausekkeessa. #include <stdio.h> #include <stdbool.h> #include <ctype.h> int main(void){ printf(" Paina jotain näppäintä"); /* luetaan käyttäjän näppäimen painallus */ if((toupper(getchar()) == 'Y') printf("\npainoit Y-näppäintä"); else printf("\npainoit jotain muuta kuin Y-näppäintä"); } return(0); 39
Sisäkkäiset if-rakenteet if-rakenteen sisälle voidaan sijoittaa toisia if-rakenteita. Esimerkiksi: #include <stdio.h> int main ( void ) { int temp; printf ("Anna tämänhetkinen lämpötila"); scanf ("%d", &temp); if ( temp < 25 ) if ( temp > 15 ) printf ("Tuntuu sopivalta.\n"); else printf ("Hieman on koleaa.\n"); else printf ("Huh hellettä!\n"); return ( 0 ); } 40
Huom. C-kielessä else-komento yhdistetään aina lähimpää if-komentoon. Sopivan muotoilun avulla helpotetaan koodin lukemista ja ymmärtämistä. 41
switch -rakenne Vaihtoehtoinen rakenne if-else rakenteelle on switch-rakenne. yleinen muoto switch ( ehtolauseke ) { case vakio1: lause1; break; case vakio2: lause2; break; 42
case vakio3: lause3; break; } default: lause4; break; Ehtolausekkeen arvon täytyy olla joko kokonaisluku- tai char-tyyppiä. Arvoa verrataan kunkin case-lauseen vakion arvoon, jos arvot täsmäävät suoritetaan case-lausetta seuraavia lauseita, kunnes kohdataan break-komento tai tullaan rakenteen loppuun. lauseita ei tarvitse laittaa lohkosulkujen ({, }) sisään. 43
Kuitenkin koko switch-komennon runko on laitettava { ja }-sulkeiden sisään. break-lauseen suorittamisen jälkeen poistutaan rakenteesta. Jos täsmäävää vaihtoehtoa ei löydy suoritetaan default-vaihtoehdon lauseet. default-osa voi myös puuttua Esimerkkiohjelma switch-rakenteen käytöstä. Ohjelma näyttää kuvaruudulla valikon ja kehottaa käyttäjää antamaan arvon. Käyttäjän annettua arvon, tutkitaan minkä arvon hän antoi ja ilmoitetaan minkä ohjelman hän valitsi. 44
/* menu.c*/ #include <stdio.h> int main (void) { char ch; printf("*** päävalikko ***\n"); printf("1. tekstinkäsittely\n"); printf("2. taulukkolaskenta\n"); printf("3. tietokanta\n"); printf("\n"); printf("valintasi : "); ch = getchar(); 45
switch(ch){ case '1': printf("\nvalitsit tekstinkäsittelyn\n"); break; case '2': printf("\nvalitsit taulukkolaskennan\n"); break; case '3': printf("\nvalitsit tietokannan\n"); break; } default: printf("\nvirheellinen valinta!\n"); break; /* tämä break ei ole pakollinen */ retur ( 0 ); }/* main-funktion loppu */ 46
Toistorakenteet while -toistorakenne Yleinen while-rakenteen muoto: while ( toistoehto ) lause; Toiminta: Toistoehto testataan ja jos se on tosi niin suoritetaan runko-osassa oleva lause. Ts. runko-osan lauseita toistetaan 0, 1 tai n kertaa, toistoehdon arvosta riippuen. 47
Runko-osa suoritetaan uudestaan niin kauan kuin (while) toistoehto on tosi. Kun toistoehto on epätosi poistutaan silmukasta ja ohjelman suoritus jatkuu while-rakennetta seuraavasta suoritettavasta lauseesta. Jos runko-osassa halutaan toistaan useita lauseita, on lauseet koottava lohkoksi { ja } -merkkien avulla. 48
do - while -toistorakenne do - while toistorakenne on while-rakenteen loppuehtoinen muunnos: do lause; while ( toistoehto ); Runko-osan lause suoritetaan ainakin yhden kerran Testataan toistoehto ja jos se on tosi runko-osan lause toistetaan. Jos runko-osassa halutaan toistaa useampia lauseita on lauseet koottavat lohkoksi { ja } merkkien avulla. 49
for-toistorakenne for-rakenteen yleinen muoto: for ( alustus; toistoehto; päivitys ) lause; for-lauseen suoritus: Aluksi suoritetaan alustus-osan lause, jossa ns. ohjausmuuttujalle annetaan alkuarvo, jonka jälkeen tutkitaan toistoehdossa ohjausmuuttujan arvoa. Jos toistoehto on tosi, suoritetaan runko-osan lause ja sen jälkeen päivitysosan lause. Tämän jälkeen testataan toistoehto uudelleen ja jos se on edelleen tosi ( eri 50
kuin 0 ) suoritetaan runko-osan lause ja päivitys uudestaan kunnes toistoehto tulee epätodeksi. Kun toistoehto tulee epätodeksi, poistutaan silmukasta ja ohjelman toiminta jatkuu for-rakennetta seuraavasta lauseesta. Haluttaessa toistaa useampia lauseita on lauseet koottava lohkoksi { ja } - merkkien avulla. Ohjausmuuttujan tyypin tulee olla kokonaisluku tai char. Huom! puolipisteen lisääminen for-lauseen loppuun aiheuttaa sen, että silmukassa toistetaankin ns. tyhjää lausetta. 51
Esimerkki: Tarkoitus olisi tulostaa kokonaislukujenlukujen 1...9 neliöt: for(luku = 1;luku < 10;luku++); printf("luvun %d neliö on %d\n", luku, luku*luku); Ohjelma kuitenkin tulostaisi seuraavaa: Luvun 10 neliö on 100 Puolipiste for-rivin lopussa aiheuttaa sen että tulostuslause ei kuulu toistorakenteen sisään! C-kieli (kuten myös Java) antaa mahdollisuuden käyttää useampaa kuin yhtä ohjausmuuttujaa: for(laskuri=0,total=0;laskuri < 10;laskuri++, total=total+5) 52
lauseet "laskuri = 0" ja "total = 0" kuuluvat molemmat alustusosaan ja ne erotetaan toisistaan pilkulla. Alustusosa päättyy puolipisteeseen. Muuttujien laskuri ja total päivitys voidaan hoitaa samassa päivitysosassa. for-silmukoita voidaan laittaan sisäkkäin: 53
/* kerto.c, tulostaa kertotaulun */ #include <stdio.h> int main ( void ) { int rivi, sarake; } for(rivi = 1; rivi <= 10; rivi++) { for(sarake = 1; sarake <= 10; sarake++) { printf(" %5d", sarake * rivi ); } printf("\n"); } return ( 0 ); 54
Ohjelma tulostaisi: 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 55
Päättymätön silmukka jatkuu ikuisesti, käyttäjä joutuu keskeyttämään suorituksen epäluonnollisesti. Joissakin tilanteissa kuitenkin päättymätöntä silmukkaa voidaan käyttää hyväksi. Päättymätön for-silmukka saadaan helposti: for( ; ; ){ printf("tämä toistuu jatkuvasti\n"); } while(1){ printf ("Tämäkin toistuu jatkuvasti\n"); } do{ printf ("Kuten myös tämä\n"); }while(1); 56
break-komento break-komennon avulla voidaan silmukan suoritus keskeyttää ja siirtää ohjaus silmukkaa seuraavalle komennolle. Jos break-komennolla poistutaan sisemmästä silmukasta, saa ulompi silmukka ohjauksen. break-komennon käyttöä silmukasta poistumiseen tulisi kuitenkin välttää, koska se vaikeuttaa koodin ymmärtämistä. 57
continue-komento continue-komentoa voidaan käyttää ohittamaan silmukan loppuosa. continue ei kuitenkaan lopeta silmukan suorittamista,vaan pakottaa silmukan suorittamaan seuraavan kierroksen suorittamatta silmukkakoodin contiuekäskyä seuraavia käskyjä. Esimerkkiohjelma tulostaa vain luvut, jotka ovat 2:lla jaollisia 58
#include <stdio.h> int main ( void ) { int luku; char c; for ( luku = 0; luku < 20; luku++) { /* jos jako menee tasan niin tulostetaan luku */ if( luku % 2 ) continue; // hypätään päivitysosaan tulostamatta mitään printf("luku = %d\n", luku ); } printf("\npaina <enter>, niin ohjelman suoritus loppuu"); c = getchar(); } return ( 0 ); 59
goto-komento Komentoa goto voidaan käyttää muuttamaan ohjelman suorituksen kulkua siirtämällä suoritus johonkin toiseen kohtaan ohjelmakoodia. goto-käskyn käyttöä tulee välttää, koska sen avulla ohjelmakoodista saadaan helposti vaikeaselkoinen, hankalasti ylläpidettävä, virhealtis jne... Ohjelmat voidaan toteuttaa ilman goto-käskyä! 60
Esimerkkiohjelma: #include <stdio.h> int main ( void ) { int laskuri = 0; uusiksi: if ( laskuri > 100 ) goto stop; printf("%d\n", laskuri ); ++laskuri; goto uusiksi; stop: } return ( 0 ); 61
Sama ohjelma ilman goto-käskyjä #include <stdio.h> int main ( void ){ int laskuri; for(laskuri = 0; laskuri <= 100; laskuri++) printf("%d\n", laskuri ); } return ( 0 ); 62