OHJ-1101 Ohjelmointi 1e
|
|
|
- Aino Penttilä
- 10 vuotta sitten
- Katselukertoja:
Transkriptio
1 OHJ-1101 Ohjelmointi 1e Essi Lahtinen
2 OHJ-1101 Ohjelmointi 1e Kurssin järjestelyt Kurssin vastuuhenkilö Essi Lahtinen (essi.lahtinen@tut., huone: TE210, puh ) vastaa kurssin sisällöstä, materiaalista, korvauksista ja luennoi toiselle ryhmälle. Toisen luentoryhmän luennoijana toimii Mikko Tiusanen (mikko.tiusanen@tut., huone: TF207, puh: ). Kurssivääpeli Teemu Erkkola ([email protected]., huone: TE212, puh: ) vastaa kaikista kurssiin liittyvistä käytännön järjestelyistä (harjoitusryhmät, harjoitustöihin liittyvät asiat, jne.). Lisäksi kurssin henkilökuntaan kuuluu 12 mukavaa ja avuliasta assistenttia, jotka ohjaavat viikkoharjoituksia ja harjoitustöitä. Kurssin henkilökunnan vastaanottoajat löytyvät kurssin nettisivulta.
3 OHJ-1101 Ohjelmointi 1e Tiedottaminen kurssilla Kurssin asioista tiedotetaan ensisijaisesti uutisryhmässä tut.ot.ohj1e, jota kannattaa seurata, jos haluaa selvitä kurssista mahdollisimman helpolla. Uutisryhmien lukemista kerrataan vielä ensimmäisessä viikkoharjoituksessa. Kysy neuvoa harjoitusassistentiltasi. Kurssin kotisivulla ohj1e/ on pääasiassa vain kurssin keston ajan muuttumatonta tietoa. Kotisivu kannattaa lukea perusteellisesti läpi, jos haluaa välttää höynäytetyksi tulemisen.
4 OHJ-1101 Ohjelmointi 1e Kurssin suorittaminen Kurssi muodostuu seuraavista osista: Luennot (2. periodilla 4 h/vk ja 3. periodilla 2 h/vk) Harjoitukset (2. ja 3. periodeilla 2 h/vk) Palautustehtävät (yhteensä 4 kpl, joista 3 kpl pakollisia), henkilökohtaisia Harjoitustyö (sisältää välipalautuksen), henkilökohtainen ja pakollinen Kaksi välikoetta tai tentti, pakollinen Luentoja on 36 h ja harjoituksia 22 h, mikä on yhteensä 48 h. Kurssista saa 4 op, joka merkitsee n. 104 h työtä. Muihin hommiin menee varmaan aika paljon aikaa! Ohjelmoimaan oppii vain ohjelmoimalla.
5 OHJ-1101 Ohjelmointi 1e Kurssin arvostelu Kurssin arvosana määräytyy kokonaispistemäärän (= suorituspisteet + bonuspisteet) perusteella. Suorituspisteitä saa tentistä tai välikokeista ( n. 30) ja harjoitustyöstä (3). Bonuspisteitä saa aktiivisesta osalistumisesta harjoituksiin (3). Suorituspisteet vaikuttavat arvosanarajojen määräytymiseen. Bonuspisteillä voi korottaa saamaansa arvosanaa maksimissaan yhdellä. (Hylättyä suoritusta ei voi korottaa.)
6 OHJ-1101 Ohjelmointi 1e Materiaali Kurssin pruju löytyy nettisivulta ja halutessaan sen voi tulostaa paperiversioksi TiTe-killan monistuskoneelta. Pruju on tarkoitettu luentojen tueksi, ei itseopiskeluun. Jos et aio käydä luennoilla, hanki jokin C++-opus. Tällaiseksi sopii esimerkiksi: Walter Savitch: Problem Solving with C++, The Object of Programming tai Jan Skansholm: C++ From the Beginning Epätoivoisesti englanninkieltä pelkäävät voivat kokeilla esim. hiukan kevyempää Päivi Hietanen: C++ ja olio-ohjelmointi C++-perusteos, järeää luettavaa unettomille ja kielestä enemmän kiinnostuneille, enemmän referenssi, kuin oppikirja Bjarne Stroustrup: The C++-programming language (saatavana myös suomenkielisenä)
7 OHJ-1101 Ohjelmointi 1e Kurssin tavoitteet ja motivaatio Tavoitteena on selvittää ohjelmoinnin peruskäsitteet ja yksinkertaiset tietorakenteet ohjelmanteon vaiheet ja ohjelman suorittaminen perustietämys C++-ohjelmointikielestä Kurssi ei ole teoriapainotteinen, vaan se antaa opiskelijalle käytännön perustaidot pienten ohjelmien suunnitteluun ja kirjoittamiseen C++-kielellä. Ammattiohjelmoijia ei kurssilla synny. Jokaisen DI:n tulisi nykyään tietää edes jotain ohjelmoinnista. Kurssilla opitut taidot ovat hyödyllisiä joillain myöhemmillä ammattiainekursseilla (osastosta riippumatta). Edellisvuoden kurssipalauteen mukaan esim. Matlabin tehokas käyttäminen on helpompaa kun ohjelmoinnin peruskäsitteet ovat hallussa. Jos kiinnostus ohjelmointiin herää kurssin kuluessa, voi ohjelmoinin opiskelua jatkaa kurssilla OHJ-1151 Ohjelmointi 2e (tai OHJ-1150 Ohjelmointi 2).
8 OHJ-1101 Ohjelmointi 1e C++:sta Kurssin esimerkkikieli on C++, mutta tarkoitus on perehtyä ohjelmointiin yleisestikin. C++ on vain esimerkkikieli. Kaikkia kielen piirteitä ei käydä läpi. Kielen syvällisempiä piirteitä käsitellään kursseilla OHJ-1400 Olio-ohjelmoinnin peruskurssi ja OHJ-1450 Olio-ohjelmoinnin jatkokurssi C++ ei ole kaikin puolin paras mahdollinen opetuskieli. Se kärsii jonkin verran menneisyyden painolastista, koska se pohjautuu C-kieleen. Huonoja piirteitä ovat mm. syntaksin kryptisyys, erilaisten suojaverkkojen puuttuminen ja jyrkkä oppimiskäyrä. Ohjelmoinnin perusjutut hukkuvat helposti yksityiskohtien alle. C++ on joustava ja tehokas ammattilaisen työkalu niille, jotka tietävät mitä tekevät.
9 OHJ-1101 Ohjelmointi 1e Kurssin ohjelmointiympäristöstä Kurssin ohjelmointiympäristönä käytetään TTY:n proa-klusteria. Kääntäjänä käytetään komentorivipohjaista tutg++:aa. Kurssilla ei opeteta käyttämään mitään graasta ohjelmointiympäristöä, koska komentorivipohjainen ympäristö tuo ohjelman kehityksen eri vaiheet selkeämmin esille. Graasta ympäristöä on helppo oppia käyttämään, jos hallitsee komentorivipohjaisen. Toisinpäin opetteleminen ei yleensä ole yhtä helppoa. Tietotekniikan ammattilainen hallitsee työnsä ympäristössä kuin ympäristössä, myös ei-graasessa. Itse tietenkin saa koodailla ihan missä ympäristössä haluaa.
10 OHJ-1101 Ohjelmointi 1e Esimerkki: Tavuttaminen Ohjelmoinnista on jo saatu yleiskäsitys kurssilla OHJ-1010 Tietotekniikan perusteet. Tällä kurssilla sanalla ohjelmointi tarkoitetaan tietokoneen ohjelmointia. Aloitamme perehtymisen ohjelmoinnin ongelmiin ja vaiheisiin pienen esimerkin avulla: suunnitellaan pientä tietokoneohjelmaa, joka tavuttaa suomenkielistä tekstiä. Esimerkissä ei ole tarkoitus keskittyä tavutussääntöjen opettelemiseen vaan ajattelu- ja toimintatapaan, jota ohjelmoija tarvitsee. Kiinnitä huomiosi muuhunkin kuin yksityiskohtiin.
11 OHJ-1101 Ohjelmointi 1e Äidinkielen kirja kertoo, että suomen kielen tavuttaminen seuraa melko suoraviivaisesti seuraavia sääntöjä: Konsonanttisääntö: Jos tavuun kuuluvaa vokaalia seuraa yksi tai useampia konsonantteja, joita vielä seuraa vokaali, tavuraja sijoittuu välittömästi ennen viimeistä konsonanttia. lef-fas-sa ki-vaa kah-del-le: tra-giik-kaa se-kä hork-ka-ti-lo-ja Vokaalisääntö: Jos tavun ensimmäistä vokaalia seuraa toinen vokaali, niiden väliin tulee tavuraja, ellei a) edellinen vokaali ole sama kuin jälkimmäinen (pitkä vokaali). b) kysymyksessä ole jokin diftongi. lu-en-to Aa-si-an kää-pi-ö-puo-lu-eis-ta Diftongisääntö: Jos tavun kuuluvaa diftongia tai pitkää vokaalia seuraa vokaali, tähän väliin tulee aina tavuraja. raa-is-tu-nut maa-il-ma, liu-ot-ti-met lau-an-tai-na tau-ot-ta leu-an al-la Poikkeuksiakin löytyy: de-mo-kra-ti-a, kai-vos-auk-ko, jne, jne. Diftongit ovat: ai, ei, oi, ui, yi, äi, öi, au, eu, ey, ie, iu, ou, uo, yö, äy tai öy.
12 OHJ-1101 Ohjelmointi 1e TiTePK:sta muistamme, että tietokone ei osaa tavuttaa noin ylimalkaisten tavutussääntöjen perusteella, vaan sitä varten pitää kehittää algoritmi. Algoritmin pitää olla: 1. yksikäsitteinen (ei tulkittavissa väärin) 2. yksityiskohtainen (tyhmäkin osaa seurata) 3. saavuttaa tavoitteensa (eli toimii oikein) 4. määrää toimenpiteiden suoritusjärjestyksen (seuraus kohdasta 1) 5. sisältää äärellisen määrän toimenpiteitä (muuten tehtävä ei tulisi suoritetuksi, seuraus kohdasta 3) Tietokone on tyhmä.
13 OHJ-1101 Ohjelmointi 1e Riittävä yksikäsitteisyys ja yksityiskohtaisuus ovat tulkinnanvaraisia ja riippuvat tilanteesta. Ihminen ymmärtää, mitä pitää tehdä, jos algoritmi sanoo Laske yhteen luvut yhdestä sataan. Ihminen saattaa jopa keksiä tähän luovan ratkaisun ja välttyä käsityöltä. Tietokoneet ovat "rajoittuneita". Suunniteltaessa tietokonealgoritmeja niiden on oltava äärimmäisen yksikäsitteisiä ja yksityiskohtaisia. Esimerkiksi, jos halutaan, että tietokone selvittää, montako vokaalia sanassa on, se pitää ohjeistaa tietokoneelle näin tarkasti: Ota käsiteltäväksi sana ensimmäinen kirjain Ota vokaalien lukumääräksi nolla NIIN KAUAN KUIN ei olla sanan lopussa JOS käsiteltävänä on vokaali Kasvata lukumäärää yhdellä Siirry seuraavaan kirjaimeen Tulosta lukumäärä
14 OHJ-1101 Ohjelmointi 1e Edellisessä algoritmissa esiintyi toistoa ja ehdollisuutta. 1. Jotain algoritmin osaa saatetaan tarvittaessa suorittaa useita kertoja peräkkäin (toisto). 2. Jonkin algoritmin osan suorittaminen saattaa riippua olosuhteista (ehdollisuus). Toisto voidaan esittää algoritmissa seuraavasti: NIIN KAUAN KUIN väite toimenpiteet jota tulkitaan suoraviivaisesti siten, että toimenpiteitä toistetaan yhä uudelleen niin kauan kuin esitetty väite on tosi. Väite voi siis periaatteessa olla mikä tahansa toteamus, kunhan siitä tavalla tai toisella voidaan päätellä, pitääkö se paikkansa vai ei.
15 OHJ-1101 Ohjelmointi 1e Algoritmissa ehdollisuus esitetään muodossa: JOS väite NIIN toimenpiteet1 MUUTEN toimenpiteet2 Tätä tulkitaan siten, että mikäli väite on tosi, on algoritmin toteuttamiseksi suoritettava toimenpiteet1. Mikäli väite taas ei pidä paikkaansa, suoritetaan toimenpiteet2. Kuten aiemminkin väite saa olla mitä tahansa, jos siitä vain voidaan päätellä, onko se tosi vai epätosi. Ehtorakenne voi olla myös sellainen, että siinä on vain JOS-osa ilman MUUTEN-osaa. Tällöin ei tehdä mitään, jos väite ei pidä paikkaansa.
16 OHJ-1101 Ohjelmointi 1e Pseudokoodi Algoritmikielessä "jos-niin-muuten" ja "niin kauan kuin" ovat syntaktisia (l. kieliopillisia) rakenteita, joiden semantiikka (l. merkitys) on ehdollisuus ja toisto. Monista ohjelmointikielistä löytyy vastaavankaltaiset rakenteet "ifthen-else" ja "while-do". Jatkon kannalta on selvempää, jos käytämme niitä suomenkielisten rakenteiden sijaan. Tällaista ohjelmointikielen ja puhutun kielen yhdistelmää kutsutaan pseudokoodiksi. Se on erittäin hyödyllinen työkalu ohjelmien suunnittelemisessa.
17 OHJ-1101 Ohjelmointi 1e Palataan tavutusongelmaan ja kokeillaan ensin muodostaa suoraan tavutussääntöjen pohjalta sen kummemmin miettimättä algoritmi, joka tavuttaa yhden sanan. Kootaan algoritmi siten, että toistorakenteen avulla käydään läpi tavutettavaa sanaa kirjain kerrallaan: Ota käsiteltäväksi sanan ensimmäinen kirjain WHILE ei olla sanan lopussa DO Selvitä tuleeko tähän kohtaan tavuviiva Ota käsiteltäväksi seuraava kirjain Tulosta sana tavuviivoin
18 OHJ-1101 Ohjelmointi 1e Osaa Selvitä tuleeko tähän kohtaan tavuviiva täytyy tarkentaa: valintarakenteen avulla katsotaan jokaisen kirjaimen kohdalla, mikä säännöistä on tarkoitus suorittaa: IF konsonanttisääntötilanne voimassa THEN Suorita konsonanttisääntö ELSE IF vokaalisääntötilanne voimassa THEN Suorita vokaalisääntö ELSE IF diftongisääntötilanne voimassa THEN Suorita diftongisääntö
19 OHJ-1101 Ohjelmointi 1e Kun valintarakenne lisätään toistorakenteen sisään, algoritmiksi muodostuu:
20 OHJ-1101 Ohjelmointi 1e Käyttäen aidinkielenkirjan tavutussääntöjä, edellisen kuvan pohjalta voidaan kirjoittaa pseudokoodilla seuraava tavutusalgoritmi: Ota käsiteltäväksi sanan ensimmäinen kirjain WHILE ei olla sanan lopussa DO IF käsiteltävänä on vokaali ja sitä seuraa konsonantti THEN IF viimeisen peräkkäin olevan konsonantin perässä on vokaali THEN Sijoita tavuviiva ennen viimeistä konsonanttia ELSE IF käsiteltävänä on vokaali ja sitä seuraa vokaali THEN IF käsiteltävä ja seuraava eivät ole tuplavokaali tai diftongi THEN Sijoita tavuviiva käsiteltävän vokaalin jälkeen ELSE IF käsiteltävä ja seuraava ovat tuplavokaali tai diftongi THEN IF tuplavokaalia tai diftongia seuraa vokaali THEN Sijoita tavuviiva tuplavokaalin tai diftongin jälkeen Siirry käsittelemään seuraavaa kirjainta Tulosta koko sana tavuviivoineen
21 OHJ-1101 Ohjelmointi 1e Vuokaavio tavutusalgoritmista tarkemmin
22 OHJ-1101 Ohjelmointi 1e Tässä vaiheessa herää epäilys: voiko tavutusalgoritmin muodostaminen olla noin yksinkertaista? Testataan kehittämäämme algoritmia. Hyvää testiaineistoa löytyy esimerkiksi sivulta 10. Otetaan käyttöön kynä ja paperia ja testataan algoritmia sanalla luento. Lopputuloksena lu-en-to eli näyttää siltä, että ainakin vokaalisääntö ja konsonanttisääntö toimivat. Ainakin joskus... Tai ainakin tässä tilanteessa! :) Toimiiko algoritmimme nyt siis oikein?
23 OHJ-1101 Ohjelmointi 1e Algoritmien muodostaminen Hyväksi havaittu tapa algoritmien muodostamiseen on kokonaisuutta pienempiin osiin. Pieniä kokonaisuuksia on helpompi hallita. jäsentää Kokonaisuus saadaan pienistä osista yhdistämällä, kunhan osien algoritmit ovat oikein muodostettu ja liitetty toisiinsa. "Hajoita ja hallitse." Jäsentämistä jatketaan, kunnes osatoiminnot ovat riittävän yksinkertaisia. Algoritmin toiminnot ovat monimutkaisuudeltaan samalla tasolla kuin mitä algoritmin suorittava systeemi ymmärtää käskyinään. Tärkeintä on, että paloittelet ja jäsennät kokonaisuuden niin, että itse ymmärrät, mitä olet tekemässä.
24 OHJ-1101 Ohjelmointi 1e Yritetään muodostaa tavutusalgoritmi uudestaan, tällä kertaa niin, että myös ymmärretään, miten se toimii. Kun katsotaan kaikkia tavutussääntöjä, huomataan, että jokainen niistä alkaa siitä, että käsitellään vokaalia. Tavutusalgoritmin kannattaa ensimmäiseksi tarkastaa ollaanko käsittelemässä vokaalia. Jos ei, niin ei tarvitse tehdä mitään, siirrytään vain seuraavaan kirjaimeen. Algoritmiksi tämän voisi pukea esim. näin: Ota käsiteltäväksi sanan ensimmäinen kirjain WHILE ei olla sanan lopussa DO IF käsiteltävänä on vokaali THEN Täytyy tehdä jotain... Siirry käsittelemään seuraavaa kirjainta Tulosta koko sana tavuviivoineen
25 OHJ-1101 Ohjelmointi 1e Kohtaa Täytyy tehdä jotain... pitää selvästikin tarkentaa. Säännöt jakautuvat kahteen tilanteeseen: 1. vokaali ja sen jälkeen konsonantti toteutetaan konsonanttisääntö 2. vokaali ja sen jälkeen vokaali toteutetaan joko vokaalisääntö tai diftongisääntö Ja sama algoritmina: IF käsiteltävästä seuraava kirjain on konsonantti THEN ELSE Suoritetaan konsonanttisääntö Suoritetaan joko vokaalisääntö tai diftongisääntö Samaan tyyliin voidaan jatkaa pala kerrallaan koko tavuttamisalgoritmin muodostamista.
26 OHJ-1101 Ohjelmointi 1e Lopputuloksena saadaan korjattu ja siistitty algoritmi: Ota käsiteltäväksi sanan ensimmäinen kirjain WHILE ei olla vielä sanan lopussa DO IF käsiteltävänä on vokaali THEN IF käsiteltävästä seuraava kirjain on konsonantti THEN IF viimeisen peräkkäin olevan konsonantin jälkeen on vokaali THEN Sijoita tavuviiva ennen viimeistä konsonanttia ELSE IF käsiteltävä vokaali on tuplavokaalin tai diftongin alku THEN IF tuplavokaalin tai diftongin jälkeen on vielä vokaali THEN Sijoita tavuviiva tuplavokaalin tai diftongin perään ELSE Sijoita tavuviiva käsiteltävän vokaalin perään Siirry käsittelemään seuraavaa kirjainta Tulosta koko sana tavuviivoineen
27 OHJ-1101 Ohjelmointi 1e Vuokaavio lopullisesta tavutusalgoritmista
28 OHJ-1101 Ohjelmointi 1e Tätä uutta algoritmia testataan tietenkin uudestaan vähintään yhtä kattavasti kuin ensimmäistäkin versiota algoritmista. Kun algoritmia on testattu riittävästi ja todettu toimivaksi, se voidaan toteuttaa jollakin ohjelmointikielellä. Kuten algoritmin toteutuksessakin, tässä vaiheessa ohjelmakoodi voidaan kirjoittaa monella eri tavalla. Seuraavalla kalvolla esitettävä toteutus ei ole ainoa oikea vaan yksi mahdollinen. Valmiiksi hyvin suunnitellun algoritmin toteuttaminen C++:lla ei todennäköisesti ole C++:aa osaavalle henkilölle yhtään niin vaativaa, kuin itse algoritmin suunnitteleminen. Siitä huolimatta tässä vaiheessa kurssia ei vielä tarvitse ymmärtää, miten seuraava C++toteutus toimii. Ohjelmalistauksesta voi kuitenkin saada jonkinlaisen käsityksen siitä, millaista C++ on.
29 OHJ-1101 Ohjelmointi 1e Yksi tapa toteuttaa tavutusalgoritmi C++:lla: string tavuta( string sana ) { vector< bool > viivat( sana.size(), false ); for( unsigned int i = 0; i < sana.size(); ++i ) { if( vokaali( sana.at( i ) ) && i+1 < sana.size() ) { // Jos käsiteltävänä vokaali ja sana ja if( konsonantti( sana.at( i+1 ) ) ) { // Vokaalin perässä konsonantti -> Konsonanttisäänt int j = 1; // Lasketaan kuinka monta konsonanttia on peräkkäin while( i+j < sana.size() && konsonantti( sana.at( i+j ) ) ) { ++j; if( i+j < sana.size() && vokaali( sana.at( i+j ) ) ) { viivat.at( i+j-2 ) = true; else { // Vokaalin perässä toinen vokaali if( ( sana.at( i ) == sana.at( i+1 ) ) diftongi( sana.at( i ), sana.at( i+1 ) ) ) { // Tuplavokaali tai diftongi -> Diftongisääntö if( i+2 < sana.size() && vokaali( sana.at( i+2 ) ) ) { viivat.at( i+1 ) = true; else { // Ei tuplavokaali eikä diftongi -> Vokaalisääntö viivat.at( i ) = true; string tavutettu; for( unsigned int i = 0; i < sana.size(); ++i ) { tavutettu += sana.at( i ); if( viivat.at( i ) ) { tavutettu += "-"; return tavutettu;
30 OHJ-1101 Ohjelmointi 1e Ohjelmoinnin vaiheet Seuraava malli kuvaa onnistuneen ohjelmointiprojektin vaiheita: 1. Ongelman ratkaisuvaihe (a) Analysointi ja määrittely: ymmärrä ongelma ja selvitä, mitä ratkaisun on tarkoitus tehdä. (b) Yleinen ratkaisu (algoritmi ): kehitä looginen sarja ohjeita, joita noudattamalla ongelmalle saadaan haluttu lopputulos. (c) Tarkistus: testaa kynällä ja paperilla, että algoritmi toimii. 2. Ratkaisun toteutusvaihe (a) Konkreettinen ratkaisu: toteuta algoritmi sopivalla ohjelmointikielellä. (b) Testaus: suorita ohjelmaa eri syötteillä ja vertaile tuloksia tunnettuihin oikeisiin ratkaisuihin: jos virheitä löytyy, mieti "miksi?" ja korjaa ne. 3. Ylläpitovaihe (a) Käyttö: käytä ohjelmaa suunniteltuun tarkoitukseen. (b) Ylläpito: korjaa löytyviä virheitä ja lisää mahdollisia uusia tarvittavia ominaisuuksia.
31 OHJ-1101 Ohjelmointi 1e Asiaan perehtymättömillä on usein sellainen käsitys, että ohjelmointi on sitä, kun istutaan tietokoneen ääressä ja syötetään näppäimistöltä koneelle ohjelmaa. Kun naputtelu on ohi, kone suorittaa ohjelman ongelmitta ja näyttää oikean tuloksen. Kun tätä käsitystä ohjelmoinnista vertaa kalvolla 29 esitettyyn malliin, niin jotain puuttuu: Harhaluuloinen käsitys koostuu pelkästään yleisen mallin viimeisestä vaiheesta. Ongelmaa ei välttämättä ole ymmärretty kunnolla eikä sen ratkaisua mietitty loppuun saakka. Väärä lähestymistapa johtaa ikävyyksiin: ongelmaa ei ole ymmärretty ratkaistaan väärä ongelma ratkaisutapa virheellinen ohjelman antama tulos on väärä ohjelmaa pitää korjata hukataan aikaa ja rahaa Karkea sääntö: ratkaisuvaihe/toteutusvaihe tulisi olla 50%/50%, kun vertaillaan käytettyä aikaa ja resursseja. "Väärää lähestymistapaa" käyttävillä suhde on usein 10%/90% tai huonompi: ongelmaa pohdittu kahvikupin verran ja rynnätty suoraan toteuttamaan. Vaikka virheellinen lähestymistapa saattaakin toimia pienissä ohjelmointiprojekteissa, ongelman koon kasvaessa se ei toimi.
32 OHJ-1101 Ohjelmointi 1e Ohjelmointikielistä Ohjelmointikieli on se kieli, jolla tietokoneen kanssa voidaan kommunikoida (l. kuvata algoritmit muodossa, joka saadaan koneen ymmärtämään muotoon). Tarkoitus on myös, että koodia lukeva ihminen ymmärtää, mistä on kyse. Se on selkeästi analoginen puhutun kielen kanssa, mutta sangen yksinkertainen. Kaikki tietokoneet ymmärtävät pohjimmiltaan vain omaa konekieltään: sopivassa järjestyksessä koneen muistiin tallennettuja lukuja 0 ja 1 (tosiasiassa jännitetasoja). Tietyssä järjestyksessä esiintyvät nollat ja ykköset tietokone osaa tulkita alkeellisiksi käskyiksi, konekäskyiksi. Alunperin kaikki ohjelmointi oli puhtaasti konekielellä ohjelmointia: johtoja ja vipuja. Konekieli on kovin hankalakäyttöistä. Symbolinen konekieli. Korkean tason ohjelmointikielet (esim. lausekielet ).
33 OHJ-1101 Ohjelmointi 1e Lausekielet Lausekielet ovat konekieltä ilmaisuvoimaisempia: niillä halutun tehtävän selittäminen tietokoneelle helpompaa ja lopputulos ymmärrettävämpää ihmiselle. Yksi lausekielellä kirjoitettu käsky vastaa useita, jopa tuhansia, konekäskyjä. Ennen kuin tietokone voi suorittaa jollain muulla kuin sen omalla konekielellä kirjoitetun ohjelman, se täytyy tavalla tai toisella muuntaa konekieleksi: kääntäminen (compiling) tulkkaaminen (interpreting)
34 OHJ-1101 Ohjelmointi 1e Ohjelman tulkkaaminen Ohjelman tulkkaaminen perustuu siihen, että ohjelmointikielen tulkki suorittaa ohjelmaa käsky ( lause/lauseke) kerrallaan. Etuja: ohjelma voidaan testata pala kerrallaan tulkki huolehtii virheilmoituksista ja auttaa virheiden etsinnässä Haittoja: ohjelman suoritus vaatii aina tulkin tehoton
35 OHJ-1101 Ohjelmointi 1e Ohjelman kääntäminen Ohjelman kääntäminen perustuu siihen, että ohjelmakoodi käännetään kokonaisuudessaan konekielelle erityisellä kääntäjäohjelmalla (kääntäjällä) ennen kuin se voidaan suorittaa. Etuja: syntaksi- ja semanttiset virheet havaitaan aina kääntäjää ei enää tarvita uudelleen ajettava ohjelma nopea helpompi optimoida Haittoja: ajonaikaiset virheet jäävät yleensä ohjelmoijan hoidettavaksi
36 OHJ-1101 Ohjelmointi 1e Kääntäjän toiminta
37 OHJ-1101 Ohjelmointi 1e Ensimmäinen C++-ohjelma Käydään yksityiskohtaisesti läpi pikkuruinen C++-kielinen ohjelma: 1 // Lähdekooditiedosto: forever.cc // // Ohjelma tulostaa näytölle lausahduksen: // "I plan to live forever or die trying." rivitettynä 5 #include <iostream> #include <cstdlib> using namespace std; 10 int main() { // Ohjelman toiminnot alkavat tästä. cout << "I plan to live forever" << endl; cout << "or die trying." << endl; return EXIT_SUCCESS; 15
38 OHJ-1101 Ohjelmointi 1e Pienessä ohjelmassa on monta tärkeää asiaa: Teksti //-kirjainyhdistelmästä rivin loppuun on kommentti, joka ei vaikuta ohjelman toimintaan. Kaikissa C++-ohjelmissa pitää olla funktio int main(), joka päättyy käskyyn return. Varsinaiset ohjelman suorittamat toiminnot ovat main:ia seuraavien aaltosulkeiden sisällä. Käskyt (lauseet) tuntuvat päättyvän ";":een. Jos C++-ohjelmassa halutaan lukea syötteitä tai kirjoittaa tulosteita, sen alkuun on lisättävä #include <iostream> ja using namespace std. cout on C++:ssa tulostusvirta, johon voidaan <<-operaattorilla ohjata tulosteita, jotka sitten ilmestyvät ohjelmaa suoritettaessa näytölle. Lainausmerkkien väliin kirjoitettua tekstiä kutsutaan merkkijonoksi, mikä tarkoittaa selkokielellä tekstimuotoista tietoa. endl tulostaa rivinvaihdon: seuraavat tulostukset alkavat uudelta riviltä (sen vasemmasta laidasta).
39 OHJ-1101 Ohjelmointi 1e Lähdekoodista suoritettavaksi ohjelmaksi C++-ohjelman tekeminen etenee yleensä seuraavasti: 1. Suunnitellun algoritmin C++-version kirjoittaminen jollain editorilla 2. Tallentaminen tiedostoon, jonka nimi päättyy.cc 3. Tiedoston kääntäminen C++-kääntäjällä konekielelle 4. JOS tuli käännösvirheitä NIIN takaisin editoriin korjaamaan ne 5. Käännetyn ohjelman testaaminen, jotta nähdään, toimiiko se oikein 6. JOS ei toimi oikein NIIN mieti miksi ei ja palaa takaisin editoriin korjaamaan viat 7. MUUTEN ohjelma on valmis
40 OHJ-1101 Ohjelmointi 1e Editointi C++-ohjelmia voi kirjoittaa millä tahansa editoriohjelmalla. Ohjelmien editointiin kannattaa kuitenkin, jos mahdollista, käyttää jed- tai emacs-editoria. Kun jedillä tai emacsilla käsittelee tiedostoa, jonka nimi päättyy.cc:hen, editori menee automaattisesti C++-tilaan, joka osaa esimerkiksi sisentää ohjelmakoodin automaattisesti, kun vain painaa sarkainnäppäintä. Periaatteessa tällä kurssilla ei ole tarkoitus uppoutua editoriohjelman käyttöön: jonkin editorin tuntemus pitäisi jokaisella olla TiTePk:sta. Ensimmäisissä viikkoharjoituksissa kuitenkin käydään pikaopastus jedin ja emacsin tärkeimpiin ominaisuuksiin.
41 OHJ-1101 Ohjelmointi 1e Kääntäminen Ohjelman kääntämiseen käytämme tutg++-nimistä kääntäjää. tutg++:lle luetellaan komentorivillä kaikki C++-kieliset lähdekooditiedostot, ja se kääntää niistä suoritettavan konekielisen ohjelman: proffa> tutg++ forever.cc Jos koodi on virheetön, tuloksena syntyy ajokelpoinen ohjelma a.out, joka suoritetaan kirjoittamalla sen nimi komentotulkille: proffa>./a.out I plan to live forever or die trying. a.out ei ole kuvaava nimi, mutta tutg++:lle voi kertoa vivulla -o, minkä nimisen ohjelman haluaa tuloksena: proffa> tutg++ -o plan forever.cc proffa>./plan I plan to live forever or die trying. tutg++ tunnistaa kymmeniä muitakin komentorivivipuja. Kuten TiTePK:sta muistamme, komentoriville kirjoitetun komennon alussa./ tarkoittaa, että ajettava ohjelma on työhakemistossa.
42 OHJ-1101 Ohjelmointi 1e Virhetilanteet Periaatteessa ohjelmissa on kolmenlaisia virheitä: kielioppi- eli syntaksivirheitä semanttisia eli "merkitysvirheitä" loogisia eli "ajatusvirheitä" Syntaksivirheet Syntaksivirheet ovat virheitä, jotka syntyvät, kun lähdekoodi ei ole käytetyn ohjelmointikielen kielioppisääntöjen mukaista. Esimerkiksi cout- tai return-lauseen lopusta puuttuva ";"-merkki olisi C++:ssa syntaksivirhe. Kääntäjä löytää aina syntaksivirheet. Virheen löydyttyä kääntäjä tulostaa ilmoituksen, joka kertoo virheen syyn ja (suuntaa-antavan) rivinumeron, jolla virhe lähdekooditiedostossa sen mielestä sijaitsi. Tyypillisesti virheilmoitus alkaa "syntax error" tai "parse error".
43 OHJ-1101 Ohjelmointi 1e Semanttiset virheet Semanttiset virheet syntyvät, kun ohjelmakoodi on syntaktisesti oikein, mutta kääntäjä ei silti pysty ymmärtämään sitä. Jos esimerkkiohjelmassa olisi vahingossa kirjoitettu ndl, kun oikea vaihtoehto on endl, olisi tuloksena semanttinen virhe. ndl on kyllä syntaktisesti ihan oikeanlainen: se voisi olla jonkin asian tunniste. Semanttinen virhe tulee, koska kääntäjä ei kuitenkaan ymmärrä, mitä ndl tarkoittaa. Semanttiset virheetkin kääntäjä löytää useimmiten. Semanttisesta virheestä tulostuu virheilmoitus, jonka jälkeen kääntäjä tyypillisesti sekoaa ja väittää löytävänsä koodista samalta ja myöhemmiltä riveiltä kaikennäköisiä virheitä. Korjaa virheet aina kääntäjän ilmoittamassa järjestyksessä.
44 OHJ-1101 Ohjelmointi 1e Loogiset virheet Loogiset virheet syntyvät, kun ohjelman kirjoittaja ajattelee jotain väärin tai unohtaa ottaa huomioon jonkun joskus hyvinkin vähäpätöisen seikan. Loogiset virheet ovat tavallisesti kirjoitusvirheitä tai algoritmin suunnittelussa tapahtuneita virheitä. Loogiset virheet ilmenevät siten, että ohjelma toimii väärin. Kääntäjällä ei ole mahdollisuuksia havaita loogisia virheitä, koska se vaatisi ohjelmoijan ajatuksenjuoksun ymmärtämistä. Ainoa tapa välttää loogisia virheitä on ohjelman huolellinen suunnittelu ja kirjoittaminen.
45 OHJ-1101 Ohjelmointi 1e Varatut sanat Kuten puhutuissa kielissä, on ohjelmointikielissäkin sanoja, joilla on jokin kiinteä merkitys. Esim. suomessa "kolme", "koska" ja "minä" tai C++:ssa main ja return. Ohjelmointikielistä puhuttaessa tällaisia sanoja kutsutaan varatuiksi sanoiksi. Varatuille sanoille on siis ohjelmointikielessä määritelty merkitys, eikä ohjelmoija yleensä voi muuttaa tätä merkitystä, koska tällöin kyseisen sanan alkuperäinen tarkoitus hukkuisi. Joskus kielen varattuja sanoja kutsutaan myös käskyiksi. Sanaa "käsky" käytetään kuitenkin usein hiukan vapaammin, esimerkiksi tarkoittamaan yhtä ohjelman lausetta. Varatut sanat luovat perustan koneen ja ohjelmoijan kommunikoinnille käytettäessä korkean tason ohjelmointikieltä.
46 OHJ-1101 Ohjelmointi 1e C++-kielen varatut sanat Seuraavassa on lueteltu C++-kielen varatut sanat: and and eq asm auto bitand bitor bool break case catch char class compl const const cast continue default delete do double dynamic cast else enum explicit export extern false oat for friend goto if inline int long main mutable namespace new not not eq operator or or eq private protected public register reinterpret cast return short signed sizeof static static cast struct switch template this throw true try typedef typeid typename union unsigned using virtual void volatile wchar t while xor xor eq Osaan kurssilla tutustutaan, mutta ei läheskään kaikkiin.
47 OHJ-1101 Ohjelmointi 1e Esimerkki // Lähdekooditiedosto: vastukset.cc // // Kommentointi on tärkeä osa ohjelman kirjoittamista, mutta // kalvoilla se vie liikaa tilaa, joten vastaisuudessa prujun // esimerkit ovat kommentoituja vain tositarpeessa! #include <iostream> #include <cstdlib> using namespace std; int main() { cout << "Sarjaan: " << << endl; cout << "Rinnan: " << 5.0 * 10.0 / ( ) << endl; return EXIT_SUCCESS;
48 OHJ-1101 Ohjelmointi 1e Kun ohjelma käännetään ja suoritetaan: proffa> tutg++ -o vastukset vastukset.cc proffa>./vastukset Sarjaan: 15 Rinnan: Siitä opittua: C++-kieli selvästikin ymmärtää lukuja ja sallii niillä laskemisen. cout:in avulla voidaan tulostaa myös lukuja (laskulausekkeen arvoja). C++ ei ole kovin tarkka siitä, kuinka jaamme ohjelmamme riveille. Huomaa sisentäminen ja koodin ulkoasu! VIP-esimerkki: 1.1. (ks. VIP-esimerkit kurssin ohj1e IDLEn valikosta)
49 OHJ-1101 Ohjelmointi 1e Perustietotyypit Tietokoneohjelmat koostuvat kahdenlaisista asioista: tiedosta toimenpiteistä, jotka käsittelevät tietoa Jotta ohjelmointikielellä voisi tehdä tietoa käsitteleviä ohjelmia, on oltava joku tapa tiedon esittämiseen ja käsittelyyn. Perustietotyypit (alkeistietotyypit ) tiedon esittämiseen Varatut sanat ja operaattorit sen käsittelyyn Yleisesti ottaen tietotyypillä käsitetään joukkoa alkioita, joilla on samat ominaisuudet, eli niitä voidaan käsitellä samoilla operaattoreilla. Perustietotyypit ovat sellaisia tiedon esitysmuotoja, jotka ohjelmointikieli tuntee automaattisesti (ilman kirjastoja). Tavallisesti perustietotyyppien alkioiden käsittelyyn on valmiit käskyt konekielessä.
50 OHJ-1101 Ohjelmointi 1e Kaikella tiedolla on joku tyyppi ja yleensä vain samantyyppisillä tietoalkioilla voi operoida keskenään. Alussa riittää tutustua perustietotyyppeihin, joita C++-kielessä ovat: bool totuusarvoille (true ja false) int kokonaisluvuille (esim. -2, 12345) double (ja float) liukuluvuille (esim , 1E10) char kirjainmerkeille (esim. 'a', '\n'). Liukuluvut eivät ole sama asia kuin reaaliluvut, vaan kasa likiarvoja. Tyyppejä int, double, float ja char kutsutaan aritmeettisiksi tyypeiksi, eli tyypeiksi, joille voidaan suorittaa normaaleja laskuoperaatioita (kuten yhteen- ja kertolasku). Todellisuudessa C++ käsittelee kirjainmerkkejäkin pieninä kokonaislukuina eli tallettaa niiden ASCII-koodin. Toistaiseksi käsitellään myös merkkijonoja ( string, tekstimuotoinen tieto, lainausmerkkien sisällä oleva teksti) kuten perustietotyyppejä, vaikka ne eivät perustietotyyppejä olekaan.
51 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita ohjelma, joka tulostaa ympyrän piirin ja pinta-alan, kun säde on 2,5 cm. #include <cstdlib> #include <iostream> using namespace std; int main() { return EXIT_SUCCESS;
52 OHJ-1101 Ohjelmointi 1e Kirjoita ohjelma, joka tulostaa jännitteen (U = R*I) voltteina ja sähkötehon (P = U*I) watteina, kun resistanssi on 1000 Ω ja virta 2A. int main() { return EXIT_SUCCESS;
53 OHJ-1101 Ohjelmointi 1e Sama esimerkki uudelleen #include <iostream> #include <cstdlib> using namespace std; int main() { double eka = 5.0; double toka = 10.0; cout << "Sarjaan: " << eka + toka << endl; cout << "Rinnan: " << eka * toka / ( eka + toka ) << endl; return EXIT_SUCCESS; Ohjelman kääntäminen ja ajo menevät samoin kuin edelliselläkin kerralla. Uusi huomio: lukuja voi tallettaa nimettyihin muuttujiin. Ohjelman muunneltavuus helpottuu huomattavasti. VIP-esimerkit: 1.2. ja 1.5.
54 OHJ-1101 Ohjelmointi 1e Muuttujat Muuttujat ovat tiedon talletuspaikkoja. Toisin sanoen, jotta voisimme manipuloida tietoa, meidän on päästävä siihen käsiksi. Muuttujalla on oltava nimi. Kolmanneksi muuttujia voi ajatella koneen muistissa olevalle tiedolle annettuina symbolisina niminä: int a = b + 10; int laina = hinta - saastot; Muuttujat ovat tallessa tietokoneen muistipaikoissa a 0004 b 0008 hinta 0012 saastot 0016 laina Muuttujien ja muiden koodielementtien selkeä nimeäminen liittyy läheisesti käsitteeseen hyvä ohjelmointityyli, johon palataan myöhemmin.
55 OHJ-1101 Ohjelmointi 1e Muuttujilla on kolme ominaisuutta: tyyppi, esimerkiksi: int nimi, jotka kerrotaan muuttujaa määriteltäessä, esimerkiksi: int rivinumero; arvo, joka yleensä asetetaan sijoitusoperaattorilla, joka on C++:ssa =, esimerkiksi: rivinumero = 1; Muuttuja on pakko määritellä ennen käyttöä. Määrittelyn yhteydessä voidaan myös antaa alkuarvo, eli se voidaan alustaa. Myöhemmin muuttujan arvoa voi muuttaa sijoittamalla. int a; int b = 5; int c(7); a = 10; b = 18; // Määrittely // Määrittely ja alustus // Määrittely ja alustus // Sijoitus // Sijoitus
56 OHJ-1101 Ohjelmointi 1e Pääsääntöisesti muuttujiin voi tallettaa vain tietoa, joka on saman tyyppistä kuin muuttujan oma tyyppi. (Tähän palataan kohdassa tyyppimuunnokset.) Kääntäjä huomaa, jos erityyppisiä asioita yritetään yhdistää väärällä tavalla: esim. kokonaisluvusta yritetään vähentää merkkijono. C++:ssa tämä varmistusmekanismi ei toimi niin hyvin kuin voisi toivoa, koska useat tyypit voidaan tulkita suoraan kokonaisluvuiksi. Muista aina muuttujaa määritellessäsi pysähtyä miettimään, minkälaista tietoa siihen on tarkoitus tallentaa. Tiedon tyyppi määrää muuttujan tyypin.
57 OHJ-1101 Ohjelmointi 1e Muuttujia voi C++:ssa määritellä mm. seuraavissa paikoissa: Minkä tahansa lohkon (eli aaltosulkuparin {) sisällä sellaisessa kohdassa, jossa voisi olla lause. Tällaista muuttujaa kutsutaan paikalliseksi muuttujaksi ja se on käytettävissä vain sen lohkon sisällä (sulkevaan -merkkiin saakka), jossa se on määritelty. Kaikkien lohkojen ulkopuolella, jolloin kyseessä globaali muuttuja, tai mikäli käytetään tarkenninta static tiedostokohtainen muuttuja. Älä käytä globaaleja muuttujia! Muuttujat tulee määritellä mahdollisimman pienelle näkyvyysalueelle. Lähellä käyttöpaikkaa määritellyt ja alustetut muuttujat lisäävät ohjelmakoodin selkeyttä. Jokainen muuttuja on määriteltävä eri lauseessa. Muuttujan tyyppi, nimi, alustus ja sitä koskeva kommentti ovat usein yhdelle riville sopiva kokonaisuus.
58 OHJ-1101 Ohjelmointi 1e Perustyyppisten muuttujien käyttäminen on hyvin suoraviivaista: bool onkokiire = true; int i = 3; i = i + 2; // nyt i:n arvo on 5 char alkukirjain = 'E'; Koska merkkijonotyyppi string ei ole C++:n perustyyppi, täytyy tiedoston alkuun lisätä rivi #include <string>, jos haluaa käyttää merkkijonomuuttujia. Muuten käsittely tapahtuu samoin: string etunimi = "Teemu"; string sukunimi = "Teekkari"; string kokonimi = etunimi + " " + sukunimi; Tärkeintä on muistaa alustaa muuttuja johonkin arvoon aina määriteltäessä. Voidaan varmistua, että muistipaikassa todella on sitä, mitä pitää, eikä jäänteitä jostain aikaisemmasta muuttujasta. Vältytään kummallisilta virheiltä. VIP-esimerkki: 1.6.
59 OHJ-1101 Ohjelmointi 1e Harjoitus jatkuu... Mistä asioista ympyrän mittoja laskevassa ohjelmassa kannattaisi tehdä muuttujat? Muuta jännitteen ja sähkötehon laskeva ohjelmasi resistanssin ja virran arvojen suhteen helpommin muunneltavaksi käyttämällä muuttujia. int main() {
60 OHJ-1101 Ohjelmointi 1e Merkkimuuttujista C++:ssa merkkimuuttuja on toteutettu siten, että talletetaan merkin ASCII-arvo. Joskus tätä voi käyttää hyödyksi. char-muuttujaan voidaan sijoittaa merkin ASCII-arvo suoraan lukuna, mutta tämä ei ole suositeltavaa, koska ei ole taattua, että merkistö olisi sama joissain muussa ympäristössä. Koodin siirrettävyys kärsii. char c = 113; cout << c << endl; // Tulostuu "q" Erikoismerkkejä: '\n' (rivinvaihto), '\t' (tabulaattori), '\a' (piippaus), '\\' (kenoviiva), '\'' (hipsu), '\b' (backspace), '\' (lainausmerkki).
61 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita ohjelma, joka tulostaa tekstin k:sta seuraavat kirjaimet ovat lmn... siten, että se on helppo muuttaa muillekin aakkosille toimivaksi. int main() { Mitä ongelmia ohjelmassa on?
62 OHJ-1101 Ohjelmointi 1e Lukualueet Sisäisesti tietokone esittää luvut kaksikantaisina (binäärilukuina) jollain äärellisellä määrällä nollia ja ykkösiä (bittejä). Lukualueet, joita se voi esittää ovat rajallisia. Yksittäisen tyypin lukualue eli mitä kaikkia arvoja se voi saada, riippuu siitä, kuinka monella bitillä tyyppi on esitetty. Esimerkiksi jos etumerkitön kokonaisluku olisi 16 bittiä pitkä, sen arvo olisi aina välillä: 0... (2 16 1) Tai jos ajatellaan tyyppiä int, jossa yksi bitti käytetään etumerkin esittämiseen, olisivat arvot välillä: (2 15 1)
63 OHJ-1101 Ohjelmointi 1e Useimmiten int on kuitenkin vähintään 32-bittinen, jolloin sen suurin arvo on Ohjelma voi näennäisesti toimia, vaikka jonkin tyypin lukualue vahingossa ylittyisi. Seurauksena on ylivuoto, jolloin muuttujan arvo on täysin väärä, mutta kuitenkin käytettävissä. Erittäin vaikeasti löydettävä virhe. Älä tee optimistisia oletuksia! int i = ; i = i * 100; // i on ? cout << i << endl; // Tulostuu: ! Vastaavasti alivuoto on tilanne, jossa liukuluvuilla laskettaessa syntyy itseisarvoltaan niin pieni tulos, ettei esitystarkkuus riitä.
64 OHJ-1101 Ohjelmointi 1e Lukualueeseen voi yrittää vaikuttaa tarkentimilla: short long unsigned signed Pienentää lukualuetta Suurentaa lukualuetta Ei-negatiiviset luvut Etumerkilliset luvut Tarkentimien oletustyyppi on int, joten myös tyypit short, long, signed ja unsigned ovat kokonaislukuja. short sopii ainoastaan tyypin int yhteyteen ja long tyyppeihin int ja double. char hyväksyy vain tarkentimet signed ja unsigned. bool ei hyväksy mitään tarkentimia. Tyyppitarkentimia voi myös yhdistellä unsigned long int isoluku; Useimmiten tyyppien pituuksista puhutaan tavuina. C++:ssa tavu on charin koko. Operaattorilla sizeof saadaan selville kuinka monta tavua tyyppi vie, esim: cout << "Integerin koko on " << sizeof(int) << " tavua." << endl; Tyyppien lukualueet löytyvät myös tiedostoista climits (kokonaislukutyypit) ja cfloat (desimaaliluvut), joissa ne on määritelty vakioina.
65 OHJ-1101 Ohjelmointi 1e Ohjelmien siirrettävyyden kannalta on hankalaa, että perustyyppien kokoja ei ole standardoitu, vaan kääntäjä saa toteuttaa ne kuten parhaaksi näkee. Eri tietokoneissa on erilaiset lukualueet. Joitakin sääntöjä kuitenkin on: char-tyypin on oltava tarpeeksi iso, jotta koko käytetty merkistö mahtuu siihen. Merkit esitetään ASCII-arvoina eli kokonaislukuina. sizeof(char) on 1. Tarkentimien merkityksestä voi olettaa: short int long float double long double Esimerkki: joidenkin tyyppien tavumääriä kahdessa eri koneessa: tyyppi tutor mozart bool 1 1 char 1 1 short int 2 2 int 4 4 long int 8 4
66 OHJ-1101 Ohjelmointi 1e Harjoitus Minkä tyyppiseen muuttujaan tallettaisit seuraavat tiedot C++ohjelmassa: TTY:n opiskelijanumero kengän numero ihmisen pituus ja paino pankkitilin saldo säätiedotuksen lämpötila-arvio matka kahden galaksin välillä
67 OHJ-1101 Ohjelmointi 1e Literaalit Literaalit ovat tietoalkioita, joilla on vain tyyppi ja arvo, mutta ei nimeä. Literaaleja voi ajatella myös nimettöminä vakioina. Literaalin muoto kertoo sen tyypin: Merkkiliteraali on hipsujen välissä, esim. 'e'. Merkkijonoliteraali on lainausmerkkien välissä, esim. "Hip!". Kokonaislukuliteraalin voi antaa paitsi kymmenkantaisena 47 myös oktaalisena 057 tai heksadesimaalisena 0x2f. Jos haluaa literaalin joksikin muuksi kokonaislukutyypiksi kuin int, sen perään laitetaan lippuja, esim. 452U on unsigned int, L on long int ja UL on unsigned long int tyyppiä. Liukulukuliteraalin tunnistaa siinä olevasta pisteestä, esim. 23., 3.4 ja Jenkkisysteemissä on desimaalipiste eikä desimaalipilkku. Liukulukuliteraalissa voi olla myös eksponentti, esim. 2.3e-12 tarkoittaa lukua 2, Liukuluvun oletustyyppi on double.
68 OHJ-1101 Ohjelmointi 1e Lauseet ja lausekkeet C++:ssa yhtä "käskyä" eli kokonaisuutta, joka päättyy puolipisteeseen kutsutaan lauseeksi. Ohjelma etenee siten, että lauseita suoritetaan järjestyksessä. Lause voi koostua useista eri osista. Osaa, jolle evaluoituu jokin arvo kutsutaan lausekkeeksi. Lausekkeet koostuvat termeistä ja operaattoreista. Esim. lausekkeissa ja eka + toka operaattorina on + ja termeinä molemmat yhteenlaskettavista. Termi voi olla esimerkiksi luku tai muuttuja. Lausekkeille evaluoituvat arvot saadaan laskettua, kun tiedetään, miten operaattori käyttäytyy ja mitä arvoja termeillä on. Evaloitunutta arvoa voi sitten käyttää missä tahansa, mihin saman tyyppinen literaali sopisi. Sen voi esimerkikisi sijoittaa johonkin muuttujaan: a = Seuraavaksi tutustutaan tarkemmin operaattoreihin.
69 OHJ-1101 Ohjelmointi 1e Operaattorit Olemme jo tutustuneet sijoitus-, sizeof ja joihinkin aritmeettisiin operaattoreihin, mutta pelkästään niiden avulla emme voi tehdä kovin monia asioita. cout:in <<-operaattori ei sinällään ole kielen perusoperaatio, siihen palataan myöhemmin. C++:ssa on paljon muitakin operaattoreita. Huomaa, että vastaavat operaattorit löytyvät suurella todennäköisyydellä monesta muustakin kielestä, tosin ehkä erinäköisinä. Aritmeettiset operaattorit: +,, *, / ja % (jakojäännös). Operaation tuloksena evaluoituu (yleensä) saman tyyppinen alkio, kuin millä operoidaan. Aritmeettisten operaattoreiden lisäksi on olemassa myös esim. vertailuoperaattoreita, loogisia (boolen) operaattoreita ja bittikohtaisia operaattoreita, joista osaa tutkitaan hiukan myöhemmin tarkemmin.
70 OHJ-1101 Ohjelmointi 1e C++:ssa (lähes) kaikkien operaattorien tuloksena evaluoituu arvo, jota voidaan käyttää operandina muille operaattoreille. Esim. lausekkeessa 3 * 8-2 operaattorin - operandeina ovat lausekkeen 3 * 8 arvo ja 2. Kokonaislukujen jakolaskussa tulos pyöristetään alaspäin, esim. 8 / 3 = 2. Negatiivisilla luvuilla pyöristyssuunta ja jakojäännöksen merkki riippuvat kääntäjän toteutuksesta ( implementation dependent). Unaarisella (unary ) operaattorilla on vain yksi operandi, esim. etumerkki -. Binääriset (binary ) operaattorit ovat kaksioperandisia, esim. aritmeettiset operaattorit. C++:ssa on myös yksi ternaarinen ( ternary ) operaattori, jolla on kolme operandia:? :. Operandit sisältävässä muodossa: a? b : c C++ käyttää ns. inx-notaatiota, jossa operaattori tulee operandiensa väliin. Muitakin mahdollisuuksia on: inx C prex Scheme postx PostScript
71 OHJ-1101 Ohjelmointi 1e Lausekkeiden evaluointi Seuraava taulukko esittelee lähes kaikki C++-kielen operaattorit, niiden laskujärjestyksen ja sitomisjärjestyksen: : :. > [ ] ( ) muuttuja ++ muuttuja ~! lauseke + lauseke ++ muuttuja muuttuja & muuttuja * lauseke sizeof new delete * / % + << >> < <= > >= ==!= & ^ && = *= /= %= += = <<= >>= &= = ^= lauseke? lauseke : lauseke lauseke, lauseke
72 OHJ-1101 Ohjelmointi 1e Laskujärjestys (presedenssi) Operaattori lasketaan ( evaluoidaan) sitä aikaisemmin, mitä ylemmässä lokerossa se on taulukossa. Suluilla evaluointijärjestys voidaan määrätä halutuksi. Jotkut operaattorit (+, -, * ja &) esiintyvät taulukossa kahteen kertaan: korkeammalla olevat ovat unaarioperaattoreita alemmat ovat binääri-operaattoreita Esimerkiksi lauseke: a = 1 * / 4; evaluoituu samoin kuin jos olisi kirjoitettu: ( a = ( ( 1 * 2 ) + ( ( -3 ) / 4 ) ) ); Kyseessä siis on aivan sama asia kuin matematiikasta tutuissa laskujärjestyssäännöissä, paitsi että C++:ssa operaattoreita on paljon enemmän.
73 OHJ-1101 Ohjelmointi 1e Sitomisjärjestys (assosioituminen) Presedenssisäännöt eivät kerro kaikkea lausekkeen evaluointijärjestyksestä, jos samassa lausekkeessa on peräkkäin useita samalla tasolla olevia operaattoreita. Tällaiset tilanteet ratkaisee operaattorin sitomisjärjestys, joka voi olla: vasemmalta oikealle, jolloin operaatiot suoritetaan vasemmalta oikealle oikealta vasemmalle, luonnollisesti päinvastoin Taulukossa sitomisjärjestys on merkitty nuolella vasempaan sarakkeeseen. Esimerkiksi: evaluoidaan C++:ssa siis: ( ( ( 1-2 ) - 3 ) - 4 ) Sitomisjärjestyksellä on merkitystä esimerkiksi yli- ja alivuototilanteissa ja pyöristysvirheiden kanssa.
74 OHJ-1101 Ohjelmointi 1e Mikäli olet epävarma evaluointijärjestyksestä, käytä sulkuja. Oikeastaan voisit käyttää sulkuja, vaikka olisitkin varma, koska ne useimmiten selkeyttävät lausekkeen rakennetta. Lopuksi horror-esimerkki siitä, miten koodin luettavuuden voi helposti pilata operaattoreiden avulla: unsigned x = 20; int p = 3; int n = 2; unsigned b = (x >> (p+1-n)) & ~(~0u << n); Mitä talletetaan muuttujaan b? Miten koodipätkää voisi selkeyttää? Vastaus: x:stä n bittiä alkaen bitistä p, eli tässä tapauksessa 20 = ja siitä 2 bittiä alkaen bitistä numero 3 eli oikealta laskien kolmannesta (indeksointi alkaa nollasta oikealta), siis 01 2.
75 OHJ-1101 Ohjelmointi 1e Esimerkki Suunnitellaan ohjelma, joka kysyy kokonaisluvun ja ilmoittaa, onko se parillinen vai pariton. Tarvitaan ehtorakenne ja hiukan matematiikkaa. Ratkaisualgoritmi: Algoritmi: Parillinen vai pariton? luku kysy käyttäjältä kokonaisluku IF luvun jakojäännös 2:n suhteen on 0 THEN ELSE tulosta, että on parillinen tulosta, että on pariton lopeta ohjelma
76 OHJ-1101 Ohjelmointi 1e Algoritmin toteutus C++:lla: #include <iostream> #include <cstdlib> using namespace std; int main() { cout << "Syötä luku: "; int i = 0; cin >> i; if ( i % 2 == 0 ) { cout << "Luku " << i << " on parillinen." << endl; else { cout << "Luku " << i << " on pariton." << endl; return EXIT_SUCCESS; VIP-esimerkki: 2.1.
77 OHJ-1101 Ohjelmointi 1e Ohjelmaa voitaisiin testailla esim. seuraavasti: proffa>./parillisuus Syötä luku: 42 Luku 42 on parillinen. proffa>./parillisuus Syötä luku: 13 Luku 13 on pariton. proffa> Ohjelmasta opittua: Muuttujaan voidaan tallettaa arvo myös lukemalla käyttäjän syötettä operaattorilla >> virrasta cin. Toimii kuten sijoitus. Operaattori == vertailee lausekkeiden yhtäsuuruutta. C++:ssa on if-rakenne ehdollista suorittamista varten. Ohjelman suoritus voi haarautua. Huom! Ohjelma ei tarkista käyttäjän antaman syötteen oikeellisuutta.
78 OHJ-1101 Ohjelmointi 1e Lisää operaattoreita C++:ssa on perustietotyyppien vertailuun käytettävissä seuraavat vertailuoperaattorit : Operaattori Merkitys == yhtäsuuri kuin!= erisuuri kuin < pienempi kuin <= pienempi tai yhtäsuuri kuin > suurempi kuin >= suurempi tai yhtäsuuri kuin Kaikki vertailuoperaattorit ovat binäärioperaattoreita: ne vertailevat kahta tietoalkiota. Vertailun tuloksena evaluoituu bool-tyyppinen arvo true (tosi) tai false (epätosi) riippuen siitä, pitikö vertailulausekkeessa esitetty väite paikkansa vai ei. Huom! = on sijoitus ja == on yhtäsuuruusvertailu!
79 OHJ-1101 Ohjelmointi 1e Usein if-rakenteen ehto on monimutkaisempi kuin yhden vertailuoperaattorin tulos. Mielivaltaisia ehtorakennelmia saadaan aikaan yhdistelemällä sopivasti loogisia operaattoreita:! ei-operaattori (unaarinen) : tosi, jos operandi on epätosi. && ja-operaattori (binäärinen) : tosi, jos molemmat operandit ovat tosia. tai-operaattori (binäärinen) : tosi, jos edes toinen operandi on tosi. Loogisia operaattoreita voi olla monta perätysten presedenssi laskeva seuraavasti:!, && ja sitomisjärjestys &&- ja -operaattoreilla ja! -operaattorilla
80 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita lauseke, joka on tosi, kun muuttujaan vuosi on talletettu jonkin karkausvuoden vuosiluku. (Vinkki: Karkausvuosia ovat kaikki neljällä jaolliset vuodet, paitsi eivät sadalla jaolliset vuodet. Poikkeuksena neljällä sadalla jaolliset vuodet ovat karkausvuosia.) int main() { int vuosi = 0; cin >> vuosi; if( ) { cout << "Vuosi " << vuosi << " on karkausvuosi." << endl; else { cout << "Vuosi " << vuosi << " ei ole karkausvuosi." << endl; return EXIT_SUCCESS; VIP-esimerkit: 1.3. ja 1.4.
81 OHJ-1101 Ohjelmointi 1e if-rakenne if-rakenne on monipuolisin tapa toteuttaa ehdollista suoritusta C++-kielessä. if-rakenteen yleinen muoto on: if ( ehto1 ) { lauseita1;... else if ( ehto2 ) { lauseita2;... // tähän tarvittava määrä else-if-haaroja else { lauseitan;...
82 OHJ-1101 Ohjelmointi 1e Ehtoja lähdetään tutkimaan ylhäältä alas, ja kun löytyy ehto, joka evaluoituu todeksi, suoritetaan siihen liittyvät lauseet ja jatketaan ohjelman suoritusta if-rakennetta seuraavasta lauseesta. else-haaran lauseet suoritetaan vain, jos mikään edeltävä ehto ei evaluoitunut todeksi. else if- ja else-haarat eivät ole pakollisia. if ei välttämättä suorita mitään haaraa, jos else puuttuu, eikä mikään ehto evaluoidu todeksi. Aaltosulkeet eivät ole pakollisia, jos haarassa vain yksi suoritettava lause. Koodin luettavuus saattaa kuitenkin kärsiä, jos aaltosulkeita jättää pois, joten ne kannattaa aina kirjoittaa. Lisäksi sulkeiden kirjoittaminen vähentää virheiden mahdollisuutta.
83 OHJ-1101 Ohjelmointi 1e Ohjelma, joka laskee viikon palkan ylityölisän huomioiden: #include <cstdlib> #include <iostream> using namespace std; int main() { cout << "Syötä tuntipalkka: "; double tuntipalkka = 0; cin >> tuntipalkka; cout << "Syötä työtunnit: "; double tunnit = 0; cin >> tunnit; double palkka = 0; if( tunnit < 40 ) { palkka = tuntipalkka*tunnit; else { palkka = tuntipalkka* *( tunnit - 40 )*tuntipalkka; cout << "Palkka on " << palkka << "." << endl; return EXIT_SUCCESS; VIP-harjoitus: 2.2.
84 OHJ-1101 Ohjelmointi 1e Esimerkki sisäkkäisistä if-rakenteista kun on määritelty muuttuja int vuosi, joka sisältää vuosiluvun: if ( v % 4 == 0 ) { // vuosi on jaollinen 4:llä -> voi olla karkausvuosi if ( v % 100 == 0 ) { // vuosi on jaollinen 4:llä ja 100:lla -> voi olla karkausvuosi if ( v % 400 == 0 ) { // vuosi on jaollinen 4:llä, 100:lla ja 400:llä cout << "Vuosi " << v << " on karkausvuosi." << endl; else { // vuosi on jaollinen 4:llä ja 100:lla muttei 400:llä cout << "Vuosi " << v << " ei ole karkausvuosi." << endl; else { // vuosi on jaollinen 4:llä mutta ei 100:lla cout << "Vuosi " << v << " on karkausvuosi." << endl; else { // vuosi ei ole jaollinen 4:llä cout << "Vuosi " << v << " ei ole karkausvuosi." << endl; VIP-esimerkki: 2.5.
85 OHJ-1101 Ohjelmointi 1e Ohjelma, joka laskee painoindeksin ja tekee vielä ylimääräisen tarkastuksen, ettei käyttäjä ole vahingossa syöttänyt pituuttaan senttimetreinä: 1 #include <cstdlib> #include <iostream> 4 using namespace std; int main() { 8 double pituus = 0; cout << "Anna pituutesi metreinä: "; cin >> pituus; 12 double paino = 0; cout << "Anna painosi kiloina: "; cin >> paino; 16 if( pituus <= 0 paino <= 0 ) { cout << "Virheellinen syöte!" << endl; return EXIT_FAILURE; 20 double indeksi = paino / ( pituus * pituus );
86 OHJ-1101 Ohjelmointi 1e if( indeksi > 40 ) { 24 cout << "Olet elefantti." << endl; else if( indeksi > 25 ) { cout << "Olet liian lihava." << endl; else if( indeksi > 20 ) { 28 cout << "Olet liian normaali." << endl; else { // Tehdään tarkastuslasku, koska jos käyttäjä on vahingossa ilmoittanut 32 // painonsa senttimetreinä metrien sijaan, painoindeksi on liian pieni pituus = pituus / 100; // Muutetaan pituus cm -> m indeksi = paino / ( pituus * pituus ); 36 if( indeksi >= 20 && indeksi <= 25 ) { cout << "Tarkasta, ettet vahingossa syöttänyt pituutta " << "senttimetreinä metrien sijaan." << endl; return EXIT_FAILURE; 40 else { cout << "Olet liian laiha." << endl; 44 return EXIT_SUCCESS;
87 OHJ-1101 Ohjelmointi 1e Harjoitus Keksi esimerkkejä ja pohdi: Mitä eroa on else- ja else if -rakenteilla? Mitä eroa on else if -rakenteella ja else-rakenteella, jonka sisällä on if-rakenne? Mitä eroa on peräkkäisillä ja sisäkkäisillä if-rakenteilla? Mitä eroa on if - else if -rakenteella ja kahdella peräkkäisellä ifrakenteella? VIP-esimerkit: 2.2., 2.3. ja 2.4. ja VIP-harjoitus: 2.3.
88 OHJ-1101 Ohjelmointi 1e C++:ssa on sudenkuoppia, jotka mahdollistavat sen, että pieni kirjoitusvirhe saa aikaan kääntyvän ohjelman, joka toimii kummallisesti. Yksi näistä on sijoitusoperaattorin = sekoittaminen vertailuoperaattoriin ==. if ( a = 0 ) { // Pitäisi tietenkin olla a == 0 // Ehto ei ole tosi, joten tätä ei koskaan suoriteta... Jotkut kääntäjät antavat tästä varoituksen, toiset eivät. Jos ehtona on bool-muuttuja tai lauseke onkstosi, älä käytä muotoa onkstosi == true. Pelkkä onkstosi riittää. Miten ehto on järkevä kirjoittaa, jos if-rakenne halutaan suorittaa, kun muuttuja onkstosi on arvoltaan false? Lisää aiheesta kohdassa tyyppimuunnokset.
89 OHJ-1101 Ohjelmointi 1e &&- ja -operaattorit ovat oikosulkuevaluoituvia: toisin kuin aritmeettiset operaattorit, ne eivät aluksi laske molempia operandejaan, vaan suorittavat evaluoinnin operandi kerrallaan vasemmalta oikealle ja lopettavat heti, kun tulos on pääteltävissä ( short circuit evaluation). Tällä on merkitystä tilanteissa, joissa halutaan pukea ehdoksi lauseke, jonka evaluointi ei kaikissa tilanteissa ole laillista. Jos esimerkiksi halutaan testata, onko muuttujan luku arvo tasan jaollinen muuttujan jakaja arvolla: int luku = 0; int jakaja = 0;... if ( jakaja!= 0 && luku % jakaja == 0 ) {... jossa &&-operaattorin oikosulkulaskenta takaa sen, ettei ehtolausekkeessa koskaan yritetä ottaa jakojäännöstä nollan suhteen. Toista vertailua ei lasketa, jos jakaja == 0.
90 OHJ-1101 Ohjelmointi 1e Muuttujien näkyvyysalueista Muuttujia (paitsi globaaleja) voi käyttää vain siinä lohkossa, jossa ne on määritelty. Kutsutaan näkyvyysalueeksi ( scope). Lohkossa näkyvät siinä ja ulommissa lohkoissa määritellyt sekä globaalit muuttujat. if( opiskelijanumero!= 0 ) { int vuosikurssi = 0; cin >> vuosikurssi;... cout << vuosikurssi << endl; // Virhe! Miten korjaat tilanteen?
91 OHJ-1101 Ohjelmointi 1e Normaalisti uusia muuttujia määriteltäessä keksitään aina uusi nimi. Jos kuitenkin sisemmässä lohkossa määritellään uudelleen (vahingossa tai tahallaan) samanniminen muuttuja kuin ulommassa lohkossa, tämä peittää ulommassa lohkossa määritellyn. Esim: int a = 1; int b = 2; int c = a + b; // c on if ( c > 0 ) { int local = 4; int a = 0; // Uusi a! c = a + b; // c on local = local + 1; // Virhe! Jotkut kääntäjät antavat varoituksen muuttujan peittymisestä.
92 OHJ-1101 Ohjelmointi 1e Ennen if-lausetta ohjelmassa on seuraavat muuttujat: Kun if-lause alkaa, peittää uusi (sisempi) näkyvyysalue aiemmat saman nimiset muuttujat. Sisemmässä näkyvyysalueessa ei kuitenkaan ole c-nimistä muuttujaa, joten ulomman näkyvyysalueen c näkyy myös sisempään näkyvyysalueeseen. Kun if-lause loppuu, poistetaan sisempi näkyvyysalue, joten muuttujaa local ei ole enää olemassa ja siksi sen käyttäminen aiheuttaa virheen.
93 OHJ-1101 Ohjelmointi 1e Esimerkki Ratkaistava ongelma: Tulosta yhden Celsius-asteen välein käyttäjän antaman alarajan ja ylärajan väliltä Celsius-lämpötiloja vastaavat Fahrenheit-lämpötilat. Tulostuksen selkeyttämiseksi numeroi tulostetut rivit. Hahmotellaan ratkaisua: Algoritmi: CelsiusFahrenheit -taulukko kysy käyttäjältä alin tulostettava Celsius-lämpötila alin celsius käyttäjältä luettu syöte kysy käyttäjältä ylin tulostettava Celsius-lämpötila ylin celsius käyttäjältä luettu syöte rivinumero 1 tulostettava celsius alin celsius WHILE tulostettava celsius ylin celsius fahrenheit 1.8 * tulostettava celsius + 32; tulosta rivinumero, tulostettava celsius ja fahrenheit rivinumero rivinumero + 1 tulostettava celsius tulostettava celsius + 1
94 OHJ-1101 Ohjelmointi 1e Algoritmin toteutus C++:lla: #include <iostream> #include <cstdlib> using namespace std; int main() { int alin = 0; int ylin = 0; cout << "Alin tulostettava C-lämpötila: "; cin >> alin; cout << "Ylin tulostettava C-lämpötila: "; cin >> ylin; int rivi = 1; int c = alin; while ( c <= ylin ) { double f = 1.8 * c + 32; cout << rivi << ": " << c << " C = " << f << " F" << endl; rivi = rivi + 1; c = c + 1; return EXIT_SUCCESS;
95 OHJ-1101 Ohjelmointi 1e Käännös ja suoritus: proffa> tutg++ -o celsius celsius.cc proffa>./celsius Alin tulostettava C-lämpötila: -5 Ylin tulostettava C-lämpötila: 4 1: -5 C = 23 F 2: -4 C = 24.8 F 3: -3 C = 26.6 F 4: -2 C = 28.4 F 5: -1 C = 30.2 F 6: 0 C = 32 F 7: 1 C = 33.8 F 8: 2 C = 35.6 F 9: 3 C = 37.4 F 10: 4 C = 39.2 F Huomioita: while-silmukkarakenteella voidaan toistaa joitain käskyjä haluttu määrä kertoja. Silmukkarakenne vaatii suunnittelua. VIP-esimerkki: 3.1.
96 OHJ-1101 Ohjelmointi 1e while-silmukka while ( ehto ) { lause.1;... lause.n; // runko alkaa // runko loppuu Jos lauseita on vain yksi, aaltosulut voi jättää pois, mutta yleensä on selkeämpää ja turvallisempaa kirjoittaa ne silti. while toistaa rungossaan olevia lauseita niin kauan kuin ehto evaluoituu todeksi juuri ennen uutta kierrosta. Heti, kun ehto evaluoituu ennen uutta kierrosta epätodeksi, ohjelman suoritus jatkuu while-rakenteen jälkeen seuraavasta lauseesta. Ehto evaluoidaan aina ensimmäisenä ennen uuden kierroksen aloittamista. Jos se on heti aluksi epätosi, silmukan runkoa ei suoriteta kertaakaan. Ehto voi olla mikä tahansa lauseke, jolle evaluoituu arvo true tai false. Kuten if-lauseenkin ehtoon, tähän sopii melkein mitä vain. VIP-esimerkki: 3.2.
97 OHJ-1101 Ohjelmointi 1e Muuttujien roolit Tarkastellaan edellisen esimerkin muuttujien saamia arvoja ohjelmaa ajettaessa. Huomaamme, että esimerkiksi muuttuja alin saa arvon vain kerran ohjelman suorituksen aikana, kun taas esimerkiksi muuttuja rivi saa uuden arvon toistuvasti silmukassa. Kyseiset muuttujat siis käyttäytyvät ohjelmassa täysin eri tavoin. Kun muuttujien saamien arvojen sarjaa ohjelman suorituksen edetessä seurataan, voidaan erottaa erilaisia käyttäytymismalleja. Näitä kutsutaan muuttujien rooleiksi. Lähes jokainen muuttuja käyttäytyy jonkin roolin mukaisesti.
98 OHJ-1101 Ohjelmointi 1e Muuttujan rooli: Kiintoarvo Muuttujan rooli on kiintoarvo, jos sille annetaan tarkoituksenmukainen arvo vain kerran ohjelman suorituksen aikana, eikä arvoa muuteta sen jälkeen. Kiintoarvoon voidaan viitata ohjelman eri kohdissa, esim. sitä voidaan käyttää laskemiseen tai se voidaan tulostaa. Fahrenheit-esimerkissä muuttujille alin ja ylin, kysyttiin ohjelman käyttäjältä arvot alustamisen jälkeen. Sen jälkeen niitä käytettiin ainoastaan muiden muuttujien alustamisessa ja vertailussa. alin ja ylin ovat kiintoarvoja.
99 OHJ-1101 Ohjelmointi 1e Muuttujan rooli: Askeltaja Askeltaja käy läpi arvoja jollain systemaattisella tavalla. Fahrenheit-esimerkissä muuttujan rivi arvoksi annettiin ensin 1. Sen jälkeen riviä kasvatettiin jokaisella silmukan kierroksella yhdellä, eli se kävi läpi tietyn sarjan arvoja. riviä kutsutaan askeltajaksi. Myös muuttuja c on askeltaja, koska se käy järjestyksessä läpi arvot välillä alin ja ylin. Kiintoarvon ja askeltajan lisäksi rooleja on muitakin. Niihin palataan myöhemmissä esimerkeissä. Prujun lopussa olevassa liitteessä on lista kaikista muuttujien rooleista.
100 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita ohjelma, joka tulostaa suuruusjärjestyksessä kaikki kahden potenssit, jotka ovat pienempiä kuin , 2, 4, 8, 16, 32,... int main() { cout << "Kahden potensseja: "; return EXIT_SUCCESS; Mitkä roolit ohjelman muuttujilla on?
101 OHJ-1101 Ohjelmointi 1e Lämpötilamuunnosohjelman silmukkarakenne perustui silmukkamuuttujan käyttöön. Silmukan voi rakentaa myös muulla tavalla. Kirjoitetaan silmukkarakenne, joka kysyy käyttäjältä kokonaisluvun niin monta kertaa, että käyttäjä syöttää positiivisen luvun. cout << "Syötä neliön sivun pituus: "; double sivu = 0; cin >> sivu; while( sivu <= 0 ) { cout << "Luvun pitää olla positiivinen." << endl << "Uusi yritys: "; cin >> sivu; cout << "Neliön pinta-ala on " << sivu * sivu << endl; VIP-esimerkki: 3.4.
102 OHJ-1101 Ohjelmointi 1e Muuttujan rooli: Tuoreimman säilyttäjä Muuttuja on tuoreimman säilyttäjä, jos sen arvo on viimeisin jostakin tietystä joukosta läpikäyty arvo tai yksinkertaisesti vain arvo, joka on syötetty viimeksi. Edellisen kalvon esimerkissä muuttuja sivu on tuoreimman säilyttäjä, koska siihen on talletettuna kulloinkin viimeksi syötetty arvo.
103 OHJ-1101 Ohjelmointi 1e Harjoitus Korjaa edellistä silmukkarakennetta niin, että luvun uudelleen syöttämistä pyydetään maksimissaan 3 kertaa. Uudelleen syöttäminen lopetetaan tietenkin heti, kun saadaan positiivinen luku. cout << "Syötä neliön sivun pituus: "; double sivu = 0; cin >> sivu; while( ) { cout << "Luvun pitää olla positiivinen." << endl << "Uusi yritys: "; cin >> sivu; cout << "Neliön pinta-ala on " << sivu * sivu << endl;
104 OHJ-1101 Ohjelmointi 1e Silmukkarakenteet while on vain yksi tapa toteuttaa iteraatiota eli toistoa C++:ssa. Sen lisäksi on olemassa muita silmukoita, kuten do- ja for-silmukat. Kaikkien silmukkarakenteiden ideana on, että silmukan runkoa suoritetaan niin monta kertaa kuin jokin annettu ehto on voimassa. Ohjelmoinnin teorian kannalta silmukkoihin liittyvät käsitteet invariantti, esi- ja jälkiehto. Invariantti kertoo, mitkä olosuhteet pysyvät muuttumattomina silmukan suorituksen aikana. Invariantti pukee loogiseksi lauseeksi jonkin silmukkaan liittyvän tärkeän piirteen. Ennen silmukan suoritusta ohjelman tila toteuttaa esiehdon. Vastaavasti jälkiehto pitää paikkansa silmukan suorittamisen jälkeen. Invariantteja ja esi- ja jälkiehtoja käytetään mallinnettaessa ohjelmia formaalisti eli matemaattisen eksaktisti, esim. ohjelmia todistettaessa.
105 OHJ-1101 Ohjelmointi 1e Esim: Lasketaan muuttujaan tulos muuttujan kantaluku e:s potenssi while-silmukan avulla kertomalla muuttujan kantaluku arvo e kertaa itsellään. Ennen silmukkaa pitää olla talletettuna muuttujiin kantaluku ja e sopivat arvot (e > 0) ja muuttujaan tulos muuttujan kantaluku arvo. Lisäksi pitää olla alustettuna askeltaja a, jonka arvo on 1. Silmukan suorituksen aikana muutujaan tulos on koko ajan talletettuna kantaluku a. Huomaa, että tämä on voimassa jo alkuehdossa. Lisäksi koko ajan a < e. Silmukan päätyttyä muuttujassa tulos on talletettuna kantaluku e, koska muuttujaa a kasvatetaan niin kauan kuin se on pienempi kuin e. Näiden toteamisen jälkeen itse silmukka onkin helppo kirjoittaa: int a = 1; // askeltaja while ( a < e ) { tulos = kantaluku * tulos; a = a + 1; VIP-esimerkki: 3.9. ja VIP-harjoitus: 3.1.
106 OHJ-1101 Ohjelmointi 1e Tällä kurssilla näihin ei perehdytä sen formaalimmin, mutta on hyvä huomata, että silmukkarakenteiden ehtoa muodostettaessa pitää miettiä, mikä ohjelman tila silmukkarakenteeseen tultaessa on ja mikä sen pitää olla silmukan jälkeen. Ajatusvirhe voi helposti aiheuttaa ikuisen silmukan tai muita virheitä. Joskus ikuinen silmukka while( true ) {... kirjoitetaan tarkoituksella.
107 OHJ-1101 Ohjelmointi 1e do-silmukka do-silmukka eroaa whilestä siinä, että silmukan runko suoritetaan ehdosta riippumatta ainakin kerran. do-silmukan yleinen muoto: do { lause.1;... lause.n; while ( ehto ); // runko alkaa // runko loppuu Huomaa puolipiste silmukan lopussa! Jos ehdon arvoksi evaluoituu rungon suorituksen jälkeen true, suoritetaan runko uudelleen. Jos ehdon arvoksi evaluoituu false, jatketaan silmukan jälkeen seuraavasta käskystä.
108 OHJ-1101 Ohjelmointi 1e Sovitaan että myös kurssin algoritmikielessä on tämän jälkeen do-while-silmukka: DO kuka kysy käyttäjätunnus tiedot etsi tunnuksen kuka tiedot IF tietoja löytyi THEN ELSE tulosta löytyneet tiedot lopeta ohjelma WHILE käyttäjä haluaa jatkaa VIP-esimerkki: 3.8.
109 OHJ-1101 Ohjelmointi 1e for-silmukka for-silmukka sopii parhaiten tilanteisiin, joissa käytetään silmukkamuuttujaa. Esim. jos halutaan tulostaa luvut väliltä 10-20: for ( int i = 10; i <= 20; i = i + 1 ) { cout << "Luku on nyt " << i << endl; // i: askeltaja for-silmukan yleinen muoto: for ( alustus; ehto; askel ) { lause.1;... lause.n;
110 OHJ-1101 Ohjelmointi 1e Alustus suoritetaan vain kerran, juuri ennen kuin ehtoa testataan ensimmäistä kertaa. Mikäli alustuksessa esitellään uusi muuttuja, sen näkyvyysalue rajoittuu silmukan sisään (runko, ehto ja askel). Silmukan runko muodostaa vielä oman näkyvyysalueensa, eli siinä esitellyt muuttujat eivät näy ehdossa tai askeleessa. VIP-esimerkki: 3.3. ja VIP-harjoitus: 3.3.
111 OHJ-1101 Ohjelmointi 1e Kuten while-silmukassakin ehto testataan aina ennen rungon suorittamista. Jos lausekkeen ehto arvoksi saadaan laskettaessa true, niin suoritetaan rungon lauseet. Jos ehto on false, niin jatketaan silmukan jälkeen tulevasta lauseesta. Kun kaikki rungon käskyt on suoritettu (saavutaan loppuaaltosulkuun), niin suoritetaan askel ja palataan takaisin testaamaan ehtoa. On mahdollista, ettei runkoa suoriteta kertaakaan: jos ehto on heti alussa false. Pohjimmiltaan for-silmukka ei C++:ssa eroa while-silmukasta juuri mitenkään. Alustuksessa määritellyn muuttujan arvoakin pääsee käsittelemään silmukan rungossa. Kaiken, minkä voi tehdä whilesilmukalla voi tehdä myös for:illa ja päinvastoin.
112 OHJ-1101 Ohjelmointi 1e Esimerkki Kertotaulua tulostavassa ohjelmassa on käyttöä sekä do- että forsilmukalle. Myös while-silmukkaa voisi hyvin käyttää. #include <cstdlib> #include <iostream> using namespace std; int main() { int luku = 0; // Tuoreimman säilyttäjä do { cout << "Syötä positiivinen luku: "; cin >> luku; while( luku < 0 ); cout << "Luvun " << luku << " kertotaulu menee seuraavasti: " << endl; for( int i = 1; i <= 10; i = i + 1 ) { // i: askeltaja cout << luku << " * " << i << " = " << luku * i << endl; return EXIT_SUCCESS;
113 OHJ-1101 Ohjelmointi 1e Harjoitus jatkuu... Voiko kahden potensseja tulostavan ohjelman muuttaa toimimaan do- tai for-silmukalla? Miten? Onko se järkevää?
114 OHJ-1101 Ohjelmointi 1e Harjoitus Palautetaan sivun 60 harjoituksesta mieleen, että C++:ssa chartyyppisillä muuttujillakin voi laskea. Kirjoita ohjelma joka tulostaa kaikki aakkoset väliltä a - z. int main() { cout << "Aakkoset näin opitaan, lauletaanpas uudestaan!" << endl; return EXIT_SUCCESS;
115 OHJ-1101 Ohjelmointi 1e Kuten if-rakenteitakin, silmukoitakin voi sijoittaa toistensa sisään. int main() { int moneskokysymys = 1; // askeltaja while( moneskokysymys <= 10 ) { int lukumaara = 0; // askeltaja cout << "Montako merkkiä piirretään? "; cin >> lukumaara; while( lukumaara!= 0 ) { cout << '*'; lukumaara = lukumaara - 1; cout << endl; moneskokysymys = moneskokysymys + 1; return EXIT_SUCCESS; VIP-esimerkit: 3.5., 3.6. ja 3.7.
116 OHJ-1101 Ohjelmointi 1e Hyppykäsky goto Pohjimmiltaan kaikki silmukkarakenteet on toteutettu hyppyinä. C++:ssakin on fossiilinen hyppykäsky goto, esim: alku:... if( ehto ) {... goto alku; Älä käytä gotoa. Se tekee ohjelmasta kulusta vaikeasti seurattavan ja sillä luodut rakenteet ovat paitsi epäesteettisiä myös virhealttiita.
117 OHJ-1101 Ohjelmointi 1e break, continue ja silmukat Silmukan rungon suoritus voidaan keskeyttää kontrollin siirtokäskyillä break ja continue: break lopettaa silmukan suorituksen välittömästi ja jatkaa silmukkaa seuraavasta käskystä. continue aloittaa uuden silmukan kierroksen (hyppää rungon loppusulkuun). Käskyt vaikuttavat vain sen sisimmän silmukan toimintaan, jonka sisällä ne suoritetaan. Tapahtumien kulku while-silmukassa:
118 OHJ-1101 Ohjelmointi 1e do-while-silmukassa: for-silmukassa: break ja continuekin aiheuttavat kontrollin siirtymisen hyppäämällä. Niiden käyttäminen ei ainakaan yleensä selkeytä ohjelmaa. Älä käytä niitä liikaa.
119 OHJ-1101 Ohjelmointi 1e Esimerkki Tehdään peli, jossa otetaan arvailtavaksi jokin luku. Arvailijalla on kymmenen arvauskertaa käytettävissään. Muodostetaan silmukka, joka pyörähtää kymmenen kertaa. Arvauksen jälkeen arvailijalle annetaan vihje, onko luku suurempi vai pienempi. Jos arvaus oli oikein, vihjettä ei tietenkään tarvitse antaa, vaan voidaan poistua silmukasta sen keskeltä.
120 OHJ-1101 Ohjelmointi 1e int main() { int luku = 0; // Kiintoarvo cout << "Syötä luku, jota ryhdytään arvailemaan: "; cin >> luku; // Tässä vaiheessa tietenkin vaihdetaan pelaaja näppiksen ääreen :) for( int krt = 10; krt > 0; krt = krt - 1 ){ // krt: askeltaja cout << "Sinulla on jäljellä " << krt << " arvauskertaa." << endl; int arvaus = 0; // Kiintoarvo cout << "Syötä arvauksesi: "; cin >> arvaus; if( luku == arvaus ) { cout << "Arvasit oikein!" << endl; break; if( arvaus < luku ) { cout << "Luku on suurempi kuin arvauksesi." << endl; else { cout << "Luku on pienempi kuin arvauksesi." << endl; cout << "Peli loppui..." << endl; return EXIT_SUCCESS;
121 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita ohjelma, joka laskee yhteen syötettyjä hintoja, kunnes käyttäjä syöttää negatiivisen luvun ja tulostaa sen jälkeen summan. Onko ohjelma helpompi tehdä/selkeämpi lukea break-lausetta käytettäessä vai ilman?
122 OHJ-1101 Ohjelmointi 1e Tulosteen muotoilu Lämpötilaesimerkki olisi ollut paljon hienomman näköinen, jos tulosteet olisi muotoiltu seuraavasti: proffa>./celsius Alin tulostettava C-lämpötila: -5 Ylin tulostettava C-lämpötila: 4 1: -5 C = 23 F 2: -4 C = 24.8 F 3: -3 C = 26.6 F 4: -2 C = 28.4 F 5: -1 C = 30.2 F 6: 0 C = 32 F 7: 1 C = 33.8 F 8: 2 C = 35.6 F 9: 3 C = 37.4 F 10: 4 C = 39.2 F C++:ssa tulosteen muotoilu on mahdollista, kun lisää rivit #include <iomanip> ja #include <ios> ohjelman alkuun. Tällöin esimerkiksi: cout << setw(3) << rivi << ": " << setw(3) << tulost_c << " C = " << tulost_f << " F" << endl; muotoilisi tulosteen kuten yllä. Ainoa ero aikaisempaan on setw(3).
123 OHJ-1101 Ohjelmointi 1e Seuraavassa esitelty lyhykäisesti tärkeimmät tulostuksen muotoiluun käytetyt ohjauskomennot. Niitä ei käydä läpi sen yksityiskohtaisemmin, mutta ne on kerätty yhteen listaan: Ohjauskomento setw(leveys) setfill(täytemerkki) left right setprecision(tarkkuus) fixed Merkitys Tulostettava tieto vie aina vähintään leveys merkkiä tilaa. Asettaa merkin, jota setw käyttää tulosteen leventämiseen. Jos tulostettava tieto vie vähemmän tilaa kuin mikä tämänhetkinen tulostuskentän leveys on, tulostetaan kentän vasempaan laitaan. Kuten edellinen, mutta tulostetaan kentän oikeaan laitaan. Reaalilukuja tulostettaessa tarkkuus kpl. merkitseviä numeroita. Em. tarkkuus tulkitaan desimaalipisteen oikealle puolelle tulostettavien desimaalien määräksi. Lisää tietoa tulostuksenmuotoilusta löytyy kirjallisuudesta.
124 OHJ-1101 Ohjelmointi 1e Operaattorit i++ ja ++i C++:ssa sijoituslauseke i = i + 1 voidaan korvata lausekkeella i++ tai ++i. Nämä lausekkeet eivät kuitenkaan ole identtisiä. Esim: int i = 0; if( i++ == 1 ) { cout << "Hei!" << endl; i = 0; if( ++i == 1 ) { cout << "Hou!" << endl; Kummankin if:in jälkeen i on yksi, mutta ainoastaan "Hou!" tulostuu. Tämä johtuu siitä, että plussat määräävät, onko operaattorin paluuarvona i:n arvo ennen kasvatusta vai kasvatuksen jälkeen.
125 OHJ-1101 Ohjelmointi 1e Koodinpätkää kannattaa pitää varoittavana esimerkkinä: Operaattoreita i++ ja ++i kannattaa käyttää harkiten ja ehtolausekkeissa mielellään ei ollenkaan. Kannattaa käyttää mielummin operaattoria ++i kuin i++.
126 OHJ-1101 Ohjelmointi 1e Tyyppimuunnokset Tyyppimuunnoksen idea on tulkita muuttujan sisältämää dataa erityyppisenä kuin miksi se on määritelty. Tyyppimuunnos voi olla joko implisiittinen tai eksplisiittinen. Implisiittisen tyyppimuunnoksen tekee kääntäjä automaattisesti. Esim. float double ja int double ja int char. float f = 0.123; double d = f; double d = 3; char merkki = 113; // merkki on 'q' Eksplisiittisen tyyppimuunnoksen tekee ohjelmoija operaattorin static cast avulla. Esim. tulkitaan int char-tyyppisenä: char merkki = static_cast< char >( 113 ); // merkki on 'q'
127 OHJ-1101 Ohjelmointi 1e Kokeillaanpa vielä kerran: short int i = 22897; char c = static_cast< char >( i ); // c on jälleen merkki 'q'! int char Mitä tapahtui? Virhe! Muuttujaan c ilmestyi vain i:n alimman tavun arvo. ( = 113 = q:n ASCII-arvo.) Huomaa, että kyseessä ei suinkaan ole sama muistipaikka, vaan sama arvo: int i = 22897; char c = static_cast< char >( i ); // c on nyt merkki q int a = static_cast< int >( c ); // a on 113 Tyyppimuunnoksia, joissa tuloksen lukualue ei riitä, ei ole määritelty. Kääntäjä voi toteuttaa muunnoksen miten vain. Määrittelemättömiä ominaisuuksia ei pidä käyttää!
128 OHJ-1101 Ohjelmointi 1e Aritmeettisten operaattoreiden tulos on samaa tyyppiä kuin niiden operandien tyypit. Tyyppimuunnosta tarvitaan usein jakolaskuoperaattorin kanssa, koska esimerkiksi 1 / 2 tarkoittaa kokonaislukujakolaskua, eli tulos onkin nolla (pyöristys alaspäin). Jos kokonaislukujen jakolaskusta on tarve saada "tarkka" liukulukutulos, täytyy toinen operandi muuttaa liukuluvuksi: static cast< double >( 1 ) / 2 jolloin suoritettava laskutoimitus on 1.0 / 2 ja tulokseksi saadaan liukuluku 0.5. Nyrkkisääntönä: jos operandit ovat eri tyyppiä, tuloksena on lukualueeltaan laajempi tyyppi. Tyyppien int ja bool välillä tehdään myös implisiittinen tyyppimuunnos siten, että 0 tulkitaan falseksi ja kaikki muut arvot trueksi. Tästä johtuen pitää olla tarkkana, että ei if-rakenteen ehdossa kirjoita =, kun pitäisi kirjoittaa ==.
129 OHJ-1101 Ohjelmointi 1e Vakiot Muuttuja voi olla myös vakio, joka käyttäytyy aivan kuten normaali muuttuja, mutta sen arvoa ei määrittelyn jälkeen voi muuttaa. Vakio määritellään lisäämällä tyyppitarkennin const määrittelyn eteen: const int MAX KOKO = 100; Vakioille pitää alustaa arvo määrittelyn yhteydessä, sillä myöhemmin se ei ole mahdollista. Vakioiden käyttäminen selkeyttää koodia. Satunnainen lukija ymmärtää heti, mistä on kysymys, jos koodissa lukee if( koko < MAX_KOKO ) {... sen sijaan, että siinä lukisi if( koko < 100 ) {... Lisäksi koodin muunneltavuus paranee.
130 OHJ-1101 Ohjelmointi 1e Taulukot Taulukko on rakenteinen tietotyyppi, jolla on seuraavat ominaisuudet: sen alkiot ovat tietyssä järjestyksessä sillä on joku määrätty koko tietoalkiot, joista se koostuu, kuuluvat keskenään samaan tietotyyppiin C++:ssa taulukkomuuttujia määritellään seuraavasti: alkiontyyppi nimi[ koko ]; Saadaan taulukkotyyppinen muuttuja nimi, johon voidaan tallettaa koko kappaletta tietoalkioita, joiden tyyppi on alkiontyyppi. Alkion tyyppi voi olla mikä tahansa tietotyyppi. Koon pitää olla vakiolauseke, koska kääntäjän on tiedettävä sen arvo jo käännösaikana. Esimerkiksi yhdeksän alkion kokonaislukutaulukko saataisiin kirjoittamalla: int luvut[ 9 ];
131 OHJ-1101 Ohjelmointi 1e Intuitiivisesti taulukkoa voi ajatella joukkona laatikoita, joista jokaisella on järjestysluku, jolla laatikon sisältöä voidaan tutkia ja muuttaa. Yhteen laatikkoon mahtuu yksi arvo, jonka tyyppi on alkion tyyppi. C++:ssa laatikoiden numerointi lähtee nollasta ja päättyy ( koko 1 ):een. Esimerkiksi int luvut[ 9 ] näyttää siis seuraavalta: luvut: Viimeinen alkio on siis indeksiltään yhtä pienempi kuin taulukon koko. indeksoidaan) hakasulku- Taulukon alkioihin viitataan (taulukoa operaattorilla [], esim: luvut[ 8 ] = 2 * luvut[ 0 ]; joka asettaisi luvut-taulukon viimeisen alkion arvoksi kaksi kertaa sen ensimmäisen alkion arvon.
132 OHJ-1101 Ohjelmointi 1e Hakasulkuoperaattorin "sisällä" (operandina) voi olla mikä tahansa lauseke, jonka tyyppi on kokonaisluku. C++ ei todennäköisesti mitenkään tarkasta, onko taulukon käsittelyssä käytetty indeksi sallituissa rajoissa: int a = 1000; luvut[ a ] = 42; // Ohi-indeksointi (looginen virhe) Tämä menisi joistain kääntäjistä läpi virheittä, mutta on silti väärin: se viittaa alkioon, jota ei ole olemassa. Luonnollisesti taulukoille pätee sama kuin muuttujille yleisestikin: taulukko (sen alkiot) pitää alustaa jollain järkevillä arvoilla ennen kuin sitä voi käyttää. Taulukko voidaan alustaa määrittelyn yhteydessä: int luvut[9] = { 1, 3, 5, 7, 9, 2, 4 ; josta saataisiin tuloksena taulukko: luvut: Jos alustusalkioita on vähemmän kuin taulukon koko, alustetaan loput nolliksi.
133 OHJ-1101 Ohjelmointi 1e Taulukkoa alustettaessa voidaan koko jättää kertomatta, jolloin se määräytyy automaattisesti alustusalkioiden lukumäärästä: int luvut[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8 ; Nämä merkintätavat toimivat vain taulukkoa määrittelyn yhteydessä alustettaessa. Se ei ole yleiskäyttöinen taulukkoon sijoitusmenetelmä. Kokonaisia taulukoita ei voi sijoittaa toisiinsa =-operaattorilla, eikä niiden yhtä- ja erisuuruutta voi vertailla ==- ja!=-operaattoreilla. Kaikki nämä on tehtävä itse, alkio kerrallaan. Taulukot ovat staattisia tietorakenteita, mikä tarkoittaa, että niiden kokoa ei voi enää muuttaa, kun se on kerran määrittelyn yhteydessä annettu. Staatisen tietorakenteen vastakohta on dynaaminen tietorakenne, jolla ei ole ennalta määrättyä maksimikokoa. VIP-esimerkit: 4.1. ja 4.2.
134 OHJ-1101 Ohjelmointi 1e Esimerkki Ohjelma, joka käyttää liukulukutaulukkoa käyttäjän syöttämien fysiikantöiden mittaustulosten tallentamiseen: int main() { const int MAARA = 10; double mittaukset[ MAARA ]; double summa = 0; // Kokooja cout << "Syötä " << MAARA << " mittaustulosta." << endl; for( int i = 0; i < MAARA; ++i ) { // i: askeltaja cin >> mittaukset[ i ]; summa += mittaukset[ i ]; double keskiarvo = summa / MAARA; // Kiintoarvo cout << "Keskiarvo on " << keskiarvo << endl; cout << "Keskiarvoa suuremmat mittaustulokset:" << endl; for( int i = 0; i < MAARA; ++i ) { // i: askeltaja if( mittaukset[ i ] > keskiarvo ) { cout << "Mittaustulos nro " << i + 1 << ": " << mittaukset[ i ] << endl; return EXIT_SUCCESS; VIP-esimerkki: 4.3.
135 OHJ-1101 Ohjelmointi 1e Esimerkki ohjelman ajosta: Syötä 10 mittaustulosta Keskiarvo on 2.32 Keskiarvoa suuremmat mittaustulokset: Mittaustulos nro 2: 2.4 Mittaustulos nro 5: 2.4 Mittaustulos nro 6: 2.5 Mittaustulos nro 7: 2.9 Mittaustulos nro 9: 2.4 Huomioita: Vakion käyttö helpottaa ohjelman muokattavuutta. for-silmukka on erittäin käyttökelpoinen taulukon kanssa. i += j on lyhennemerkintä lausekkeelle i = i + j. Kun syötettä luetaan >>-operaattorilla, tyhjä tila syötteestä "häviää".
136 OHJ-1101 Ohjelmointi 1e Muuttujan rooli: Kokooja Kokooja on muuttuja, jonka arvo kerääntyy kaikista jollain menetelmällä läpikäydyistä arvoista. Edellisessä esimerkissä luetaan virrasta cin lukuja, jotka talletetaan taulukkoon. Samalla muuttujaan summa lasketaan syötettyjen lukujen summaa. summa on siis kokooja. Huomaa, että vaikka muuttujan keskiarvo sisältö määräytyy myös kahden muun muuttujan perusteella, se ei ole kokooja vaan kiintoarvo, koska keskiarvo asetetaan vain kerran.
137 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita ohjelma, joka lukee käyttäjältä kymmenen lukua ja tulostaa ne sitten päinvastaisessa järjestyksessä näytölle. int main() { Sano se suomeksi: Milloin taulukkoa kannattaa käyttää? VIP-harjoitukset 4.3., 4.2., 4.1. ja 4.4.
138 OHJ-1101 Ohjelmointi 1e sizeof-operaattori Operaattorilla sizeof saadaan selville muuttujan tai tietotyypin käyttämä muistin määrä: sizeof( muuttujan_nimi ) sizeof( tietotyypin_nimi ) sizeof-operaattorin tuloksena evaluoituu operandin koko tavuissa (1 tavu = 8 bittiä). sizeof on kätevä työkalu, kun halutaan selvittää taulukon alkioiden lukumäärä: const int KOKO = sizeof( taulukko ) / sizeof( alkion_tyyppi ); tai const int KOKO = sizeof( taulukko ) / sizeof( taulukko[ 0 ] ); jolloin koko-vakion arvo on aina oikea taulukon alkioiden lukumäärä, vaikka taulukon kokoa käännösten välillä lähdekoodissa muutettaisiinkin. Huomaa: sizeof ei toimi "oikein", jos operandi on funktion muodollisena parametrina oleva taulukko.
139 OHJ-1101 Ohjelmointi 1e Esimerkki: Taulukosta etsiminen Tehdään ohjelma, joka tarkastaa, löytyykö tietty luku taulukosta, ja tulostaa myös suurimman indeksin, josta ko. luku löytyy. int main() { int taulukko[] = { 42, 37, 42, 42, 1, 37 ; const int KOKO = sizeof( taulukko ) / sizeof( int ); cout << "Syötä luku, jota etsitään: "; cin >> etsitty; int etsitty = 0; // Kiintoarvo bool loytyyko = false; // Yksisuuntainen lippu int viimeisenkohta = -1; // Sopivimman säilyttäjä for( int i = 0; i < KOKO; ++i ) { // i: askeltaja if( taulukko[ i ] == etsitty ) { loytyyko = true; viimeisenkohta = i; if( loytyyko ) { cout << "Luku " << etsitty << " löytyy taulukosta ja viimeisen kohdan " << "indeksi on " << viimeisenkohta << endl; else { cout << "Luku " << etsitty << " ei löydy taulukosta" << endl; return EXIT_SUCCESS;
140 OHJ-1101 Ohjelmointi 1e Muuttujan rooli: Yksisuuntainen lippu Yksisuuntainen lippu on bool-muuttuja, joka ei saa enää alkuperäistä arvoaan sen jälkeen, kun se on kerran muuttunut. Edellisessä esimerkissä loytyyko asetettiin ensin arvoon false, koska siihen mennessä etsittyä lukua ei vielä ole löytynyt. Siinä tapauksessa, että luku löytyy, muuttujan arvoksi tulee true. Muuttujan rooli: Sopivimman säilyttäjä Sopivimman säilyttäjän arvo on paras tai jollain muulla tavoin halutuin siihen asti läpikäydyistä arvoista. Arvojen paremmuuden mittamisessa ei ole mitään rajoituksia: halutuin voi tarkoittaa esimerkiksi pienintä tai suurinta lukua tai sellaista lukua, joka on lähinnä jotain tiettyä arvoa. Esimerkkiohjelmassa muuttujaan viimeisenkohta etsittiin indeksiä, jossa luvun viimeinen esiintymä sijaitsee. viimeisenkohta on sopivimman säilyttäjä.
141 OHJ-1101 Ohjelmointi 1e Vähän string-merkkijonoista Merkkijono on joukko merkkejä, jotka ovat järjestyksessä. Merkkijonotyyppisen (string) muuttujan merkkejä voi myös käsitellä yksitellen. Tällöin merkkijonoa käsitellään kuten taulukkoa. string nimi = ""; cin >> nimi; cout << "Nimen ensimmäinen kirjain on " << nimi[ 0 ] << endl; Merkkijonon pituuden saa myös selville sanomalla merkkijononnimi.size() mutta tähän palaamme myöhemmin, kun merkkijonoja käsitellään perusteellisemmin. cout << "Nimen kirjaimet järjestyksessä:" << endl; for( unsigned int i = 0; i < nimi.size(); ++i ) { cout << i << ": " << nimi[ i ] << endl;
142 OHJ-1101 Ohjelmointi 1e Esimerkki: Kirjainlaskuri Tutkitaan ohjelmaa, joka laskee syötteenä annetuista sanoista esiintyneiden kirjainten (a-z) lukumääriä. Ohjelman suoritus saadaan loppumaan kirjoittamalla sana loppu. Ohjelmassa pitää pystya tallettamaan, kuinka monta kappaletta a-kirjainta on esiintynyt, kuinka monta kappaletta b-kirjainta on esiintynyt jne. Talletetaan jokaisen kirjaimen esiintymien lukumäärät taulukkoon: int tilasto[ AAKKOSTEN_LUKUMAARA ]; Nyt siis taulukon kohdassa 0 on talletettuna kirjaimen a esiintymien lukumäärä, kohdassa 1 kirjaimen b esiintymien lukumäärä, jne.
143 OHJ-1101 Ohjelmointi 1e Ohjelman toteutus C++:lla: 1 int main() { 2 const int LKM = 26; // Aakkosten a-z lukumäärä const int AN_ASCIIARVO = 97; 4 int tilasto[ LKM ]; 6 for( int i = 0; i < LKM; ++i ) { // Alustetaan taulukon alkiot nolliksi tilasto[ i ] = 0; 8 10 string sana = ""; // Tuoreimman säilyttäjä cin >> sana; 12 while( sana!= "loppu" ) { for( unsigned int i = 0; i < sana.size(); ++i ) { 14 if( sana[ i ] >= 'a' && sana[ i ] <= 'z' ) { int jarjestysnro = static_cast< int >( sana[ i ] ) 16 - AN_ASCIIARVO; // Kiintoarvo ++ tilasto[ jarjestysnro ]; cin >> sana; 22 for( int i = 0; i < LKM; ++i ) { 24 cout << static_cast< char >( i + AN_ASCIIARVO ) << ": " << tilasto[ i ] << endl; 26 return EXIT_SUCCESS; 28
144 OHJ-1101 Ohjelmointi 1e Harjoitus Ohjelman lause riveillä on hiukan monimutkaisen näköinen. Miten selkeytät ko. lausetta? Mitä tapahtuu, jos ohjelmalle syötetään sanoja, joissa on muita merkkejä kuin pieniä kirjaimia välillä a-z?
145 OHJ-1101 Ohjelmointi 1e Esimerkki Perunoiden keittämistä varten voisi kirjoittaa algoritmin. Toisaalta perunat eivät ole ainoa ruoka, jota keitetään. Kannattaa kirjoittaa yleinen algoritmi ruuan keittämiseksi. Algoritmi: Keitä (ruokaa) JOS tarvetta pese ruoka etsi kattila laita ruoka kattilaan lisää kattilaan vettä kunnes ruoka peittyy laita kattila levylle käännä levy päälle anna kiehua kunnes ruoka on kypsää käännä levy pois päältä kaada keitinvesi viemäriin
146 OHJ-1101 Ohjelmointi 1e Keittämisalgoritmia hyväksi käyttäen on helppo kirjoittaa algoritmi ruoka-annoksen nakit ja muusi toteuttamiseksi: Algoritmi: Nakit ja muusi keitä (perunat) muusaa perunat lisää maito, voi ja suola perunoihin keitä (nakit) etsi lautanen laita perunamuusi lautaselle laita nakit lautaselle Riittää, kun selitetään kerran tarkasti, miten keittäminen tapahtuu. Nakit ja muusi -algoritmi on selkeämpi lukea, kun keitä-algoritmia ei tarvitse esittää erikseen joka välissä, vaan sen nimi kertoo, mitä tapahtuu. Jos olosuhteet muuttuisivat ja käytössä olisikin kaasukeitin, tarvitsisi keittämisalgoritmia muuttaa vain yhteen paikkaan. Silti sekä perunoiden että nakkien keittäminen onnistuisi.
147 OHJ-1101 Ohjelmointi 1e Funktiot Funktiot ovat ohjelmointikielen tarjoama työkalu ohjelman pilkkomiseen hallittaviin osiin. Päämääränä funktioiden käytössä on tietysti se vanha tuttu: jos ongelma on liian iso, pilko sitä pienempiin palasiin, kunnes jäljellä on niin pieniä osia, että pää ei sekoa. Toimiva ohjelma saadaan, kun syntyneet pienet osaset yhdistellään toimimaan kokonaisuutena. Funktio voi joko toimia aina samalla tavalla tai saada ulkopuolelta toimintaan vaikuttavia tietoja, joita kutsutaan parametreiksi.
148 OHJ-1101 Ohjelmointi 1e Esimerkki C++:lla Ratkaistava ongelma: Tee ohjelma, joka tulostaa seuraavan söötin kertotaululunttilapun: *
149 OHJ-1101 Ohjelmointi 1e Hahmotellaan ratkaisua: Algoritmi: Kertotaulun tulostus tulosta erotinvaakarivi tulosta sarakkeiden otsikkorivi tulosta erotinvaakarivi luku 1 WHILE luku!= 9 tulosta luvun kertotaulurivi luku luku + 1 tulosta erotinvaakarivi Erotinvaakarivin tulostaminen tehdään aika monta kertaa. kannattaa erottaa omaksi kokonaisuudekseen. Se Lisäksi kannattaa tehdä omat kokonaisuutensa asioista, joita pitää tarkentaa algoritmissa. Otsikkorivin tulostaminen ja kertotaulurivin tulostaminen ovat tällaisia.
150 OHJ-1101 Ohjelmointi 1e Suunnitellaan vielä tarkennettavat kohdat pseudokoodina: Algoritmi: Tulosta sarakkeiden otsikkorivi tulosta pystyviivat ja kertomerkki alkuun luku 1 WHILE luku!= 9 tulosta luku luku luku + 1 tulosta pystyviiva Algoritmi: Tulosta kertotaulurivi tietylle kertoimelle tulosta pystyviivat ja kerroin alkuun kerrottava 1 WHILE kerrottava!= 9 tulosta kerroin * kerrottava kerrottava kerrottava + 1 tulosta pystyviiva
151 OHJ-1101 Ohjelmointi 1e Toteutus C++:lla: 1 #include <iostream> #include <iomanip> #include <cstdlib> using namespace std; 5 void tulostaerotinvaakarivi() { cout << " " << endl; 10 void tulostaotsikkorivi() { cout << " * "; for( int i = 1; i <= 9; ++i ) { cout << setw(3) << i; 15 cout << " " << endl; void tulostakertotaulurivi( int kertoja ) { cout << " " << kertoja << " "; 20 for( int kerrottava = 1; kerrottava <= 9; ++kerrottava ) { cout << setw(3) << kertoja * kerrottava; cout << " " << endl;
152 OHJ-1101 Ohjelmointi 1e int main() { tulostaerotinvaakarivi(); tulostaotsikkorivi(); tulostaerotinvaakarivi(); for( int luku = 1; luku <= 9; ++luku ) { tulostakertotaulurivi( luku ); 35 tulostaerotinvaakarivi(); return EXIT_SUCCESS; Mitä siitä opittiin: Kokonaisuus on jaettu funktioiksi, joista saa nopeasti käsityksen siitä, mitä ne tekevät, koska ne ovat lyhyitä ja nimet kuvaavia. Pääohjelma on selkeä. Siitä näkee yhdellä vilkaisulla mitä tapahtuu. Ohjelmaa on helpompi hallita. VIP-esimerkki: 5.1.
153 OHJ-1101 Ohjelmointi 1e void-funktiot C++:ssa void-funktiot ovat funktion yksinkertaisimpia tapauksia, joten aloitamme niistä. C++:ssa void-funktio määritellään seuraavasti: void funktionnimi() { funktionrunko tai mikäli sillä on parametreja: void funktionnimi( parametrit ) { funktionrunko Toisin kuin ehto- ja silmukkarakenteissa, lohkosulkeita ei tässä voi jättää pois, vaikka funktion runko sisältäisi vain yhden lauseen. Jotkut kutsuvat void-funktioita myös nimellä aliohjelma. Tarkkaan ottaen C++:ssa ei kuitenkaan ole aliohjelmia, joten jätämme termien funktio ja aliohjelma erottelemisen kurssin OHJ-2050 Ohjelmointikielten periaatteet asiaksi.
154 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita funktio, joka osaa tulostaa hienon tiedotteen, jonka mukaan sinä olet koodannut ko. ohjelman. Muuta edellinen funktio sellaiseksi, että sillä voi tulostaa kenen tahansa nimen. Miten funktioita kutsutaan? VIP-harjoitus: 5.3.
155 OHJ-1101 Ohjelmointi 1e Funktion nimi voi olla mikä tahansa, kunhan se noudattaa samoja sääntöjä kuin muuttujien nimet. Funktiolle kannattaa pyrkiä valitsemaan nimi, joka kuvaa hyvin sen toimintaa. Ohjelma selkiytyy. Funktion runko saa olla mitä tahansa suoritettavia C++-lauseita. Ne määräävät, mitä funktio tekee. (Ei saa kuitenkaan sisältää toisen funktion määrittelyjä.) Koska funktioiden koko idea oli se, että iso ongelma paloitellaan pienemmiksi osiksi, funktion runko ei saisi olla liian pitkä. Hyvä nyrkkisääntö: Jos funktio on pidempi kuin mitä näytölle mahtuu kerralla rivejä, mieti kuinka sen voisi jakaa kahdeksi tai useammaksi uudeksi funktioksi, jotka yhdessä toteuttavat sen toiminnot.
156 OHJ-1101 Ohjelmointi 1e Parametrit näyttävät listalta pilkulla eroteltuja muuttujan määrittelyitä, mitä ne käytännössä ovatkin. Jokainen parametrit-listassa määritelty muuttuja käyttäytyy funktion rungossa kuten paikallinen muuttuja. Sen alkuarvoksi on kopioitu kutsussa annetusta todellisesta parametrilausekkeesta laskettu arvo. Parametrit ovat tapa välittää tietoa funktion kutsujalta funktion käyttöön. Niitä voi olla nolla tai useampia. VIP-esimerkki: 5.6.
157 OHJ-1101 Ohjelmointi 1e Funktion käskyt (runko) saadaan suoritettua kirjoittamalla haluttuun kohtaan ohjelmakoodissa funktion nimi ja sen perään suluissa samassa järjestyksessä sama määrä samantyyppisiä lausekkeita, kuin mitä funktion parametrit määräävät (tyhjät sulut, jos parametreja ei ole). Tätä nimitetään myös funktiokutsuksi. Funktiota kutsuttaessa hypätään suorittamaan funktion käskyjä järjestyksessä kunnes ne loppuvat, minkä jälkeen palataan alkuperäiseen kutsukohtaan ja jatketaan siitä normaalisti eteenpäin.
158 OHJ-1101 Ohjelmointi 1e Harjoitus Piirrä kuva kaikista muuttujista, jotka esiintyvät seuraavassa ohjelmassa: int main() { void yhteenlasku( int eka, int toka ) { int a = 7; cout << eka << " + " << toka int b = 3; << " = " << eka + toka << endl; yhteenlasku( a, b ); yhteenlasku( 42, 0 ); return EXIT_SUCCESS;
159 OHJ-1101 Ohjelmointi 1e Funktiot (yleisesti) Tutkitaan funktioiden toimintaa yleisemmin C++:ssa: kutsujan ja void-funktion välillä tietoa siirtyy vain yhteen suuntaan (kutsuja void-funktio) yleisessä tapauksessa tietoa siirtyy kahteen suuntaan (kutsuja funktio)
160 OHJ-1101 Ohjelmointi 1e Sen lisäksi, että funktio saa kutsujaltaan tietoa parametreina, se voi myös palauttaa tietoa paluuarvona. Esimerkki funktiosta, joka palauttaa kutsujalleen kokonaisluvun: int max( int i, int j ) { int suurempi = i; // Kokeillaan ensin i:tä if( j > i ) { // Tarkastetaan valittiinko oikein suurempi = j; // Vaihdetaan, jos meni väärin return suurempi; // Palautetaan suurempi arvo jota voitaisiin käyttää esim. seuraavasti: int matinpisteet = 10; int teponpisteet = 11; int voittajanpisteet = max( matinpisteet, teponpisteet ); cout << "Voittaja sai " << voittajanpisteet << " pistettä!" << endl; Funktiokutsua voi käyttää sellaisessa kohdassa, jossa voisi käyttää jotain muuta saman tyyppistä tietoalkiota kuin funktion tyyppi. Tässä paluuarvo otettiin talteen sijoittamalla se muuttujaan. Toisin sanoin: funktiokutsulle evaluoituu arvo, jota voidaan käyttää vaikka if-rakenteen ehtona tai sen osana, parametrina muille funktioille, operaattoreiden operandina jne.
161 OHJ-1101 Ohjelmointi 1e Funktion yleinen määrittely on muotoa: tyyppi funktionnimi( parametrit ) { funktionrunko jossa kuten muistetaan parametrit voi olla myös tyhjä. Funktion määrittelyyn kuuluu funktion tyyppi, joka määrää, minkä tyyppistä tietoa funktio palauttaa kutsujalleen (käytännössä siis sen, minkälaisessa lausekkeessa funktiota saa kutsua). Funktion tyyppi saa olla mikä tahansa tietotyyppi. Aikaisemmin huomattiin, että se voi olla myös void, mikä tarkoittaa, että funktio ei palauta mitään. Itseasiassa void on tietotyyppi, joka ei sisällä mitään arvoja.
162 OHJ-1101 Ohjelmointi 1e Jos funktion paluuarvo on jokin muu kuin void, pitää funktion runko rakentaa siten, että sen suoritus loppuu aina käskyyn return, jolla paluuarvo välitetään kutsujalle. Yleisesti ottaen return-käsky näyttää seuraavalta: return paluuarvo; jossa paluuarvo on mikä vain lauseke, jolle laskettava arvo on tyypiltään sama kuin funktion tyyppi. Lausekkeen paluuarvo arvo määrää, mikä arvo funktiolle evaluoituu sitä kutsuvassa lausekkeessa. return-käsky lopettaa funktion suorituksen. Jatketaan kutsukohdasta eteenpäin. Funktion rungossa voi siis olla useampiakin return-käskyjä, mutta funktiosta paluu tapahtuu heti, kun yksikin niistä suoritetaan, esimerkiksi: double itseisarvo( double x ) { if ( x > 0 ) { return x; return -x; VIP-esimerkit: 5.2., 5.3. ja 5.4. ja VIP-harjoitukset: 5.1. ja 5.2.
163 OHJ-1101 Ohjelmointi 1e Harjoitus Piirrä kuva kaikista muuttujista, jotka esiintyvät seuraavassa ohjelmassa: int main() { int yhteenlasku( int eka, int a = 7; int toka ) { int b = 3 int lopputulos = eka + toka; return lopputulos; int tulos = 0; tulos = yhteenlasku( a, b ); cout << tulos << endl; return EXIT_SUCCESS;
164 OHJ-1101 Ohjelmointi 1e Myös funktion, jonka paluuarvo on void, suoritus saadaan keskeytettyä return-käskyllä, mutta tällöin paluuarvo lauseketta ei anneta: void tulostamerkkeja( char merkki, int lkm ) { if( lkm < 0 ) { cout << "Virhe!" << endl; return; // return-lauseke ilman paluuarvoa for( int i = 0; i < lkm; ++i ) { cout << merkki; cout << endl; return EXIT SUCCESS; on aivan normali return-lause, jonka tarkoituksena on poistua int main-funktiosta. EXIT SUCCESS:in täytyy olla tyyppiä int. Älä yritä käyttää return EXIT SUCCESS;-lausetta ohjelman lopettamiseen muualla kuin main-funktiossa.
165 OHJ-1101 Ohjelmointi 1e Funktiokutsuissa rajoittavin tekijä on, että tietoa saadaan helposti siirtymään paljon kutsujalta funktioon (parametrejä voi olla paljon). Funktiolta kutsujalle sen sijaan voidaan välittää ainoastaan yksi paluuarvo. (Tähän palataan myöhemmin.) Matemaattinen funktiokäsite, jonka mukaan funktiot ovat kuvauksia, esim: f : R R : f(r) = πr 2 on suppeampi kuin ohjelmointikielten funktiokäsite. Ohjelmointikielissä funktioilla voi olla paluuarvon lisäksi myös sivuvaikutuksia.
166 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita funktio, joka osaa eri kehotteella kysyä eri kouluaineiden arvosanoja ja tarkastaa, että annettu arvosana on laillinen. Kirjoita pääohjelma, joka kysyy käyttäjältä matikan ja fysiikan arvosanat ja laskee niiden keskiarvon.
167 OHJ-1101 Ohjelmointi 1e Funktiokutsua voi käyttää missä tahansa, mihin funktion tyyppinen lauseke sopisi. #include <cstdlib> #include <iostream> using namespace std; int toiseen( int i ) { return i * i; bool onkoparillinen( int i ) { return i % 2 == 0; bool jatketaanko() { while( true ) { cout << "Haluatko jatkaa: "; char vast = ' '; cin >> vast; if( vast == 'k' vast == 'K' ) { return true; if( vast == 'e' vast == 'E' ) { return false;
168 OHJ-1101 Ohjelmointi 1e int main() { do { cout << "Syötä luku: "; int luku = 0; cin >> luku; cout << "Luvun " << luku << " toinen potenssi on "; if( onkoparillinen( toiseen( luku ) ) ) { cout << "parillinen." << endl; else { cout << "pariton." << endl; while( jatketaanko() ); return EXIT_SUCCESS; VIP-esimerkki: 5.10.
169 OHJ-1101 Ohjelmointi 1e Funktioiden löytäminen Huolellisesti suunnitellusta algoritmista on suhteellisen helppo löytää sopivat funktioehdokkaat. Funktiona kannattaa toteuttaa: jokainen algoritmin kohta, joka vaatii tarkentamista jokainen algoritmissa moneen kertaan samanlaisena toistuva toiminto Jo näillä säännöillä selviää pitkälle, mutta toki kokemus ja harjoittelu antavat lisänäkemystä. Lisäksi kannattaa pitää mielessä, että funktio on liian pitkä, jos se ei mahdu kerralla näytölle. Funktioita suunnitellessa pitää myös miettiä, mitä on se tieto, jota funktion tarvitsee lähettää takaisin kutsujalleen.
170 OHJ-1101 Ohjelmointi 1e Hyvin usein funktio on tunnistettavissa siitä, että algoritmissa toiminto esiintyy osana jotain lauseketta, esimerkiksi: IF Diskriminantti < 0 THEN tai tai tai viikonpäivä päivämäärän pp.kk.vvvv viikonpäivä tulosta astelukua vastaava fahrenheit-lämpötila sosiaaliturvatunnus kysy käyttäjän sosiaaliturvatunnus joissa potentiaaliset funktiot kursiivilla.
171 OHJ-1101 Ohjelmointi 1e Usein funktio saattaa algoritmissa olla jaettuna kahdelle tai useammalle riville, kannattaa siis olla tarkkana: tulosta kehote, joka tiedustelee sosiaaliturvatunnusta lue käyttäjän näppäilemä syöte WHILE syöte ei ole laillinen sosiaaliturvatunnus tulosta ilmoitus virheellisestä syötteestä tulosta kehote, joka tiedustelee sosiaaliturvatunnusta lue käyttäjän näppäilemä syöte sosiaaliturvatunnus käyttäjän syöttämä tunnus jossa kursivoidut toiminnot yhdessä muodostaisivat funktion kysysosiaaliturvatunnus().
172 OHJ-1101 Ohjelmointi 1e Funktioiden merkitys Hyvin valitut funktioiden nimet (kuvaavat ja helposti muistettavat) selkeyttävät ohjelmaa ja kertovat itsessään jotain ohjelman toiminnasta. Ohjelmointi helpottuu ja koodin luettavuus paranee. Funktiot säästävät kirjoittamisen vaivaa, sillä usein toistuvat toiminnot tarvitsee koodata vain kerran. Ohjelmakoodi lyhenee ja selkeytyy, kun tietyt toiminnot suoritetaan funktiokutsulla. Kun funktion toiminnot toteuttava ohjelmakoodi esiintyy vain yhdessä paikassa, siinä olevat virheet tarvitsee korjata vain kerran. Mikäli funktion prototyyppi pysyy ennallaan, funktiota muutettaessa muuhun ohjelmaan ei tarvitse koskea. Ohjelman toiminnan muuttaminen tarvittaessa (ylläpidettävyys) on helpompaa, koska muutos tarvitsee tehdä vain yhteen paikkaan. Virheiden jäljitettävyys helpottuu, kun virhe voidaan paikallistaa jonkin funktion yhteyteen. Funktiot ovat tärkeä työkalu ohjelman jakamisessa osakokonaisuuksiin (strukturointi ). Ne tukevat hierarkkista suunnittelua. Niiden avulla ohjelmalle saa hallittavan rakenteen (hajoita ja hallitse).
173 OHJ-1101 Ohjelmointi 1e Esimerkki Harjoitellaan funktioiden etsimistä tekemällä ohjelma, joka tulostaa lämpötilakäyrän: proffa>./lampotila Anna lampötila kello 0.30: 0.3 Anna lampötila kello 1.30: -4.1 Anna lampötila kello 2.30: -8.2 Anna lampötila kello 3.30: Anna lampötila kello 22.30: 7.2 Anna lampötila kello 23.30: : * 1.30: * 2.30: * 3.30: * : * 23.30: *
174 OHJ-1101 Ohjelmointi 1e Harjoitellaan ensin itse... Mitä funktioksi sopivia osatoimintoja ohjelmasta löytyy? Keksi löytämillesi toiminnoille kuvaavat nimet. Mitä tietoja funktion suorittamiseksi tarvitaan eli mitä parametreja funktiolle pitää antaa? Minkä tyyppisiä parametrit ovat? Mitä funktion pitää palauttaa, että se olisi hyödyllinen kutsujalleen?
175 OHJ-1101 Ohjelmointi 1e Suunnitellaan algoritmi: Algoritmi: Lämpötilagraa tunti 0 WHILE tunti < 24 lämpötila tunti kysy lämpötila kello tunti tunti tunti + 1 tulosta otsikkorivi ylälaitaan tunti 0 WHILE tunti < 24 tulosta graan rivi ajalle tunti tunti tunti + 1 tulosta otsikkorivi alalaitaan Selkeästi joitain kohtia voitaisiin taas yksityiskohtaistaa, mutta annetaan olla tällä kertaa. Potentiaaliset funktiot kursiivilla.
176 OHJ-1101 Ohjelmointi 1e Toteutus C++:lla: #include <iostream> #include <iomanip> #include <string> #include <cstdlib> using namespace std; const int TUNTEJA_PAIVASSA = 24; // Vakiomäärittely double kysylampotila( int tunti ){ cout << "Anna lämpötila kello " << setprecision( 2 ) << fixed << tunti << ": "; double lampo; cin >> lampo; return lampo; void tulostaotsikkorivi( bool ylalaita ) { const string VALIT = " "; // 6 kpl välilyöntejä const string VIIVAT = " "; const string NUMEROT = " "; if ( ylalaita ) { cout << VALIT << NUMEROT << endl << VALIT << VIIVAT << endl; else { cout << VALIT << VIIVAT << endl << VALIT << NUMEROT << endl;
177 OHJ-1101 Ohjelmointi 1e void tulostagraafirivi( int tunti, double lampotilat[] ) { cout << setw(5) << setprecision(2) << fixed << tunti << ": "; if( lampotilat[ tunti ] < lampotilat[ tunti ] > 40.0 ) { cout << endl; return; int valilyonnit = static_cast<int>( (lampotilat[ tunti ] - (-40) ) / ); while ( valilyonnit > 0 ) { cout << ' '; --valilyonnit; cout << '*' << endl; int main() { double lampotilat[ TUNTEJA_PAIVASSA ]; for( int tunti = 0; tunti < TUNTEJA_PAIVASSA; ++tunti ) { lampotilat[ tunti ] = kysylampotila( tunti ); tulostaotsikkorivi( true ); for( int tunti = 0; tunti < TUNTEJA_PAIVASSA; ++tunti ) { tulostagraafirivi( tunti, lampotilat ); tulostaotsikkorivi( false ); return EXIT_SUCCESS;
178 OHJ-1101 Ohjelmointi 1e Määrittely vs. esittely Funktion määrittelyllä tarkoitetaan funktion kirjoittamista ohjelmakoodiin kokonaisuudessaan. Esimerkiksi seuraava on funktion itseisarvo määrittely: double itseisarvo( double d ) { if( d < 0 ) { return -d; return d; Funktion esittely taas tarkoittaa sitä, kun funktiosta kerrotaan vain sen nimi, parametrien tyypit ja paluuarvo. Seuraavassa funktion itseisarvo esittely: double itseisarvo( double d );
179 OHJ-1101 Ohjelmointi 1e Funktion esittelyä kutsutaan myös prototyypiksi. Esittely kertoo funktiosta kaiken sen, mitä kääntäjän tarvitsee tietää, kun se tarkistaa, onko ohjelmakoodiin kirjoitettu funktiokutsu laillinen (ei sisällä semanttisia virheitä). Määrittely taas kertoo funktiosta kaiken saman kuin esittelykin, mutta sen lisäksi myös käskyt, jotka pitää suorittaa funktiota kutsuttaessa. Käytännössä tämä tarkoittaa seuraavaa: 1. Funktio pitää aina määritellä (ja vain kerran) jossain päin ohjelmakoodia, sillä mistä muuten tiedettäisiin, mitä pitää tehdä, kun aliohjelmaa kutsutaan. 2. Jotta kääntäjä voisi suorittaa virhetarkistuksia, funktio pitää joko esitellä tai määritellä ohjelmakoodissa ennen kuin sitä kutsutaan ensimmäisen kerran. Syvällisesti ajateltuna kaikki tämäkin johtuu siitä, että kaikella tiedolla pitää olla tyyppi : funktiot ovat tietoa siitä, kuinka joku asia tehdään.
180 OHJ-1101 Ohjelmointi 1e Ohjelman käännösvaiheessa itseasiassa linkkeri yhdistää käännetyt funktiot kokonaiseksi ohjelmaksi. Jos siis teet virheitä funktion esittelyssä, virheen huomaa linkkeri eikä kääntäjä. Linkkeriltä tulevat virheilmoitukset ovat usein erinäköisiä kuin kääntäjältä tulevat virheilmoitukset. Linkkeri ei aina ilmoita virheen sijaintia rivinumeron perusteella, vaan funktion, jonka yhteydessä virhe ilmenee. /tmp/ccoeq8ac.o: In function main':.../ohjelma.cc:11: undefined reference to funktio(int&)' collect2: ld returned 1 exit status Kun saat aikaan linkkerinvirheilmoituksen, kannattaa aivan ensimmäiseksi tarkastaa, ovatko funktion esittely ja määrittely täsmälleen toisiaan vastaavat. Lisäksi funktiokutsun pitää olla näiden kanssa yhteensopiva.
181 OHJ-1101 Ohjelmointi 1e Funktion esittelyn pitäisi olla niin selkeä, että sen perusteella täysin ulkopuolinen henkilö pystyy kirjoittamaan funktiolle kattavat testitapaukset. Tähän voidaan päästä paitsi valitsemalla funktiolle selkeä ja kuvaava nimi, myös kommentoimalla funktion esittely perusteellisesti. Hyvässä kommentoinnissa funktiosta kerrotaan ainakin: funktion nimi ja tarkoitus funktion paluuarvo: tyyppi ja tarkoitus jokaisesta parametrista: tyyppi, nimi ja tarkoitus funktion toiminta, esim. mahdolliset sivuvaikutukset // Funktio: loytyykoarvo // Tarkoitus: etsii löytyykö tietty arvo taulukosta, tehokas suurille taulukoille // Paluuarvo: bool, kertoo löytyykö tietty arvo taulukosta // Parametrit: int i, arvo, jota taulukosta etsitään // int t[], taulukko, josta etsitään // Toiminta: Järjestää taulukon sisällön suuruusjärjestykseen (sivuvaikutus) // ja käyttää puolitushakua arvon etsimiseen. bool loytyykoarvo( int i, int t[] );
182 OHJ-1101 Ohjelmointi 1e Kun ohjelma on hiukan suurempi ja kooditiedostosta tulee pitkä, saattaa olla selkeämpää kirjoittaa ohjelma seuraavassa järjestyksessä: 1. alussa funktioiden esittelyt, että lukija tietää, minkälaisia osia ohjelmassa on käytettävissä 2. seuraavaksi pääohjelman määrittely, josta siis selviää, miten koko ohjelma itseasiassa toimiikaan 3. viimeisenä funktioiden määrittelyt, jos lukija haluaat tietää miten ohjelman yksityiskohdat on tarkemmin toteutettu Käytä tätä järjestystä esim. harjoitystyötä toteuttaessasi, koska se on selkeämpi ohjelman lukijan kannalta.
183 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita puuttuvat osat ohjelmaan: #include <cstdlib> #include <iostream> using namespace std; // Funktion esittely: Funktio laskee kahden luvun maksimin // Pääohjelma: int main() { int luku = 0; cin >> luku; // Funktiokutsu:... return EXIT_SUCCESS; // Funktion määrittely:
184 OHJ-1101 Ohjelmointi 1e Kirjastoista C++:n kirjastoista saat käyttöösi valmiita funktioita. Pyörää ei aina tarvitse keksiä uudelleen. Kuten olemme jo oppineet, kirjastot otetaan käyttöön kirjoittamalla tiedoston alkuun #include ja kirjaston nimi <>-sulkujen sisään. Kirjastoja voi ottaa mukaan missä tahansa.cc- tai.hh-tiedostossa. Jos kokoat kirjastoja omista funktioistasi, muista aina tehdä kirjastolle myös.hh-tiedosto, jossa on funktioiden prototyypit. Olemme jo käyttäneet mm. kirjastoja iostream (syötteiden ja tulosteiden käsittely) ja iomanip (syötteiden muotoilu) sekä C++:n standardikirjastoa cstdlib. Nyt tutustumme yhteen uuteen kirjastoon.
185 OHJ-1101 Ohjelmointi 1e Matematiikkakirjasto C++:n matematiikkakirjaston nimi on cmath ja se tarjoaa valmiina tärkeimmät matemaattiset funktiot. Seuraavassa funktioista hyödyllisimmät: funktio kutsulle evaluoituva arvo double abs(double x) x double sqrt(double x) x double pow(double x, double y) x y double exp(double x) e x double log(double x) log e x double log10(double x) log 10 x double sin(double x) sin x double cos(double x) cos x double tan(double x) tan x double asin(double x) arcsin x eli sin 1 x double acos(double x) arccos x eli cos 1 x double atan(double x) arctan x eli tan 1 x Trigonometrisissa funktioissa kulmat ovat radiaaneina.
186 OHJ-1101 Ohjelmointi 1e Valmiita funktioita käytettäessä kannattaa huomata, että funktion toteutuksessa saattaa olla joitain rajoitteita. Esimerkiksi funktiolle double sqrt(double x) ei neliöjuuren matemaattisen määrittelyn vuoksi saa antaa negatiivista lukua parametriksi. Tätä kutsutaan funktion esiehdoksi. sqrt siis palauttaa parametrina saamansa luvun neliöjuuren vain, jos funktion esiehto (parametri on positiivinen) toteuttuu. Muussa tapauksessa funktion toiminta on määrittelemätön. (Ohjelma voi esim. kaatua.) Kun tutustut uusiin kirjastofunktioihin, kannattaa aina selvittää, mitkä funktion esiehdot ovat.
187 OHJ-1101 Ohjelmointi 1e Liukulukujen vertaileminen Tietokone esittää liukuluvut (kuten kokonaisluvutkin) jollain rajallisella määrällä bittejä (0 ja 1). Tästä seuraa luonnollisesti, että laskutoimitusten tulokset ovat monissa tapauksissa likiarvoja todellisille vastauksille: oikeassa tuloksessa voi olla enemmän merkitseviä numeroita kuin mihin esitystarkkuus pystyy. Toisaalta johtuen tavasta, jolla reaaliluvut koodataan vastaaviksi liukuluvuiksi, se ei ole kaikissa tilanteissa edes mahdollista tarkasti. Asian syvin olemus on se, että liukuluvuilla laskettaessa syntyy aina pyöristysvirheitä ja lopputulos on siten likiarvo. Esimerkiksi lausekkeen tulos ei välttämättä olekaan tasan 0.0, vaan pyöristysvirheiden tuloksena esim {{ paljon nollia
188 OHJ-1101 Ohjelmointi 1e Tämän seurauksena vertailuoperaattorit == ja!= saattavat toimia järjenvastaisesti, esimerkiksi ohjelma int main() { double luku1 = 20.1; double luku2 = 20.0; double luku3 = 0.1; if ( (luku1 - luku2 - luku3) == 0 ) { cout << "Oikein meni!" << endl; else { cout << "Väärin meni!" << endl; return EXIT_SUCCESS; tulostaa suoritettaessa näytölle tekstin "Väärin meni!". Tästä ikävästä ominaisuudesta selvitään sillä, että hyväksytään pyöristysvirheiden olemassaolo ja tulkitaan kaksi liukulukua samoiksi, jos ne ovat "riittävän" lähellä toisiaan.
189 OHJ-1101 Ohjelmointi 1e Tämän seurauksena reaalilukuvertailu a == b pitäisi siis kirjoittaa a b < ɛ, jossa ɛ on jokin riittävän pieni virhetoleranssi, esimerkiksi 1E-8. C++:lla reaalilukujen vertailu a == b siis kirjoitettaisiin: // Määritellään jossain ohjelman alussa // virhetoleranssille jokin sopiva arvo: const double EPSILON = 1E-8;... // Myöhemmin ohjelmassa kun halutaan vertailla // kahden reaaliluvun a ja b yhtäsuurutta: abs( a - b ) < EPSILON Erisuuruutta vertailtaisiin vastaavasti: abs( a - b ) >= EPSILON tai!( abs( a - b ) < EPSILON )
190 OHJ-1101 Ohjelmointi 1e Arvo- ja viiteparametrit Funktioiden parametrit ovat C++:ssa normaalisti arvoparametreja, jolla tarkoitetaan sitä, että funktion näkyvyysalueella on omat muuttujat, joihin se kopioi parametriensa arvot. Funktion muuttaessa muodollisen parametrinsa arvoa todellisen parametrin arvo säilyy ennallaan. void vaihda( int parametri1, int parametri2 ) { int tmp = parametri1; parametri1 = parametri2; parametri2 = tmp; int main() { int eka = 42; int toka = 0; vaihda( eka, toka ); cout << eka << endl; return EXIT_SUCCESS; Edellisen ohjelman tulostus on siis 42 eli todellinen parametri ei muuttunut.
191 OHJ-1101 Ohjelmointi 1e Funktiolle siis välitetään muuttujien eka ja toka arvot, jotka funktion näkyvyysalueessa sijoitetaan paikallisiin muuttujiin. Kun funktio muuttaa paikallisten muuttujien arvoja, ne muuttuvat tietenkin vain funktion omiin muuttujii.
192 OHJ-1101 Ohjelmointi 1e Kun funktio loppuu ja sen näkyvyysalueella olevat muuttujat poistetaan muistista, muutokset katoavat. Usein tulee vastaan tilanne, jossa olisi hyödyllistä, jos funktio pystyisi muuttamaan todellisen parametrin arvoa. C++:n normaalin parametrinvälitysmekanismin ( arvonvälitys, arvoparametrit ) lisäksi kieli tarjoaa myös viitteenvälityksen (viiteparametrit, muuttujaparametrit ). Viiteparametrit toimivat juuri siten, että funktion muuttaessa muodollisen parametrinsa arvoa myös todellisen parametrin arvo muuttuu. Parametri voidaan määritellä viiteparametriksi lisäämällä sen tyypin ja nimen väliin merkki &. VIP-esimerkki: 5.5. ja VIP-harjoitus: 5.4.
193 OHJ-1101 Ohjelmointi 1e Edellinen esimerkki voitaisiin siis toteuttaa viiteparametreilla seuraavaan tapaan: // Ainoa muutos alkuperäiseen verrattuna ovat // seuraavalle riville lisätyt &-merkit. void vaihda( int& parametri1, int& parametri2 ) { int tmp = parametri1; parametri1 = parametri2; parametri2 = tmp; int main() { int eka = 42; int toka = 0; vaihda( eka, toka ); cout << eka << endl; return EXIT_SUCCESS; Nyt ohjelma tulostaakin 0 eli funktio vaihda pystyi muuttamaan todellisten parametrien arvoja.
194 OHJ-1101 Ohjelmointi 1e Tällä kertaa funktion näkyvyysalueella olevat parametrit eivät olekaan oikeita muuttujia, vaan pelkästään viittauksia pääohjelman muuttujiin. Kun muutos tehdään tämän viittauksen kautta, pääohjelman muuttujan arvo muuttuu oikeasti. Huomaa, että nyt todellisten parametrien on oltava muuttujia. Lausekeet eivät käy.
195 OHJ-1101 Ohjelmointi 1e Viitteet Viitteet (reference) ovat C++:n tyyppejä, joilla voidaan viitata jonkin muuttujan sisältöön. C++:ssa viite määritellään ja alustetaan: kohdetyyppi& viittennimi = kohde; Esim. kokonaislukujen tapauksessa: int luku = 0; int& lukuviite = luku; Viitteet eivät ole muuttujia. Niillä ei ole "omaa" arvoa, vaan ne ainoastaan viittaavat jonkun toisen muuttujan arvoon. Niiden kautta voi käsitellä viitattua arvoa niiden nimen avulla. lukuviite = 42; Viitettä ei voi kääntää osoittamaan johonkin toiseen muuttujaan, joten se on alustettava.
196 OHJ-1101 Ohjelmointi 1e Viitteet ovat hyödyllisiä, kun ei haluta ottaa kopiota muuttujasta, joka vie paljon muistia. Esim. jos funktion parametrina on string, eikä haluta, että joka kerta, kun funktiota kutsutaan, stringistä tehdään kopio. string:it kannattaa yleensä välittää viitteinä, jos niitä käytetään funktion parametreina. Viitteenvälitys on kätevä myös, jos haluaa palauttaa funktion kutsujalle enemmän kuin yhden arvon. Esim. funktio voi palauttaa tiedon siitä, onnistuiko toimenpide, jota yritettiin tehdä, ja suorittaa toimenpiteen viitteenä saamalleen muuttujalle. Esim. bool neliojuuri( double d, double& juuri ) joka laskisi muuttujaan juuri muuttujan d neliöjuuren arvon, mikäli d on positiivinen. Tällöin funktio myös palauttaisi true. Jos d on negatiivinen, funktio ainoastaan palauttaisi false. Myös vector-tietorakenteet, joista puhutaan myöhemmin, välitetään aina viiteparametrina. VIP-esimerkki: 5.9. ja VIP-harjoitus: 5.5.
197 OHJ-1101 Ohjelmointi 1e Esimerkki Funktio, joka muuntaa merkkijonon isoiksi kirjaimiksi käyttäen arvoparametria ja paluuarvoa: #include <iostream> #include <string> #include <cctype> #include <cstdlib> using namespace std; string isoiksi( string mjono ) { for( unsigned int i = 0; i < mjono.length(); ++i ) { mjono[ i ] = toupper( mjono[ i ] ); return mjono; int main() { cout << "Kirjoita jotain: "; string syote = ""; cin >> syote; syote = isoiksi( syote ); cout << "Sama huutaen: " << syote << endl; return EXIT_SUCCESS; VIP-esimerkki: 5.11.
198 OHJ-1101 Ohjelmointi 1e Funktio, joka tekee saman muunnoksen käyttäen viiteparametria: #include <cstdlib> #include <iostream> #include <string> #include <cctype> using namespace std; void isoiksi( string& mjono ) { for( unsigned int i = 0; i < mjono.length(); ++i ) { mjono[ i ] = toupper( mjono[ i ] ); int main() { cout << "Kirjoita jotain: "; string syote = ""; cin >> syote; isoiksi( syote ); cout << "Sama huutaen: " << syote << endl; return EXIT_SUCCESS; VIP-esimerkki: 5.12.
199 OHJ-1101 Ohjelmointi 1e Harjoitus Toisen asteen yhtälön ax 2 + bx + c = 0 mahdolliset reaaliratkaisut löydetään kaavalla: x = b ± b 2 4ac (1) 2a Miten laadit C++-funktion, joka laskee ratkaisut?
200 OHJ-1101 Ohjelmointi 1e Taulukot funktion parametrina Vaikka funktion parametrit C++:ssa ovatkin oletusarvoisesti arvoparametreja, käyttäytyvät taulukot kummallisesti. Tämä johtuu tavasta, jolla taulukot on toteutettu C++:ssa. Tällä kurssilla asiaan ei perehdytä syvällisesti, vaan ainoastaan omaksutaan muutama fakta: Jos funktion parametrina on taulukko, se käyttäytyy kuten viiteparametri. (Viitemerkkiä ei voi edes laittaa.) Funktiossa ei mitenkään voida päätellä ( sizeof ei toimi oikein), montako alkiota taulukossa on. Funktiolle pitää erikseen kertoa taulukon alkioiden määrä (globaali vakio tai ylimääräinen parametri). Taulukkoa ei voi välittää paluuarvona. (Tämä voidaan kiertää käyttämällä viiteparametria, jollainen taulukkoparametri siis on.)
201 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita funktio, joka tarkastaa, ovatko taulukon alkiot suuruusjärjestyksessä.
202 OHJ-1101 Ohjelmointi 1e Tietueet Taulukko ja vector sisältävät kokoelman samantyyppisiä arvoja. Välillä täytyy sitoa yhteen eri tyyppisiä tietoalkioita, jotka liittyvät yhteen, esim. opiskelijan nimi, opiskelijanumero ja Ohjelmointi 1e:n arvosana. Tietue (struct) sopii tällaiseen tilanteeseen. Tietueita (kuten taulukoitakin) kutsutaan rakenteisiksi tietotyypeiksi: niillä on ohjelmoijan määräämä rakenne. Tietuetyypin määrittely tapahtuu varatun sanan struct avulla: struct Tyypin_nimi { kentän_1_tyyppi kentän_1_nimi;... kentän_n_tyyppi kentän_n_nimi; ; Huom! Puolipiste loppuaaltosulun jälkeen. Tämän seurauksena kieleen ilmestyy uusi tietotyyppi nimeltään Tyypin nimi, jota voidaan käyttää normaalisti muuttujien, parametrien, taulukon alkioiden jne. määrittelyyn: Tyypin_nimi muuttujan_nimi;
203 OHJ-1101 Ohjelmointi 1e Tietuetyypin yksittäiset kentät käyttäytyvät kuten muuttujat, kun niitä käsitellään operaattorin "."(piste) avulla: struct Opiskelija { // Luodaan uusi tietotyyppi string nimi; // ei siis vielä varata muistia muuttujalle int opnum; ;... Opiskelija opisk; // Luodaan tietuetyyppinen muuttuja... // (Vertaa: int i) opisk.nimi = "Teemu Teekkari"; cin >> opisk.opnum; Tietuetyypin muuttujia voidaan myös alustaa määrittelyvaiheessa lausekkeilla, joiden tyyppi on sama kuin vastaavan kentän tyyppi: Opiskelija op1 = { "Ahto Simakuutio", ; Opiskelija op2 = { "Teemu Teekkari", ; Kentät alustetaan annetuilla arvoilla siinä järjestyksessä, jossa ne esiintyivät tyyppiä määriteltäessä. VIP-esimerkki: 7.1.
204 OHJ-1101 Ohjelmointi 1e Tietuetyyppisiä muuttujia voi sijoittaa toisiinsa = operaattorilla, mutta niitä ei voi vertailla == ja!= operaattoreilla. Tietueiden kentät saavat olla minkä tahansa tyyppisiä, myös taulukoita: struct Arvosana { string nimi; int tehtavien_pisteet[ 4 ]; ;... Arvosana asana;... asana.tehtavien_pisteet[ 2 ] = 5; Toisaalta, kuten aiemmasta muistetaan, taulukon alkiot saavat olla mitä tahansa tyyppiä, myös tietueita siis: Opiskelija opiskelijat[ 1000 ]; opiskelijat[ 0 ].nimi = "Ahto Simakuutio"; cin >> opiskelijat[ 42 ].opnum;
205 OHJ-1101 Ohjelmointi 1e Esimerkki ohjelmasta, joka korvaa tietyt kirjaimet toisilla: #include <cstdlib> #include <iostream> #include <string> using namespace std; struct Kirjainpari { char korvattava; char korvaava; ; // Määritellään uusi tietotyyppi. // Huomaa, että koska kyseessä on tietotyyppi, eikä muuttuja // se kannattaa sijoittaa globaalille näkyvyysalueelle. int main() { const Kirjainpari KORVAUKSET[] = { { 'ö', 'o', { 'ä', 'a', { 'å', 'a' ; const int LKM = sizeof( KORVAUKSET ) / sizeof( Kirjainpari ); string syote = ""; cin >> syote; for( unsigned int i = 0; i < syote.length(); ++i ) { for( int j = 0; j < LKM; ++j ) { if( syote[ i ] == KORVAUKSET[ j ].korvattava ) { syote[ i ] = KORVAUKSET[ j ].korvaava; cout << syote << endl; return EXIT_SUCCESS;
206 OHJ-1101 Ohjelmointi 1e Harjoitus Piirrä kuva tietorakenteista, joita edellinen ohjelma käyttää: VIP-esimerkit: 7.2. ja 7.3.
207 OHJ-1101 Ohjelmointi 1e Jos edellisessä esimerkissä korvattavien kirjainten lista (ei olisi vakiotaulukossa ja) haluttaisiin järjestää aakkosjärjestykseen, voitaisiin käyttää vaikkapa seuraavaa funktiota: void jarjesta( Kirjainpari taulukko[], int koko ) { // Järjestetään taulukko siten, että jokaisella kierroksella valitaan taulukon // loppuosasta alkio, joka kuuluu seuraavaksi ja siirretään oikealle paikalle. for( int i = 0; i < koko; ++i ) { // Etsitään pienin eli lähinnä aakkosten alkua oleva kirjain lopputaulukosta int pienimmankohta = i; for( int j = i; j < koko; ++j ) { if( taulukko[ j ].korvattava < taulukko[ pienimmankohta ].korvattava ) { pienimmankohta = j; // Vaihdetaan pienin alkio omalle paikalleen Kirjainpari tmp = taulukko[ i ]; taulukko[ i ] = taulukko[ pienimmankohta ]; taulukko[ pienimmankohta ] = tmp;
208 OHJ-1101 Ohjelmointi 1e Itse funktio on hiukan monimutkainen, eikä sen toimintaa ole tässä vaiheessa välttämätöntä ymmärtää, mutta kannattaa kiinnittää huomiota funktion loppuosaan: // Vaihdetaan pienin alkio omalle paikalleen Kirjainpari tmp = taulukko[ i ]; taulukko[ i ] = taulukko[ pienimmankohta ]; taulukko[ pienimmankohta ] = tmp; Tietue on kätevä, kun halutaan, että yhteenkuuluvat alkiot pysyvät yhdessä. Muuttujan rooli: Tilapäissäilö Muuttuja on tilapäissäilö, jos sen arvoa tarvitaan aina vain hyvin lyhyen ajan. Edellisessä funktiossa muuttuja tmp on selkeä esimerkki tilapäissäilöstä.
209 OHJ-1101 Ohjelmointi 1e Merkkijonoista C++:ssa on kaksi eri merkkijonotietotyyppiä: C:stä peräisin oleva char-taulukko vaikea käyttää string-kirjastossa esitelty tietotyyppi, jota jo aikaisemmin käytimme perustietotyyppien tapaan char-taulukot char-taulukot toimivat samoin kuin taulukot yleensäkin. Ne ovat hankalia, koska niiden pituutta ei voi muuttaa. Merkkijonoliteraalilla alustetun char-taulukon ja tavallisen chartaulukon ero on siinä, että merkkijono päättyy aina merkkiin ' \0', jonka ASCII-arvo on nolla. Esim. literaali "Oh yeah!" olisi muistissa muodossa: O h y e a h! \0
210 OHJ-1101 Ohjelmointi 1e Merkkijonon alustus literaalin avulla: char nimi[] = "Teemu Teekkari"; T e e m u T e e k k a r i \0 Merkkijonon käsittelyä: nimi[5] = '\0'; cout << nimi; // Tulostuu "Teemu" T e e m u \0 T e e k k a r i \0 Merkkijonojen käsittelyyn on olemassa valmiita funktioita, esim: int pituus = strlen( nimi ); if( strcmp( nimi, "Oskari" ) == 0 ) { cout << "Se on Oskari!" << endl; Tästä huolimatta char-taulukot ovat melko kömpelöitä käyttää. Huom! Merkkijonon tyyppi voi olla myös char*. Tähän palataan myöhemmin.
211 OHJ-1101 Ohjelmointi 1e Merkkijonotietotyyppi string Ottamalla mukaan kirjasto string saadaan käyttöön joustavampi merkkijonotyyppi, josta voidaan luoda merkkijono- olioita. Olio on tietotyyppi, jolla on omia funktioita (metodeja), jotka on tarkoitettu nimenomaan kyseisen tiedon käsittelemiseen ja siksi niitä kutsutaan vain olion nimen kautta seuraavasti: muuttujanimi.funktio( parametrit ); Esimerkiksi funktio int length(), joka ilmoittaa merkkijonon pituuden, ei ole hyödyllinen, jos ei ole merkkijonoa. stringillä on oma funktio length(), jota voitaisiin käyttää seuraavasti: string merkkijono = "Oh yeah!"; int pituus = merkkijono.length(); cout << pituus << endl;
212 OHJ-1101 Ohjelmointi 1e Esim. jos ohjelmassa olisi tallennettu string-muuttujiin etu ja suku vastaavat nimet, voisimme tarkastella stringin funktiolla length(), onko etunimi pidempi kuin sukunimi esim. seuraavasti: if( etu.length() > suku.length() ) { // Etunimi on pidempi kuin sukunimi... Tai ovatko nimien alkukirjaimet samat stringin funktiolla at( int i ) esim. seuraavasti: if( etu.at( 0 ) == suku.at( 0 ) ) { // Samat alkukirjaimet... Kutsu etu.length() siis palauttaa nimenomaan etu-merkkijonon merkkien lukumäärän ja kutsu suku.length() vastaavasti suku-merkkijonolle. stringin funktio char at( int i ) palauttaa i:nnen merkin merkkijonosta, jolle sitä kutsutaan. VIP-esimerkit: 6.3. ja 6.4.
213 OHJ-1101 Ohjelmointi 1e stringiin liittyy lukematon määrä muitakin funktioita, tässä muutamia esimerkkejä: string mjono = "Nan nan naa"; // Alimerkkijonon valinta (mjono ei muutu!). cout << mjono.substr( 4, 7 ); // tulostuu: nan naa // Lisäys merkkijonon perään (mjono muuttuu!). mjono.append( " na nan nan na naa na!" ); cout << mjono; // tulostuu: Nan nan naa na nan nan na naa na! // Lisäys merkkijonon sisään (mjono muuttuu!). mjono.insert( 11, "," ); cout << mjono; // tulostuu: Nan nan naa, na nan nan na naa na! // Merkkijonon osan korvaus (mjono muuttuu!). mjono.replace( 2, 30, "sta" ); cout << mjono; // tulostuu: Nastaa!
214 OHJ-1101 Ohjelmointi 1e stringiä voi myös indeksoida kuten taulukkoa: mjono[0] = 'n'; cout << mjono; // tulostuu: nastaa! mutta tämä ei tarkista indeksoinnin rajoja, kuten at()-funktio.
215 OHJ-1101 Ohjelmointi 1e Harjoitus Millä string:in funktioista voisi olettaa olevan esiehtoja? Millaisia?
216 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita funktio, joka kääntää nimen oikeaan järjestykseen, mikäli se on annettu muodossa Sukunimi, Etunimi. VIP-harjoitus: 6.3.
217 OHJ-1101 Ohjelmointi 1e Taulukkotietotyyppi vector Kuten string on dynaaminen vastine staattisille merkkijonoille, löytyy myös staattisille taulukoille dynaaminen vastine: vector. vector on C++-standardiin kuuluvan STL:n (Standard Template Library) osa. STL tarjoaa ohjelmoijalle paljon valmiita tietorakenteita ja algoritmeja. Ohjelmoija voi keskittyä olennaiseen eikä pyörää tarvitse aina keksiä uudelleen. Taulukoiden ongelmia C++:ssa: Ne ovat staattisia eli alkioiden lukumäärää voi muuttaa vain kääntämällä ohjelman uudelleen. Taulukkoa ei voi kopioida toiseen taulukkoon =-operaattorilla. Taulukkoa ei voi alustaa toisella taulukolla. Taulukon alkioiden lukumäärää ei yleisesti saa selville, paitsi pitämällä siitä kirjaa itse. vector korjaa nuo puutteet ja paljon muuta.
218 OHJ-1101 Ohjelmointi 1e Jotta vectoria voi käyttää, täytyy ottaa käyttöön kirjasto vector. Ohjelmoija voi tallettaa vectoriin itse valitsemansa tyyppisiä alkioita. Kuten taulukoissakin, yhdessä vectorissa voi olla vain yhdentyyppisiä alkioita. vector määritellään kulmasulkunotaation avulla, esim: vector< int > numerot; vector< string > nimet; vectorin yleinen määrittely: vector< tyyppi > nimi; // kokonaisluku-vector // merkkijono-vector vector on alustettaessa tyhjä, ellei sille anna jotain alustustietoja. vector< double > mittaukset1( 4, 2.3 ); vector< double > mittaukset2( 3 ); vector< double > mittaukset3( mittaukset2 ); Nyt mittaukset1 vectorissa on neljä kertaa alkio 2.3, mittaukset2 vectorissa kolme kertaa alkio 0.0 ja mittaukset3 on samansisältöinen kuin mittaukset2.
219 OHJ-1101 Ohjelmointi 1e Kuten stringillä, vectorillakin on omia funktioita, joiden avulla sitä voidaan käsitellä. vector < int > numerot( 3, 2 ); // sisältää nyt { 2, 2, 2 numerot.clear(); // numerot on nyt tyhjä numerot.push_back( 4 ); numerot.push_back( 8 ); // sisältää nyt { 4, 8 numerot.push_back( numerot.at( 1 ) ); numerot.push_back( numerot[0] ); // sisältää nyt { 4, 8, 8, 4 numerot.pop_back(); // sisältää nyt { 4, 8, 8 if(! numerot.empty() ) { // jos numerot ei ole tyhjä, tulostetaan sen sisältö cout << "Vektorissa:" << endl; for( unsigned int i = 0; i < numerot.size(); ++i ) { cout << numerot.at( i ) << endl; VIP-esimerkit: 6.1. ja 6.2. ja VIP-harjoitus: 6.2.
220 OHJ-1101 Ohjelmointi 1e Esimerkki fysiikantyötuloksia tallentavasta ohjelmasta toteutettuna niin, että mittaustuloksia voi olla mikä tahansa lukumäärä: int main() { double keskiarvo = 0; double summa = 0; vector< double > mittaukset; double mittaus = 0; cout << "Syötä mittaustulokset (lopeta syöttämällä negat. luku):" << endl; while( mittaus >= 0 ) { cin >> mittaus; if( mittaus >= 0 ) { mittaukset.push_back( mittaus ); for( unsigned int i = 0; i < mittaukset.size(); i++ ) { summa = summa + mittaukset.at( i ); keskiarvo = summa / mittaukset.size(); cout << "Keskiarvo on " << keskiarvo << "." << endl; cout << "Keskiarvoa suuremmat mittaustulokset:" << endl; for( unsigned int i = 0; i < mittaukset.size(); i++ ) { if( mittaukset.at( i ) > keskiarvo ) { cout << "Mittaustulos nro " << i+1 << ": " << mittaukset.at( i ) << endl; return EXIT_SUCCESS;
221 OHJ-1101 Ohjelmointi 1e Kannattaa huomata, että push back kopioi parametrina saamansa alkion vectoriin. Toimitaan aivan samalla tavalla kuin parametrin välityksessä yleensäkin. Edellisessä ohjelmaesimerkissä on siis yksi kappale muuttujaa, jonka nimi on mittaus. Tähän muuttujaan luetaan jokaisella silmukan kierroksella uusi arvo cinistä. push back-funktio kopioi muuttujassa olevan arvon vectorin viimeiseksi alkioksi. vectorin koko siis kasvaa yhdellä jokaisella kierroksella. Seuraavalla kierroksella samaan mittaus-muuttujaan voidaan lukea uusi arvo.
222 OHJ-1101 Ohjelmointi 1e Harjoitus Muuta sivun 136 ohjelma sellaiseksi, että se osaa käsitellä kokonaislukuja niin kauan kuin syötetään negatiivinen luku lopettamisen merkiksi. int main() { return EXIT_SUCCESS; VIP-harjoitus: 6.1.
223 OHJ-1101 Ohjelmointi 1e Esimerkki: Palstoittaminen Tehdään ohjelma, joka osaa lukea käyttäjältä sanoja niin kauan, että syötetään sana loppu, ja sen jälkeen tulostaa syötetyt sanat kahteen palstaan jaettuna. Esimerkki ohjelman toiminnasta: proffa>./palstat maanantai tiistai keskiviikko torstai perjantai lauantai sunnuntai loppu maanantai tiistai keskiviikko torstai proffa> perjantai lauantai sunnuntai
224 OHJ-1101 Ohjelmointi 1e Emme etukäteen tiedä, kuinka monta sanaa käyttäjä aikoo syöttää, joten toteutamme ohjelman siten, että sanat tallennetaan vectoria käyttäen: #include <cstdlib> #include <iostream> #include <string> #include <vector> #include <iomanip> using namespace std; int main() { string sana = ""; vector< string > sanat; // Luetaan ja talletataa sanoja, kunnes syötetään sana "loppu" while( sana!= "loppu" ) { cin >> sana; if( sana!= "loppu" ) { sanat.push_back( sana ); unsigned int puolituskohta = static_cast<unsigned int>(sanat.size()/2.0+.5);
225 OHJ-1101 Ohjelmointi 1e // Selvitetään pisimmän ensimmäiseen palstaan tulevan sanan pituus, jotta // tiedetään, kuinka leveäksi ensimmäinen palsta tulostetaan unsigned int pituus = 0; for( unsigned int i = 0; i < puolituskohta; ++i ) { if( sanat.at( i ).length() > pituus ) { pituus = sanat.at( i ).length(); // Palstojen väliin tulostettavien tyhjien merkkien lukumäärä const int PALSTAVALI = 3; // Tulostetaan sanat palstoitettuna for( unsigned int i = 0; i < puolituskohta; ++i ) { // Ensimmäiseen palstaan tuleva sana ja sopivasti tyhjää väliin cout << setw( pituus + PALSTAVALI ) << left << sanat.at( i ); // Toiseen palstaan tuleva sana vain, jos vectorissa on riittävästi sanoja if( puolituskohta + i < sanat.size() ) { cout << sanat.at( puolituskohta + i ); cout << endl; return EXIT_SUCCESS;
226 OHJ-1101 Ohjelmointi 1e Esimerkki Toteutetaan ohjelma, joka lukee opiskelijoiden tenttipistemääriä (opiskelijanumero ja pistemäärä) ja tulostaa sitten arvosanarajojen perustella listan tenttituloksista. Esimerkiksi, jos tentin maksimipistemäärä olisi 30, voisi läpipääsyn pisteraja olla 15 ja arvosanan 2 raja 18 jne. kolmen pisteen välein. Tällöin ohjelma toimisi näin: %./tentti : 14p = : 17p = : 29p = 5 %
227 OHJ-1101 Ohjelmointi 1e #include <cstdlib> #include <iostream> #include <vector> using namespace std; // Talletetaan jotkin sopivat pisterajat, valitaan maksimiksi 30 p. // Taulukon kohdassa 0 pisteraja, joka tarvitaan arvosanaan 1 jne. const int PISTERAJAT[] = { 15, 18, 21, 24, 28 ; const int ARVOSANOJA = sizeof( PISTERAJAT ) / sizeof( int ); // Tietue-tyyppi yhden opiskelijan tietojen tallentamiseen struct Arvostelu { int opnro; int pisteet; int arvosana; ; // Funktio, joka palauttaa pistemäärää vastaavan arvosanan int annaarvosana( const int pisteet ); // Funktio, joka tulostaa listan tiedot void tulostaarvostelu( vector< Arvostelu >& tiedot );
228 OHJ-1101 Ohjelmointi 1e int main() { vector< Arvostelu > lista; cout << "Syötä opiskelijanumero-pistemäärä-pareja " << "(lopetus opiskelijanumerolla -1): "; const int LOPETUS = -1; while( true ) { // Luetaan syötettä... int opnro = 0; int pisteet = 0; cin >> opnro; if( opnro == LOPETUS ) { //...kunnes löytyy lopetuskoodi break; cin >> pisteet; // Alustetaan väliaikaismuuttuja Arvostelu tmp = { opnro, pisteet, 0 ; // Kopioidaan väliaikaismuuttuja talteen vectoriin lista.push_back( tmp );
229 OHJ-1101 Ohjelmointi 1e // Sijoitetaan jokaiselle oikea arvosana for( unsigned int i = 0; i < lista.size(); ++i ) { lista.at( i ).arvosana = annaarvosana( lista.at( i ).pisteet ); tulostaarvostelu( lista ); // Tulostetaan lista arvosanoineen return EXIT_SUCCESS; int annaarvosana( const int pisteet ) { for( int i = 0; i < ARVOSANOJA; ++i ) { if( pisteet < PISTERAJAT[ i ] ) { return i; // Palautetaan suurin arvosana, koska ei jääty minkään pisterajan alle return ARVOSANOJA; void tulostaarvostelu( vector< Arvostelu >& tiedot ) { for( unsigned int i = 0; i < tiedot.size(); ++i ) { cout << tiedot.at( i ).opnro << ": " << tiedot.at( i ).pisteet << "p = " << tiedot.at( i ).arvosana << endl;
230 OHJ-1101 Ohjelmointi 1e Luettelotyyppi enum Joskus tulee tarve muuttujalle, jolla voi olla vain tiettyjä arvoja, esim. kirjaston ohjelmistossa kirjan tila voi olla hyllyssä, lainassa, varattu tai vaikka hukassa. string tai vaikka int sallivat paljon muitakin vaihtoehtoja. Ko. tietotyypit eivät ole parhaita mahdollisia kirjan tilan tallentamiseen. Luettelotyyppi on tietotyyppi (vrt. s.48), jonka kaikki mahdolliset arvot ovat käyttäjän määräämiä. C++:ssa luettelotyyppi määrittellään varatulla sanalla enum. enum Tyypin_nimi { arvo_1, arvo_2,..., arvo_n ; Tämä määrittelee uuden tyypin Tyypin nimi, jonka mahdolliset arvot ovat arvo 1, arvo 2,... ja arvo n. Esim: enum Kirjantila { HYLLYSSA, LAINASSA, VARATTU, HUKASSA ;
231 OHJ-1101 Ohjelmointi 1e Luettelotyypin arvoista on tyyppimuunnos kokonaisluvuiksi. C++kääntäjä määrittelee automaattisesti tyyppimuunnoksen arvoiksi: arvo 1 = 0, arvo 2 = 1 jne. Luettelotyypin arvoja voi siis käyttää kaikkialla, mihin sopisi kokonaisluku- tai char-tyyppinen arvo. Tarvittaessa ohjelmoija voi antaa muunnoksessa käytetyt arvot luettelotyyppiä määriteltäessä itse: enum Tyypin_nimi { arvo_1 = vakio_1,..., alkio_n = vakio_n ; Jos numeroinnin lopettaa kesken, niin loput arvot C++ numeroi automaattisesti aina yhtä suuremmaksi kuin edellinen: enum Vari { PUNAINEN = 8, VIHREA, SININEN = -1, KELTAINEN ; // PUNAINEN = 8, VIHREA = 9, SININEN = -1 ja KELTAINEN = 0 Kahdella tai useammalla arvolla voi myös olla sama vakioarvo.
232 OHJ-1101 Ohjelmointi 1e Joskus on kätevää, että luettelotyyppi osaa kertoa oman kokonsa. enum Kuukausi { TAMMI, HELMI, MAALIS, HUHTI, TOUKO, KESA, HEINA, ELO, SYYS, LOKA, MARRAS, JOULU, KUUKAUSIA_VUODESSA ; Nyt kuukaudet on numeroitu 0-11 ja KUUKAUSIA VUODESSA kertoo kuukausien kokonaismäärän.
233 OHJ-1101 Ohjelmointi 1e Harjoitus Käytössä on seuraavat tietotyypit: enum Kirjantila { HYLLYSSA, LAINASSA, VARATTU, HUKASSA, TILOJEN_LKM ; struct Kirja { string nimi; KirjanTila tila; ; Kirjoita ohjelmapätkä, joka laskee tietorakenteeseen vector< Kirja > kirjat; talletetuista tiedoista, kuinka monta kirjaa missäkin tilassa on.
234 OHJ-1101 Ohjelmointi 1e Toiseen suuntaan automaattista tyyppimuunnosta ei kuitenkaan ole. Luettelotyyppisen tietoalkion paikalla ei siis voi sijoituslauseessa tai funktiokutsun todellisena parametrina käyttää kokonaislukuarvoa ilman eksplisiittistä tyyppikonversiota. enum Vuodenaika { TALVI, KEVAT, KESA, SYKSY ; // Funktio, joka tulostaa vuodenajan tekstinä void tulosta( Vuodenaika neljannes ); int luku = KESA; // luku on 2 Vuodenaika vast = static_cast< Vuodenaika >( luku ); // vast on KESA tulosta( static_cast< Vuodenaika >( luku )); // tulosta( KESA );
235 OHJ-1101 Ohjelmointi 1e Toteutetaan pieni apuohjelma kivi-paperi-sakset-pelin pelaamiseen: #include <cstdlib> #include <iostream> #include <string> using namespace std; enum Vastaus { KIVI, PAPERI, SAKSET, VASTAUS_LKM, VIRHE = -1 ; enum Pelitilanne { VOITTO, TASAPELI, HAVIO ; const string NIMET[ VASTAUS_LKM ] = { "kivi", "paperi", "sakset" ; const string TILANTEET[] = { "Voitit!", "Tasapeli.", "Hävisit." ; Vastaus luevastaus() { string syote = ""; cin >> syote; for( int i = 0; i < VASTAUS_LKM; ++i ) { if( syote == NIMET[ i ] ) { return static_cast< Vastaus >( i ); cout << "Virheellinen syöte!" << endl; return VIRHE;
236 OHJ-1101 Ohjelmointi 1e // Palauttaa pelituloksen vastaajan eka näkökulmasta Pelitilanne peli( Vastaus eka, Vastaus toka ) { if( eka == toka ) { return TASAPELI; else if ( eka == SAKSET && toka == KIVI ) { return HAVIO; else if ( eka == KIVI && toka == SAKSET eka > toka ) { return VOITTO; else { return HAVIO; int main() { cout << "Syötä valintasi: "; Vastaus vast1 = luevastaus(); cout << "Syötä vastustajasi valinta: "; Vastaus vast2 = luevastaus(); if( vast1 == VIRHE vast2 == VIRHE ) { return EXIT_FAILURE; Pelitilanne loppu = peli( vast1, vast2 ); cout << TILANTEET[ loppu ] << endl; return EXIT_SUCCESS;
237 OHJ-1101 Ohjelmointi 1e switch-rakenne switch-rakenteella saadaan aikaan ehdollista suoritusta tilanteissa, joissa 1. testattava arvo on tulkittavissa kokonaisluvuksi ( int, char tai enum). 2. vaihtoehdot, joihin testattavaa arvoa vertaillaan, ovat kokonaisluvuiksi tulkittavissa olevia vakioita. C++:n switch ei ole yhtä joustava kuin if-else. Tiettyihin tilanteisiin se kuitenkin sopii erinomaisesti. Rakenne näyttää seuraavalta: switch ( testattava_arvo ) { case vaihtoehto_1: { käskyt_1; break;... case vaihtoehto_n: { käskyt_n; break; default: { käskyt_def; break;
238 OHJ-1101 Ohjelmointi 1e switch vertaa testattavaa arvoa vaihtoehtoihin. Kun vastaan tulee vaihtoehto, joka on yhtäsuuri kuin testattava arvo, niin suoritetaan vastaavaan case-haaraan liittyvät käskyt. Jos mikään vaihtoehto ei täsmää, suoritetaan default-haaran käskyt. default voi puuttua. On mahdollista, että switch-rakenne ei tee mitään. Kun suoritettava haara on kerran valittu, suoritus jatkuu, kunnes törmätään break-käskyyn. break keskeyttää switch-rakenteen suorituksen. Suoritus jatkuu rakenteen perästä.
239 OHJ-1101 Ohjelmointi 1e Mikäli jostain haarasta puuttuu break, niin suoritus "putoaa" seuraavan haaran puolelle. Tätä ominaisuutta käytetään usein silloin, kun useaan vaihtoehtoon liittyy samat toiminnot: switch ( vastaus ) { case 'e': case 'E': {... suoritettavat toiminnot break; vastauksen ollessa e tai E
240 OHJ-1101 Ohjelmointi 1e break:in voi jättää pois, jos haarasta (koko funktiosta) poistutaan return:illa: string kuukaudennimi( Kuukausi kuukausi ) { switch ( kuukausi ) { case TAMMIKUU: { return "tammikuu"; case HELMIKUU: {... case JOULUKUU: { return "joulukuu";
241 OHJ-1101 Ohjelmointi 1e Esimerkki Laajennetaan kirjaston cctype funktiota int tolower( int c ), joka palauttaa merkkiä c vastaavan pienen kirjaimen ( A a ) siten, että se toimii myös ääkkösten kanssa: char ToLower( char c ) { switch( c ) { case 'Å': case 'å': { return 'å'; case 'Ä': case 'ä': { return 'ä'; case 'Ö': case 'ö': { return 'ö'; default: { return static_cast< char >( tolower(c) );
242 OHJ-1101 Ohjelmointi 1e Kirjastossa cctype on muitakin hyödyllisiä funktioita yksittäisten merkkien käsittelyyn: Funktio palauttaa true, jos c on... bool isdigit( int c ) numero bool islower( int c ) pieni kirjain bool isupper( int c ) iso kirjain bool isalpha( int c ) ylipäätään kirjain bool isalnum( int c ) kirjain tai numero bool isspace( int c ) tyhjä merkki bool ispunct( int c ) väli- tai erikoismerkki bool iscntrl( int c ) kontrollimerkki Lisäksi funktio int toupper( int c ), joka muuttaa kirjaimet isoiksi kirjaimiksi ( a A ). stringiä indeksoitaessa (joko [ ]-operaattorilla tai at( int i )- funktiolla) palautuu tyyppi char. cctype-kirjaston funktioita voi käyttää stringien käsittelyyn esim. seuraavasti: string mjono = "pikkukirjaimia"; for( unsigned int i = 0; i < mjono.size(); ++i ) { mjono[i] = toupper( mjono[i] );
243 OHJ-1101 Ohjelmointi 1e Tyyppialias Joskus tulee tarve tyypeille, joilla ei kuulu operoida keskenään. Esim. rahaa ja kilogrammoja ei kannata laskea yhteen, vaikka molemmat saattavat olla tallennettuina double-muuttujiin. Silloin voidaan yrittää selkeyttää tilannetta antamalla jo olemassa olevalle tyypille vaihtoehtoinen nimi typedef-määrittelyllä. Esim. typedef double Valuutta; typedef ei kuitenkaan luo uutta tyyppiä, vaan esimerkin tyypit double ja Valuutta olisivat keskenään vaihtokelpoisia. Tyyppialiaksilla voidaan parantaa koodin luettavuutta. Tyyppialiaksilla voidaan parantaa myös koodin siirrettävyyttä. Esimerkiksi joissain koneissa tyyppi int on vain 16-bittinen. Jos ohjelma siirrettäisiin tälläiseen ympäristöön ja tarvittaisiin isoja rahasummia, niin ainoastaan aliaksen määrittely täytyisi muuttaa ja kaikki ne tsiljoona kohtaa, jossa aliasta käytetään, saisivat olla ennallaan.
244 OHJ-1101 Ohjelmointi 1e Hierarkkiset tyypit Olemassa olevista tyypeistä voi koota hierarkkisia tietuetyyppejä. enum Kansalaisuus { SUOMI, EU, MAAILMA ; struct Henkilo { string sukunimi; string etunimi; string toinennimi; unsigned int ika; Kansalaisuus kansalaisuus; ; struct TiliNro { string konttori; string tili; ; enum Kulkualue { TIETOTALO, SAHKOTALO,... ; struct Tyontekija { Henkilo htiedot; Valuutta kkpalkka; TiliNro maksuyhteys; vector< Kulkualue > kulkualueet; ;
245 OHJ-1101 Ohjelmointi 1e Viittaus tehdään aivan normaalisti: Tyontekija vahtimestari; vahtimestari.htiedot.sukunimi = "Jalo"; vahtimestari.htiedot.kansalaisuus = SUOMI; vahtimestari.maksuyhteys.tili = " "; vahtimestari.kulkualueet.push_back( TIETOTALO ); Piirrä kuva rakenteesta:
246 OHJ-1101 Ohjelmointi 1e Harjoitus Minkälaisia tyyppejä voitaisiin määritellä, jos haluttaisiin tallettaa tämän periodin lukujärjestyksesi? Minkätyyppiseen muuttujaan lukujärjestys voitaisiin tallettaa? Miten tähän muuttujaan saataisiin asetettua tiedot kurssista Ohjelmointi 1e?
247 OHJ-1101 Ohjelmointi 1e Ohjelmistoprojekti Isot ohjelmistoprojektit koostuvat yleensä toivon mukaan seuraavista osista: Vaatimukset (10%) Määrittely (15%) Suunnittelu (21%) Koodaus (15%) Testaus (21%) Integrointi (18%) Ylläpito (??%) Prosenttiluvut kuvaavat osuutta projektin kokonaiskustannuksista. Huomaa, että ohjelmisto ( software) ei rajoitu pelkästään tehtyyn ohjelmaan. Tuotteeseen kuuluvat myös tehdyt dokumentit ja muu oheistuotanto. Tällä kurssilla käsitellään suunnittelua, koodausta ja testausta. Kellomäki, Mäkinen: Ohjelmoinnin alkemia ja Scheme-kieli
248 OHJ-1101 Ohjelmointi 1e Vaatimukset Aivan projektin aluksi selvitetään kaikki työhön liittyvät reunaehdot. Käytännössä tämä tarkoittaa sitä, että asiakas (työn tilaaja) pyrkii kertomaan mahdollisimman tarkasti, mitä hän haluaa. Vaatimusten perusteella työn tekijä voi aloittaa esitutkimustyön, jonka tuloksia voidaan käyttää määrittelyvaiheessa. Määrittely Määrittelyvaiheen tehtävänä on kuvata toteutettavan ohjelmiston toiminta kaikissa olosuhteissa. Mitä huolellisemmin tehdyt määrittelydokumentit, sitä helpompi niiden pohjalta on ohjelmisto rakentaa. Ohjelmiston oikeellisuus ja toimivuus tarkoittavat sitä, että ohjelmisto toimii määrittelynsä mukaisesti. Määrittelytyö tehdään yhdessä asiakkaan kanssa.
249 OHJ-1101 Ohjelmointi 1e Suunnittelu Määrittely vastaa kysymykseen "Mitä tehdään?". Suunnittelu kertoo miten. Isoja ohjelmistoja ei voida lähteä koodaamaan suinpäin ihan vain ilispohjalta. Työ jaetaan osiin, jonka jälkeen eri osia (moduuleja) voidaan ohjelmoida rinnakkain. Osakokonaisuuksia ja niiden välisiä rajapintoja suunniteltaessa tulee ottaa huomioon mm. muunneltavuus, uudelleenkäytettävyys, testattavuus ja ohjelmiston sisäinen looginen rakenne. Hyvä suunnitelma on hierarkkinen, jolloin ohjelman osien väliset riippuvuudet eivät muodosta silmukoita. Tällöin ohjelman osat on helppo rakentaa, testata ja liittää toisiinsa.
250 OHJ-1101 Ohjelmointi 1e Koodaus Mikäli edeltävät vaiheet on toteutettu hyvin, niin varsinainen koodaus on kohtalaisen suoraviivaista hommaa. Yksittäisen ohjelmoijan vastuulla on määrätyn ohjelmiston osan (moduulin) toteuttaminen suunnitellulla tavalla ja määrittelyn mukaisesti. Tehdyn koodin tulisi olla hyvän ohjelmointityylin mukaista. Huom: Pienissä ohjelmissa ja valitettavan usein isommissakin lähdekoodi on ohjelman ainoa ajantasalla oleva dokumentti. Vielä senkin pitäisi selvästi ja ymmärrettävästi kertoa, mitä ollaan tekemässä tai ainakin ohjata tiedon alkulähteelle.
251 OHJ-1101 Ohjelmointi 1e Testaus Jokainen toteutettu osakokonaisuus testataan tehdyn testaussuunnitelman mukaisesti. Testaussuunnitelman teko on osa suunnitteluvaihetta. Testien tehtävänä on löytää virheitä, mitä enemmän sen parempi. Koska on testattu tarpeeksi? Testaussuunnitelma on käyty läpi Halutut mittaluvut toteutuvat, esim. testikattavuus Tuottavinta on testaus kynällä ja paperilla suunnittelu- ja koodausvaiheissa. Suunnitteluun jääneet ristiriitaisuudet löytyvät aikaisemmin. Paljon jälkikäteen vaikeasti löydettäviä virheitä jää tekemättä. Ei kokonaan korvaa testaamista, mutta helpottaa virheitä löytävien testitapauksien suunnittelua Liian helposti tulee valittua vain sellaisia testitapauksia, joilla ohjelma toimii oikein.
252 OHJ-1101 Ohjelmointi 1e Integrointi Kun ohjelmiston osat ovat valmiit, ne liitetään yhteen ja aletaan testaamaan kokonaisuutta. Integrointia ei tehdä kerralla, vaan osat liitetään ohjelmaan yksitellen. Ylläpito Ohjelmiston tyypistä riippuen sille täytyy tarjota rinnakkaispalveluita kuten erilaiset koulutus- ja tukitoiminnot. Tässä vaiheessa on vielä kohtuullisen helppoa pilata hyvä asiakassuhde.
253 OHJ-1101 Ohjelmointi 1e Ohjelmointityylistä Suurin osa ohjelmointikielistä ei aseta vaatimuksia ohjelmakoodin asettelulle. Niin kauan kuin ohjelmakoodi täyttää kielen syntaktiset ja semanttiset vaatimukset, kääntäjä tai tulkki ei välitä. Monissa ohjelmointikielissä koko ohjelman voi esimerkiksi kirjoittaa yhdelle pitkälle riville. Käytännössä ohjelmakoodia kuitenkin aina joutuvat lukemaan ja muokkaamaan myös ihmiset, muutkin kuin koodin alkuperäinen kirjoittaja. On kriittisen tärkeää, että ohjelmaa kirjoitettaessa kiinnitetään huomiota myös koodin ulkoasuun ja pyritään tekemään siitä mahdollisimman selkeä. Selkeä ja johdonmukainen rakenne auttaa ihmislukijaa ymmärtämään koodin tarkoituksen. Noudattamalla muutamia yksinkertaisia periaatteita koodista saa selkeää varsin pienellä lisävaivalla.
254 OHJ-1101 Ohjelmointi 1e Tyyliopas Koska nykyaikaiset ohjelmointikielet ovat mutkikkaita ja monitahoisia, pyritään tyylioppaalla rajaamaan projektin tai organisaation tarpeisiin sopivat tavat käyttää niitä. Yhtenäisen ohjelmointityylin noudattaminen lisää lähdekoodin ymmärrettävyyttä, ylläpidettävyyttä, siirrettävyyttä, luettavuutta ja uudelleenkäytettävyyttä. Mutkikkaissa ohjelmointikielissä, kuten C++, ohjeet voivat myös lisätä koodin tehokkuutta ja auttaa virheiden välttämisessä. Ohjelmistotekniikan laitoksen C++-tyyliopas löytyy osoitteesta oliot/kirja/tyyliopas/ Oppaaseen on koottu sääntöjä ja suosituksia, jotka liittyvät ohjelmakoodin ulkoasuun, muokkaamiseen ja taltiointiin.
255 OHJ-1101 Ohjelmointi 1e Kommentointi Kommentoinnin tarkoituksena on selittää, miksi jokin asia on koodissa tai mikä on sen tarkoitus. Kommentoitaessa saa olettaa, että lukija ymmärtää käytettyä ohjelmointikieltä suvereenisti. Seuraavat kommentit ovat huonoja: d = x * x + y * y; return sqrt( d ); // Sijoitetaan muuttujaan d arvo x*x+y*y. // Palautetaan muuttujan d neliöjuuri. koska ne eivät tarjoa mitään uutta informaatiosisältöä lukijalle, joka osaa C++:aa. Vältä siis koodissasi ohjelmointikielen ominaisuuksien ja itsestäänselvyyksien kommentointia. Huomaa kuinka paljon hyödyllisempiä seuraavat kommentit ovat: d = x * x + y * y; // Lasketaan diskriminantti kateeteista x ja y. return sqrt( d ); // Diskriminantista d saadaan hypotenuusa. Nämä kommentit eivät enää keskity itsestäänselvyyksiin, vaan selittävät yleisemmällä tasolla koodirivien tarkoitusta.
256 OHJ-1101 Ohjelmointi 1e Ideaalitilanteessa ohjelmakoodi tulisi kommentoida niin tarkasti, että siitä ei voi esittää "miksi"- tai "mikä on tämän tarkoitus"- kysymystä, johon ei löytyisi vastausta kommenteista. Yleensä jokaisen lähdekooditiedoston alkuun kannattaa lisätä lyhyt kommentti, joka kertoo koodin tekijän ja sen tarkoituksen (siis lyhyen kuvauksen ohjelman toiminnasta). Jokaisen funktion alkuun/esittelyyn on hyvä lisätä kommentti selittämään funktion tarkoitusta, parametreja ja paluuarvoa: // Funktio: pythagoras // Tarkoitus: Funktio laskee pythagoraan lauseella suorakulmaisen // kolmion hypotenuusan pituuden. // Parametrit: double x, double y: kateettien pituudet. // Paluuarvo: double, hypotenuusan pituus. double pythagoras( double x, double y); Kannattaa pitää mielessä myös se, että kommentoinnissakaan määrä ei korvaa laatua.
257 OHJ-1101 Ohjelmointi 1e Sisennykset Sisennys tarkoittaa loogisesti yhteenkuuluvien koodirivien asettelua samalle tasolle (yhtä kauas koodin vasemmasta laidasta). Ihmislukijan on helppo hahmottaa, mikä on osa mitäkin kokonaisuutta. Sisennysten periaate on hyvin yksinkertainen: aina uuden lohkon alussa kasvatetaan rivien sisennystä tietyn vakiomäärän verran (45 välilyöntiä) ja lohkon lopussa palautetaan sisennys lohkoa edeltäneelle tasolle. Sisennykset ovat ehkä tärkein ja helppokäyttöisin yksittäinen tekijä, jonka avulla koodista saa selkeämpää. Monisteen esimerkit on sisennetty huolellisesti ja niistä kannattaa ottaa mallia. Jotkut editorit (esim. jed ja emacs) osaavat auttaa koodin sisentämisessä. Viime kädessä vastuu on kuitenkin koodaajan, koska aputyökalut eivät ole erehtymättömiä. Siis aaltosulkuparin { sisällä.
258 OHJ-1101 Ohjelmointi 1e Tyhjä tila Tyhjät rivit ja ylimääräiset välilyönnit (muualla kuin rivien alussa) ovat hienovarainen työkalu koodin ulkoasun selkeyttämiseen. Tyhjää tilaa on helppo käyttää liikaa tai liian vähän. "Tyylikeino" joka vaatii näkemystä. Vaikea antaa absoluuttisia ohjeita. Esimerkiksi seuraava koodi: int i=0;//silmukkamuuttuja tulostamiseen. while(i<10){ cout<<i<<endl; if(i==9){ tulostasumma(1,9); näyttää paremmalta, kun käyttää myös välilyöntejä ja rivinvaihtoja: int i = 0; // Silmukkamuuttuja tulostamiseen. while ( i < 10 ) { cout << i << endl; if ( i == 9 ) { tulostasumma( 1, 9 );
259 OHJ-1101 Ohjelmointi 1e Rivin pituus Pidä koodiriviesi pituus alle 80 merkissä. Tämä tyyliohje perityy historian aamuhämärästä, jolloin näyttöpäätteiden leveys oli 80 merkkiä. Ohje on kuitenkin pätevä vielä nykypäivänäkin. Jos koodiisi väkisin tulee C++-lauseita tai -lausekkeita, joiden pituus on yli 79 merkkiä, jaa ne jotenkin selkeästi useammalle riville. const string PITKA_MERKKIJONO = "Katenointi on ominaisuus, jonka " "avulla kääntäjä yhdistää peräkkäiset merkkijonoliteraalit " "yhdeksi.\n"; Pitkien rivien katkaisemisesta on luentomonisteessa paljonkin malleja (esimerkiksi pitkän cout-tulostuksen jakaminen monelle riville). Yleensä jatkorivejä kannattaa sisentää enemmän kuin ensimmäistä riviä.
260 OHJ-1101 Ohjelmointi 1e Nimeämiskäytäntö Muuttujat, funktiot ja tietotyypit on järkevä nimetä siten, että niiden nimestä pystyy suoraan lukemaan tarkoituksen. Valitsemalla nimiksi selkeitä puhutun kielen sanoja tai ilmaisuja koodin lukeminen on helpompaa. Kääntäjä ei välitä kirjoittaako koodin const int m = 12; double f( double a ); int o = 0; struct ttt {... ; vai const int KUUKAUSIEN_LUKUMAARA = 12; double laskepolynomib( double xkoordinaatti ); int opiskelijanumero = 0; struct Tuote {... ; jälkimmäinen on kuitenkin lukijan kannalta paljon selkeämpi.
261 OHJ-1101 Ohjelmointi 1e On useita koulukuntia siitä, kuinka valitut nimet pitäisi kirjoittaa. Ohjelmistotekniikan laitoksen tyylioppaan mukainen tapa on kirjoittaa: tietotyypien nimet isolla alkukirjaimella muuttujien ja funktioiden nimet pienellä alkukirjaimella useammasta sanasta koostuvat nimet kirjoitetaan yhteen ja loppupään sanat aloitetaan isolla alkukirjaimella, esim. haeraportinpaivays() vakioiden nimet kokonaan isoilla kirjaimilla, sanaväleinä alaviiva, esim. PUSKURIN SUURIN KOKO Tämä ei ole missään tapauksessa ainoa oikea tapa. Minkä tavan ikinä valitseekin, tärkeintä on noudattaa sitä uskollisesti. Hyvin valitut nimet vähentävät usein kommentoinnin tarvetta. Ohjelmakoodin kommentit ja symboliset nimet kirjoitetaan yhtenäisellä kielellä.
262 OHJ-1101 Ohjelmointi 1e Vakiomuuttujat (const-vakiot) Vakiomuuttujien avulla voidaan nimetä koodin epämääräiset ja vaikeaselkoiset vakioarvot. Hyvin valitut nimet selkeyttävät koodia: int paiva = 29; on vaikeatajuisempi kuin const int KARKAUSPAIVA = 29;... int paiva = KARKAUSPAIVA; Jos jotain vakioarvoa täytyy koodissa muuttaa, on se helpompi tehdä kerran const-vakion määrittelykohdassa kuin käydä koko koodi läpi ja muuttaa kaikki literaaliarvot käsin.
263 OHJ-1101 Ohjelmointi 1e Vakiomuuttujienkin nimet kannattaa valita huolella kuvaamaan niiden tarkoitusta. Usein näkee aloittelevien ohjelmoijien syyllistyvän seuraavaan tyylivirheeseen: const int VIISI = 5; Tämä ei tuo ohjelman selkeyteen mitään lisäarvoa, vaan koodiin on kirjattu itsestäänselvyys. Parempi olisi miettiä, mitä literaaliarvo 5 esittää, ja keksiä nimi sen perusteella vaikkapa: const int TENTTITEHTAVIA = 5; tai mistä sitten ikinä onkaan kyse.
264 OHJ-1101 Ohjelmointi 1e Esimerkki Suunnitellaan ohjelma, joka kysyy tiedoston nimen ja tulostaa tiedoston sisällön siten, että rivit on numeroitu. Algoritmi on hyvin yksinkertainen: Algoritmi: Rivinumerot tiedostoon kysy käyttäjältä tiedoston nimi yritä avata ko. nimellä varustettu tiedosto luettavaksi IF avaaminen onnistui THEN WHILE tiedostossa on rivejä tulosta rivinumero ja rivi sulje tiedosto ELSE tulosta virheilmoitus lopeta ohjelma Ongelmana onkin lähinnä tiedoston käsittelyn yksityiskohtien toteuttaminen. C++:ssa tiedostoja voi käsitellä olioina.
265 OHJ-1101 Ohjelmointi 1e Ratkaisu C++:lla: 1 #include <iostream> #include <cstdlib> #include <fstream> #include <iomanip> 5 using namespace std; int main() { string tiedostonnimi = ""; 10 cout << "Anna tiedoston nimi: "; cin >> tiedostonnimi; ifstream tiedosto( tiedostonnimi.c_str() ); // stringin c_str()-funktio palauttaa sisällön 15 // C:n merkkijonona
266 OHJ-1101 Ohjelmointi 1e if( tiedosto ) { cout << " --- " << tiedostonnimi << " --- " << endl; string rivi = ""; int rivinro = 1; 20 while( getline( tiedosto, rivi ) ) { cout << setw(3) << rivinro << ": " << rivi << endl; ++rivinro; 25 tiedosto.close(); else { cerr << "Virhe! Tiedostoa " << tiedostonnimi << " ei saatu avattua." << endl; 30 return EXIT_SUCCESS;
267 OHJ-1101 Ohjelmointi 1e Tietovirran (stream) idea Usein ohjelmoidessa tulee tarve lukea ohjelman käyttöön tietoa, joka on talletettuna tiedostossa koneen kovalevyllä. tallettaa ohjelman tuottamia tuloksia tiedostoon kovalevylle myöhempää käyttöä varten. Jotta ohjelma voisi käsitellä tiedostoja, täytyy ohjelmointikielessä olla tapa, jolla esitetään reaalimaailman levytiedosto (pätkä magneettiraitaa kovalevyn pinnalla). Tavallisesti ohjelmointikielet ratkaisevat tämän ongelman erityisellä tietotyypillä, joka tarjoaa funktiot tiedon lukemiseen ja kirjoittamiseen. C++:ssa ja monissa muissa ohjelmointikielissä tällaista tietotyyppiä (oliota) kutsutaan tietovirraksi (stream). Itse asiassa tietovirran käsite on laajempi kuin pelkkä liittymä levytiedostoihin: kaikki ohjelman syötteet ja tulosteet ovat tietovirtoja.
268 OHJ-1101 Ohjelmointi 1e Tietovirran voi ajatella jonona merkkejä, jotka liikkuvat järjestyksensä säilyttäen yhteen suuntaan. Ainoastaan syötevirran ensimmäisen merkin voi lukea (operaatio get). Ainoastaan tulostusvirran perään voi kirjoittaa merkin (operaatio put). Kaikki muut toimenpiteet voidaan toteuttaa get:in ja put:in avulla. Merkkien järjestyksen säilyminen tietovirrassa on olennainen ominaisuus, esimerkiksi: Jos käyttäjä kirjoitaa näppäimistöltä merkkisarjan " abcdef", niin toki ohjelma syötevirtaa ( cin) lukiessaan saa merkit käyttöönsä samassa järjestyksessä. Jos ohjelma kirjoittaa levytiedostoon sidottuun tulostusvirtaan merkkejä tietyssä järjestyksessä, niin toki on tarkoituksenmukaista, että merkit tallettuvat tiedostoon juuri samassa järjestyksessä.
269 OHJ-1101 Ohjelmointi 1e Tietovirrat ovat peräkkäissaantirakenteita : niiden siirtämää tietoa voidaan käydä läpi vain siinä järjestyksessä, jossa se on virrassa. Jos ohjelmaa kiinnostaa käyttäjän näppäimistösyötteen viides merkki, niin ennen sen lukemista täytyy lukea neljä edeltävää merkkiä. Sama pätee oletusarvoisesti myös syötevirtaan, joka on sidottu levytiedostoon: tiedosto on luettava läpi järjestyksessä alusta loppuun. Tosiasiassa levy tiedostoja on mahdollista käsitellä myös hajasaantirakenteina, eli niiden sisältö voidaan lukea ja kirjoittaa hyppien sinne tänne. Yleensä tietovirta kulkee ohjelman ja jonkin oheislaitteen (näppäimistö, levytiedosto jne.) välillä, mutta joskus myös kahden ohjelman välillä.
270 OHJ-1101 Ohjelmointi 1e Tietovirrat ja niiden käyttö C++:ssa C++-kielessä tietovirrat esitetään tietotyyppeinä, jotka ovat toteutettu kirjastoissa: #include <iostream> istream syötevirrat, jotka on yleensä valmiiksi sidottu näppäimistöön ( cin) ostream tulostusvirrat, jotka on yleensä valmiiksi sidottu näyttöön ( cout, cerr ja clog) #include <fstream> ifstream syötevirrat, jotka käyttäjän on itse sidottava levytiedostoon ofstream tulostusvirrat, jotka käyttäjän on itse sidottava levytiedostoon fstream sekä tulostus- että syötevirrat, jotka käyttäjän on itse sidottava levytiedostoon #include <sstream> istringstream syötevirrat, jotka käyttäjän on itse sidottava merkkijonoon ostringstream tulostusvirrat, joiden avulla voidaan muuttaa tietoja merkkijono muotoisiksi (tulostaa merkkijonoon) stringstream virrat, joiden avulla voidaan sekä tulostaa merkkijonoon että lukea siitä Ohjelmoijan ei tarvitse huolehtia cinin, coutin ja cerrin sitomisesta: ne ovat direktiivin #include <iostream> jälkeen automaattisesti käytettävissä.
271 OHJ-1101 Ohjelmointi 1e Tietovirtojen käyttö koostuu yleensä kolmesta vaiheesta ( cin, cout ja cerr siis poikkeuksia): 1. alustaminen (avaaminen, sitominen) 2. käsittely (eli operointi: luku, kirjoitus) 3. sulkeminen Esimerkkiohjelmassa tiedostosta lukiessa suoritettiin nämä kolme vaihetta. Vastaavasti tiedostoon tulostaminen tapahtuisi siis siten, että 1. avataan tiedosto 2. tulostetaan sinne aivan samoin kuin ciniin ja 3. suljetaan tiedosto.
272 OHJ-1101 Ohjelmointi 1e Vaihe 1: Tietovirran alustaminen Ennen fstream- ja sstream-kirjastojen tarjoamilla tietovirroilla operointia, ne on alustettava: ifstream ofstream istringstream ostringstream Luodaan ifstream-tyyppinen muuttuja ja kerrotaan, minkä nimisestä tiedostosta syöte luetaan: ifstream virran nimi( tiedoston nimi ); Luodaan ofstream-tyyppinen muuttuja ja kerrotaan, minkä nimiseen tiedostoon syöte kirjoitetaan: ofstream virran nimi( tiedoston nimi ); Luodaan istringstream-muuttuja ja kerrotaan merkkijono, josta syöte luetaan: istringstream virran nimi( merkkijono ); Luodaan ostringstream-muuttuja, johon voidaan tulostaa tietoja: ostringstream virran nimi;
273 OHJ-1101 Ohjelmointi 1e Edellisessä taulukossa tiedoston nimi ei ole string-tyyppinen, vaan C-kielen char-taulukko. Ohjelmoijan on annettava tiedoston nimi oikean tyyppisenä: string tiedoston_nimi = ""; cin >> tiedoston_nimi; ifstream tiedosto( tiedoston_nimi.c_str() ); stringin c str()-funktio palauttaa string-merkkijonoa vastaavan C-merkkijonon. tiedoston nimi voi olla myös merkkijonoliteraali, koska merkkijonoliteraalin oletustyyppi C++:ssa on C-merkkijono: ifstream tiedosto( "syotteet.txt" ); Joissain tilanteissa saattaa tarvita alustaa tietovirtamuuttuja ensin ja sitoa se vasta myöhemmin johonkin tiedostoon. Tällöin voi käyttää funktiota open: ifstream tiedosto; // Tietovirtaa ei vielä voi käyttää... tiedosto.open( "syotteet.txt" );
274 OHJ-1101 Ohjelmointi 1e Vaihe 2: Tietovirran käsittely Alustettuun tietovirtaan voi sitten soveltaa eri operaatioita riippuen sen tyyppistä ja siitä, onko se syöte- vai tulostusvirta. Tietovirroilla operointi sattaa vaikuttaa hiukan sekavalta, koska C++:ssa operaatioiden merkintätapoja on useita: operaattorit: cout << "kukkuu"; funktiot: getline( cin, mjono ); stream:ien funktiot: cout.put('a');
275 OHJ-1101 Ohjelmointi 1e Operaatiot, jotka voidaan kohdistaa kaiken tyyppisiin tulostusvirtoihin (esimerkkinä käytetty cout:ia): cout << arvo << endl cout.put( merkki ) cout << setw( leveys ) Tulostetaan lausekkeen arvo virtaan: arvo voi olla tyypiltään perustietotyyppi tai string. Rivinvaihto saadaan tulostettua endl:n avulla. Tulostetaan yksi merkki ( char) virtaan. Kaikki muut sivulla 122 esitellyt tulostuksen ohjauskomennot ovat käytettävissä, kunhan muistaa sanoa #include <iomanip>. Olennaisia tulostukseen liittyviä operatioita ei ole tämän enempää: melkein kaiken saa hoidettua << -operaattorilla. Lisäksi ostringstream-tyyppiseen virtaan voidaan kohdistaa operaatio: virta.str() Palauttaa kaiken virtaan tulostetun tiedon merkkijonona (string).
276 OHJ-1101 Ohjelmointi 1e Operaatiot, jotka voidaan kohdistaa kaiken tyyppisiin syötevirtoihin (esimerkkinä käytetty cin:iä): cin >> muuttuja Lukee virrasta seuraavan sanan, tulkitsee sen muuttujan tyyppiseksi arvoksi ja tallettaa arvo muuttujaan, joka voi olla tyypiltään perustietotyyppi tai string. cin.get() Lukee ja palauttaa virran seuraavan merkin. cin.get(merkki) Lukee virrasta seuraavan merkin muuttujaparametriin merkki, jonka on oltava tyypiltään char. getline(cin, str) Lukee virrasta rivin tekstiä ja tallettaa sen stringtyyppiseen muuttujaparametriin str ilman loppurivinvaihtoa. getline(cin, str, chr) Kuten edellä, mutta rivinvaihdon sijaan lukee ensimmäiseen vastaantulevaan merkkiin chr saakka. cin.ignore(montako, merkki) Lukee virtaa korkeintaan montako merkkiä tai kunnes vastaan tulee ensimmäinen merkki. Heittää luetut merkit menemään. Montako on tyypiltään int ja merkki char. cin.peek() Paluuarvona on seuraava syötevirrassa oleva merkki. Merkkiä ei lueta pois virrasta, vaan seuraava lukuoperaatio palauttaa myös sen.
277 OHJ-1101 Ohjelmointi 1e Vaihe 3: Tietovirran sulkeminen Kun virtaa ei ohjelmassa enää tarvita, se on syytä sulkea, sillä muuten se jää kuluttamaan järjestelmän rajallisia resursseja. Virran sulkeminen voi tapahtua kahdella tavalla: 1. Jos virta on paikallinen muuttuja, niin C++ sulkee sen automaattisesti, kun sen määrittelylohkosta poistutaan. 2. Tarvittaessa virran voi myös sulkea "käsin" close-jäsenfunktiolla: ifstream tietokanta( "puhnrot.dat" );... // Virralla operointi tässä välissä... tietokanta.close(); Kun virta on suljettu, sillä ei enää voi operoida, paitsi tietenkin, jos sen alustaa uudelleen.
278 OHJ-1101 Ohjelmointi 1e Tietovirrasta lukeminen 3 tapaa Ohjelman syötteitä luettaessa on tärkeää ymmärtää, millä tavoin syötteitä halutaan käsitellä ohjelmassa. Valitaan oikea tapa jäsentää ja tallentaa syötteet. Yleisimmin syötteiden käsittelyyn sopii jokin seuraavista tai näiden yhdistelmä: 1. Luetaan merkki kerrallaan 2. Luetaan sana kerrallaan (sanalla tässä tarkoitetaan tyhjillä merkeillä toisistaan eroteltuja kokonaisuuksia) 3. Luetaan rivi kerrallaan
279 OHJ-1101 Ohjelmointi 1e Lukeminen merkki kerrallaan istreameilla on funktio get, jolla tietovirrasta voidaan lukea seuraava merkki: 1 #include <cstdlib> #include <iostream> using namespace std; 5 int main() { char merkki = ' '; while( cin.get( merkki ) ) { cout << "Luettiin '" << merkki << "'" << endl; 10 return EXIT_SUCCESS; Tällä tavalla käsitellyksi tulevat aivan kaikki merkit, joita tietovirrassa on. Esimerkiksi välilyönti ja rivinvaihto näkyisivät tulosteessa Luettiin merkki.... Kokeile esimerkkiohjelmaa proalla: /usr/local/kurssit/ohj1e/merkkikerrallaan (Ohjelman saa lopetettua kirjottamalla ctrl+d)
280 OHJ-1101 Ohjelmointi 1e Lukeminen sana kerrallaan Tämä on tutuin tapa lukea syötettä: olemme käyttäneet >>-operaattoria melkein kurssin alusta asti lukemaan muuttujille arvoja. >>-operaattori ei huomioi tyhjiä merkkejä, eli välilyönnit, tabuloinnit ja rivinvaihdot hypätään yli. Operaattorilla käytettäessä muuttujaan talletetaan virrasta ensimmäinen yhtenäinen merkkijono. 1 #include <cstdlib> #include <string> #include <iostream> using namespace std; 5 int main() { string sana = ""; while( cin >> sana ) { 10 cout << "Luettiin '" << sana << "'" << endl; return EXIT_SUCCESS; Kokeile esimerkkiohjelmaa proalla: /usr/local/kurssit/ohj1e/sanakerrallaan (Ohjelman saa lopetettua kirjottamalla ctrl+d)
281 OHJ-1101 Ohjelmointi 1e Jos >>-operaattorilla ollaan lukemassa jonkin muun tyyppiseen muuttujaan kuin string, operaattori lukee vain niin pitkälle kuin se sopii muuttujan tyyppin. int luku = 0; cin >> luku; Esimerkiksi, jos edellämainitussa tilanteessa syöte olisi 123abc, tulisi muuttujan luku arvoksi 123 ja kirjainmerkit jäisivät virtaan odottamaan seuraavaa lukuoperaatiota. Jos virrasta tule vääräntyyppistä tietoa (esim. kun ollaan lukemassa kokonaislukua, yritettäisiinkin syöttää kirjaimia), >>-operaattori ei toimi. Myöhemmin tutustutaan siihen, miten voidaan tarkastaa, että syöte on oikeantyyppistä.
282 OHJ-1101 Ohjelmointi 1e Lukeminen rivi kerrallaan Funktio getline lukee tietovirran sisältöä string-tyyppiseen muuttujaan kunnes vastaan tulee annettu merkki. Useimmiten tätä käytetään yhden rivin lukemiseen (oletuksena rivinvaihtomerkki). 1 #include <cstdlib> #include <string> #include <iostream> using namespace std; 5 int main() { string rivi = ""; 10 while( getline( cin, rivi ) ) { cout << "Luettiin '" << rivi << "'" << endl; 15 return EXIT_SUCCESS; Kokeile esimerkkiohjelmaa proalla: /usr/local/kurssit/ohj1e/rivikerrallaan (Ohjelman saa lopetettua kirjottamalla ctrl+d)
283 OHJ-1101 Ohjelmointi 1e Tietovirtaongelmien havaitseminen Tietovirroilla operoitaessa voi törmätä seuraavan tyyppisiin ongelmatilanteisiin: 1. Yritetään tulostaa tietoa tulostusvirtaan ja epäonnistutaan (esim. täydelle levylle kirjoittaminen). 2. Yritetään lukea syötevirrasta tietoa, vaikka kaikki on jo luettu (esim. levytiedosto luettu loppuun). 3. Syötevirrasta yritetään lukea väärän tyyppistä tietoa (esim. odotetaan näppäimistöltä kokonaislukua, mutta käyttäjä naputteleekin kirjaimia). Ongelmien havaitseminen on kuitenkin helppoa, kun tietää seuraavat yksityiskohdat: 1. Kaikkien edellä esiteltyjen tietovirtoihin kohdistuvien operaatioiden tuloksena evaluoituu virta, johon operaatio kohdistui. 2. Ehtolausekkeena käytetyn virran arvoksi evaluoituu tosi vain, jos sille viimeksi tehty operaatio onnistui. Paitsi ei peek() ja parametriton get(). Myös alustus.
284 OHJ-1101 Ohjelmointi 1e Tämän pohjalta voidaan esittää seuraavat hyödylliset mallit erilaisten poikkeustilanteiden käsittelystä. Sidotaan syötevirta levytiedostoon ja luetaan se läpi rivi kerrallaan: ifstream tiedosto( "tuotteet.dat" ); if(! tiedosto ) { cerr << "Avaaminen epäonnistui!" << endl; return VIRHE; // Tai jotain... string rivi = ""; while ( getline( tiedosto, rivi ) ) { // Tässä luetulle riville tehdään jotain Vääräntyyppisen syötteen havaitseminen: cout << "Syötä luku: "; int luku = 0; if (!( cin >> luku ) ) { cerr << "Virheellinen syöte!" << endl; else { cout << "Luettiin luku " << luku << endl;
285 OHJ-1101 Ohjelmointi 1e Kuinka erottaa toisistaan virran loppuminen ja joku muu virhetilanne: while( getline( virta, rivi ) ) {... if(! virta.eof() ) { // Lukeminen epäonnistui jostain muusta // syystä kuin virran loppuminen... Virhe. Streamien funktio bool eof() palauttaa arvon tosi, jos virrassa ei ole enää mitään luettavaa.
286 OHJ-1101 Ohjelmointi 1e Esimerkki siitä, kuinka lukea läpi syötevirta, joka muodostuu riveistä: puhelinnumero 1 nimi 1 puhelinnumero 2 nimi 2... Seuraava koodinpätkä havainnollistaa asian: int numero = 0; string nimi = ""; while ( virta >> numero && getline( virta, nimi ) ) { // Käsitellään luettu numero ja nimi, // esimerkiksi talletetaan ne tietorakenteeseen tms. if(! virta.eof() ) { // Virheellinen rivi syötevirrassa, // tulostetaan virheilmoitus ja lopetetaan.
287 OHJ-1101 Ohjelmointi 1e istringstreamin avulla voi helposti jäsentää rivin syötettä yksiköihin, jotka on erotettu toisistaan tyhjillä merkeillä. Ensin luetaan rivi getline-funktiolla stringiin. Luetulla stringillä alustetaan istringstream, josta alkiot luetaan yksitellen vaikka >>-operaattorilla esim. vectoriin. cout << "Syötä rivillinen alkioita: "; string rivi = ""; getline( cin, rivi ); istringstream rivivirta( rivi ); vector< string > alkiot; string alkio = ""; while( rivivirta >> alkio ) { alkiot.push_back( alkio ); Kun alkiot ovat vector:issa, niitä on helppo käsitellä yksitellen: for( unsigned int i = 0; i < alkiot.size(); ++i ) { cout << alkiot.at( i ) << endl;
288 OHJ-1101 Ohjelmointi 1e stringstreamit ovat yleensä järkevin tapa, kun halutaan käsitellä syötettä siten, että varmasti otetaan huomioon koko rivi. Esimerkiksi kalvolla 283 esitetyn vääräntyyppisen syötteen havaitsemisen voi tehdä istringstreamin avulla siten, että varmistutaan myös siitä, että oikean syötteen perässä ei ole mitään "roskaa". cout << "Syötä luku: "; int luku = 0; while ( true ) { string rivi = ""; string loput = ""; getline( cin, rivi ); istringstream s( rivi ); if( ( s >> luku ) &&!( s >> loput ) ) { break; cout << "Virhe! Yritä uudelleen: ";
289 OHJ-1101 Ohjelmointi 1e Harjoitus Kirjoita funktio, joka muuttaa merkkijonomuodossa talletetun luvun int-tyyppiseksi luvuksi. Kirjoita funktio, joka muuttaa int-tyyppisen luvun merkkijonoksi.
290 OHJ-1101 Ohjelmointi 1e Standardivirrat cin, cout, cerr ja clog Virrat cin, cout, cerr ja clog ovat ilman muita alustuksia ohjelmoijan käytettävissä direktiivin #include <iostream> jälkeen. ciniä ja coutia käytetään tuttuun tapaan näppäimistösyötteen lukemiseen ja näytölle tulostamiseen. cerr toimii aivan samoin kuin cout, mutta sinne on tarkoitus tulostaa vain ohjelman virheilmoituksia. Kaikki muut tulosteet laitetaan coutiin. Eri virtoihin tulostetut asiat voidaan UNIXissa erotella eri paikkoihin >-merkillä. Virheilmoitukset eivät roskaa varsinaista tulostetta. clogiin voi tulostaa esim. ohjelman lokititetoja. Noudata näitä käytäntöjä myös omissa ohjelmissasi.
291 OHJ-1101 Ohjelmointi 1e Tietovirta funktion parametrina Tärkein asia joka pitää muistaa, jos haluaa antaa funktiolle parametrina tietovirran: muodollisen parametrin pitää olla viiteparametri. Tuo on järkeenkäypä vaatimus, sillä jos funktio operoi tietovirralla, niin virtahan muuttuu. Muutoksen on välityttävä myös todelliseen parametriin. Pääsääntöisesti todellisen parametrin pitää olla samaa tyyppiä kuin funktion muodollinen parametri, paitsi jos: muodollisen parametrin tyyppi istream& ostream& todellinen parametrin tyyppi saa olla myös ifstream tai istringstream ofstream tai ostringstream Käytännössä tuo mahdollistaa yleiskäyttöisempien funktioiden kirjoittamisen: sama funktio voi operoida erityyppisillä virroilla. Miten ja miksi tämä on mahdollista, siitä enemmän Olio-ohjelmoinnin peruskurssilla ja jatkokurssilla.
292 OHJ-1101 Ohjelmointi 1e Tarkastellaan pientä esimerkkifunktiota: int lueluku( istream& virta ) { int luku = 0; virta >> luku; if (!virta ) { return VIRHE; else { return luku; nyt funktiota voitaisiin kutsua eri tyyppisillä syötevirroilla eli lukea samalla funktiolla syötettä esimerkiksi näppäimistöltä: int numero = lueluku( cin ); tiedostosta: ifstream tietokanta( "syoteluvut.txt" ); int numero = lueluku( tietokanta ); tai merkkijonosta: string rivillinenlukuja = " "; istringstream lukujono( rivillinenlukuja ); int numero = lueluku( lukujono );
293 OHJ-1101 Ohjelmointi 1e Tentistä Tenttiin lukiessa ei kannata opetella ulkoa syntaksia tai muuta nippelitietoa, vaan keskittyä yleisiin periaatteisiin ja siihen, miksi asiat toimivat niin kuin ne toimivat. Todennäköisesti viisi kysymystä (voi olla kuusikin). Esim. seuraavantyylisiä kysymyksiä: termien selityksiä (usein 1p/kohta) pikkukysymyksiä (usein 2-3p/kysymys) koodaustehtävä (yleensä vähintään 6p) ainakin yksi laajempi kysymys jostakin aihepiiristä muunkin tyylisiä tehtäviä... Laajempi kysymys ei välttämättä ole essee.
294 OHJ-1101 Ohjelmointi 1e Ota vastauksissasi huomioon seuraavat: Esimerkki yksinään ei riitä vastaukseksi, anna yleinen selitys. Kysytäänkö C++:n tapaa toteuttaa jokin asia vai onko kyse ohjelmoinnista yleensä? Älä selitä kysyttyä termiä sen itsensä (tai sen taivutusmuotojen) avulla. Selitä yksikäsitteisesti: Jos vastauksesi voidaan tulkita väärin, se tulkitaan väärin. Essee tarkoittaa selkeää, jäsenneltyä ja täydellistä selitystä pyydetystä aiheesta. Kannattaa siis jäsentää ensin ja kirjoittaa vasta sitten. Täydellinen ei kuitenkaan tarkoita itsestäänselvyyksien jaarittelemista. Jos tehtävänannossa pyydetään vastaamaan ranskalaisilla viivoilla, tarkoitus ei ole kirjoittaa jokaiseen ranskalaiseen viivaan esseetä. Lue huolellisesti mitä kysytään ja vastaa siihen. Tylsintä on menettää pisteitä siksi, että on vastannut aiheen vierestä.
Java-kielen perusteet
Java-kielen perusteet Tunnus, varattu sana, kommentti Muuttuja, alkeistietotyyppi, merkkijono, literaalivakio, nimetty vakio Tiedon merkkipohjainen tulostaminen 1 Tunnus Java tunnus Java-kirjain Java-numero
Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.
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
Java-kielen perusteet
Java-kielen perusteet Tunnus, varattu sana, kommentti Muuttuja, alkeistietotyyppi, merkkijono, Vakio Tiedon merkkipohjainen tulostaminen Ohjelmointi (ict1tx006) Tunnus (5.3) Javan tunnus Java-kirjain Java-numero
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 21.1.2009 T-106.1208 Ohjelmoinnin perusteet Y 21.1.2009 1 / 32 Tyypeistä Monissa muissa ohjelmointikielissä (esim. Java ja C) muuttujat on määriteltävä ennen
Java-kielen perusteita
Java-kielen perusteita valintalauseet 1 Johdantoa kontrollirakenteisiin Tähän saakka ohjelmissa on ollut vain peräkkäisyyttä eli lauseet on suoritettu peräkkäin yksi kerrallaan Tarvitsemme myös valintaa
Kääntäjän virheilmoituksia
OHJ-1101 Ohjelmointi 1e 2008-09 1 Kääntäjän virheilmoituksia Kun progvh2 ohjelma käännetään antaa tutg++ seuraavat virheilmoitukset ja varoitukset: proffa> tutg++ progvh2.cc progvh2.cc:29:13: warning:
13. Loogiset operaatiot 13.1
13. Loogiset operaatiot 13.1 Sisällys Loogiset operaatiot AND, OR, XOR ja NOT. Operaatioiden ehdollisuus. Bittioperaatiot. Loogiset operaatiot ohjausrakenteissa. Loogiset operaatiot ja laskentajärjestys.
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 20.1.2010 T-106.1208 Ohjelmoinnin perusteet Y 20.1.2010 1 / 40 Arvon pyytäminen käyttäjältä Käyttäjän antaman arvon voi lukea raw_input-käskyllä. Käskyn sulkujen
Python-ohjelmointi Harjoitus 2
Python-ohjelmointi Harjoitus 2 TAVOITTEET Kerrataan tulostuskomento ja lukumuotoisen muuttujan muuttaminen merkkijonoksi. Opitaan jakojäännös eli modulus, vertailuoperaattorit, ehtorakenne jos, input-komento
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 2.3.2009 T-106.1208 Ohjelmoinnin perusteet Y 2.3.2009 1 / 28 Puhelinluettelo, koodi def lue_puhelinnumerot(): print "Anna lisattavat nimet ja numerot." print
Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)
Alkuarvot ja tyyppimuunnokset (1/5) Aiemmin olemme jo antaneet muuttujille alkuarvoja, esimerkiksi: int luku = 123; Alkuarvon on oltava muuttujan tietotyypin mukainen, esimerkiksi int-muuttujilla kokonaisluku,
13. Loogiset operaatiot 13.1
13. Loogiset operaatiot 13.1 Sisällys Loogiset operaatiot AND, OR, XOR ja NOT. Operaatioiden ehdollisuus. Bittioperaatiot. Loogiset operaatiot ohjausrakenteissa. Loogiset operaatiot ja laskentajärjestys.
VIII. Osa. Liitteet. Liitteet Suoritusjärjestys Varatut sanat Binääri- ja heksamuoto
Osa VIII Liitteet Liitteet A B C Suoritusjärjestys Varatut sanat Binääri- ja heksamuoto Osa VIII A. Liite Operaattoreiden suoritusjärjestys On tärkeää ymmärtää, että operaattoreilla on prioriteettinsa,
1. Algoritmi 1.1 Sisällys Algoritmin määritelmä. Aiheen pariin johdatteleva esimerkki. Muuttujat ja operaatiot (sijoitus, aritmetiikka ja vertailu). Algoritmista ohjelmaksi. 1.2 Algoritmin määritelmä Ohjelmointi
OHJ-1100 Ohjelmointi I
OHJ-1100 Ohjelmointi I lukuvuosi 2012 2013 Luentomoniste Ari Suntioinen [email protected] Sisällysluettelo Sisältö OHJ-1100 Ohjelmointi I Mitä on ohjelmointi?.......................................
815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset
815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 2 vastaukset Harjoituksen aiheena on BNF-merkinnän käyttö ja yhteys rekursiivisesti etenevään jäsentäjään. Tehtävä 1. Mitkä ilmaukset seuraava
etunimi, sukunimi ja opiskelijanumero ja näillä
Sisällys 1. Algoritmi Algoritmin määritelmä. Aiheen pariin johdatteleva esimerkki. ja operaatiot (sijoitus, aritmetiikka ja vertailu). Algoritmista ohjelmaksi. 1.1 1.2 Algoritmin määritelmä Ohjelmointi
Ohjelmointitaito (ict1td002, 12 op) Kevät 2008. 1. Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen raine.kauppinen@haaga-helia.
Ohjelmointitaito (ict1td002, 12 op) Kevät 2008 Raine Kauppinen [email protected] 1. Java-ohjelmoinnin alkeita Tietokoneohjelma Java-kieli ja Eclipse-ympäristö Java-ohjelma ja ohjelmaluokka
Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen
Metodit Metodien määrittely Metodin parametrit ja paluuarvo Metodien suorittaminen eli kutsuminen Metodien kuormittaminen 1 Mikä on metodi? Metodi on luokan sisällä oleva yhteenkuuluvien toimintojen kokonaisuus
Muuttujien roolit Kiintoarvo cin >> r;
Muuttujien roolit Muuttujilla on ohjelmissa eräitä tyypillisiä käyttötapoja, joita kutsutaan muuttujien rooleiksi. Esimerkiksi muuttuja, jonka arvoa ei muuteta enää kertaakaan muuttujan alustamisen jälkeen,
815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset
815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 3 vastaukset Harjoituksen aiheena ovat imperatiivisten kielten muuttujiin liittyvät kysymykset. Tehtävä 1. Määritä muuttujien max_num, lista,
Ehto- ja toistolauseet
Ehto- ja toistolauseet 1 Ehto- ja toistolauseet Uutena asiana opetellaan ohjelmointilauseet / rakenteet, jotka mahdollistavat: Päätösten tekemisen ohjelman suorituksen aikana (esim. kyllä/ei) Samoja lauseiden
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 19.1.2011 T-106.1208 Ohjelmoinnin perusteet Y 19.1.2011 1 / 39 Haluatko antaa palautetta luennoista? Ilmoittaudu mukaan lähettämällä ilmainen tekstiviesti Vast
12. Javan toistorakenteet 12.1
12. Javan toistorakenteet 12.1 Sisällys Yleistä toistorakenteista. Laskurimuuttujat. While-, do-while- ja for-lauseet. Laskuri- ja lippumuuttujat. Tyypillisiä ohjelmointivirheitä. Silmukan rajat asetettu
Tietotyypit ja operaattorit
Tietotyypit ja operaattorit Luennossa tarkastellaan yksinkertaisten tietotyyppien int, double ja char muunnoksia tyypistä toiseen sekä esitellään uusia operaatioita. Numeeriset tietotyypit ja muunnos Merkkitieto
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CSE-A1111 9.9.2015 CSE-A1111 Ohjelmoinnin peruskurssi Y1 9.9.2015 1 / 26 Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute.
Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:
1 (7) Tiedon lukeminen näppäimistöltä Scanner-luokan avulla Miten ohjelma saa käyttöönsä käyttäjän kirjoittamaa tekstiä? Järjestelmässä on olemassa ns. syöttöpuskuri näppäimistöä varten. Syöttöpuskuri
AS-0.1103 C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin
AS-0.1103 C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin Raimo Nikkilä Aalto-yliopiston sähkötekniikan korkeakoulu - Automaation tietotekniikan tutkimusryhmä 17. tammikuuta 2013
12. Javan toistorakenteet 12.1
12. Javan toistorakenteet 12.1 Sisällys Yleistä toistorakenteista. Laskurimuuttujat. While-, do-while- ja for-lauseet. Laskuri- ja lippumuuttujat. Tyypillisiä ohjelmointivirheitä. Silmukan rajat asetettu
Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti
C! Perusteet 19.1.2017 Palautteesta (1. kierros toistaiseksi) (Erittäin) helppoa Miksi vain puolet pisteistä? Vaikeinta oli ohjelmointiympäristön asennus ja käyttö Ei selvää että main funktion pitikin
Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.
Osoittimet Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan. Muistilohkon koko riippuu muuttujan tyypistä, eli kuinka suuria arvoja muuttujan
Python-ohjelmointi Harjoitus 5
Python-ohjelmointi Harjoitus 5 TAVOITTEET Kerrataan silmukkarakenteen käyttäminen. Kerrataan jos-ehtorakenteen käyttäminen. Opitaan if else- ja if elif else-ehtorakenteet. Matematiikan sisällöt Tehtävät
Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti
C! Perusteet 19.1.2017 Palautteesta (1. kierros toistaiseksi) Toistaiseksi helppoa Miksi vain puolet pisteistä? Vaikeinta oli ohjelmointiympäristön asennus ja käyttö Vaikeaa eroavuudet Pythonin ja C:n
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 28.2.2011 T-106.1208 Ohjelmoinnin perusteet Y 28.2.2011 1 / 46 Ohjelmointiprojektin vaiheet 1. Määrittely 2. Ohjelman suunnittelu (ohjelman rakenne ja ohjelman
3. Muuttujat ja operaatiot 3.1
3. Muuttujat ja operaatiot 3.1 Sisällys Imperatiivinen laskenta. Muuttujat. Nimi ja arvo. Muuttujan nimeäminen. Muuttujan tyyppi. Operaattorit. Operandit. Arvon sijoitus muuttujaan. Aritmeettiset operaattorit.
Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat ja operaatiot
3. Muuttujat ja operaatiot Sisällys Muuttujat. Nimi ja arvo. Algoritmin tila. Muuttujan nimeäminen. Muuttujan tyyppi. Muuttuja ja tietokone. Operaattorit. Operandit. Arvon sijoitus muuttujaan. Aritmeetiikka.
Sisällys. 17. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. for-lause lyhemmin
Sisällys 17. Ohjelmoinnin tekniikkaa for-lause lyhemmin. Vaihtoehtoisia merkintöjä aritmeettisille lauseille. Useiden muuttujien esittely ja alustaminen yhdellä lauseella. if-else-lause vaihtoehtoisesti
11. Javan toistorakenteet 11.1
11. Javan toistorakenteet 11.1 Sisällys Laskuri- ja lippumuuttujat. Sisäkkäiset silmukat. Tyypillisiä ohjelmointivirheitä: Silmukan rajat asetettu kierroksen verran väärin. Ikuinen silmukka. Silmukoinnin
Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit.
3. Muuttujat ja operaatiot Sisällys Imperatiivinen laskenta. Muuttujat. Nimi ja arvo. Muuttujan nimeäminen. Muuttujan tyyppi.. Operandit. Arvon sijoitus muuttujaan. Aritmeettiset operaattorit. Arvojen
811120P Diskreetit rakenteet
811120P Diskreetit rakenteet 2018-2019 1. Algoritmeista 1.1 Algoritmin käsite Algoritmi keskeinen laskennassa Määrittelee prosessin, joka suorittaa annetun tehtävän Esimerkiksi Nimien järjestäminen aakkosjärjestykseen
811120P Diskreetit rakenteet
811120P Diskreetit rakenteet 2016-2017 1. Algoritmeista 1.1 Algoritmin käsite Algoritmi keskeinen laskennassa Määrittelee prosessin, joka suorittaa annetun tehtävän Esimerkiksi Nimien järjestäminen aakkosjärjestykseen
Osoitin ja viittaus C++:ssa
Osoitin ja viittaus C++:ssa Osoitin yksinkertaiseen tietotyyppiin Osoitin on muuttuja, joka sisältää jonkin toisen samantyyppisen muuttujan osoitteen. Ohessa on esimerkkiohjelma, jossa määritellään kokonaislukumuuttuja
5/20: Algoritmirakenteita III
Ohjelmointi 1 / syksy 2007 5/20: Algoritmirakenteita III Paavo Nieminen [email protected] Tietotekniikan laitos Informaatioteknologian tiedekunta Jyväskylän yliopisto Ohjelmointi 1 / syksy 2007 p.1/17 Tämän
12 Mallit (Templates)
12 Mallit (Templates) Malli on määrittely, jota käyttämällä voidaan luoda samankaltaisten aliohjelmien ja luokkien perheitä. Malli on ohje kääntäjälle luoda geneerisestä tyyppiriippumattomasta ohjelmakoodista
Algoritmit. Ohjelman tekemisen hahmottamisessa käytetään
Ohjelmointi Ohjelmoinnissa koneelle annetaan tarkkoja käskyjä siitä, mitä koneen tulisi tehdä. Ohjelmointikieliä on olemassa useita satoja. Ohjelmoinnissa on oleellista asioiden hyvä suunnittelu etukäteen.
ITKP102 Ohjelmointi 1 (6 op)
ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 22. huhtikuuta 2016 Vastaa kaikkiin tehtäviin. Tee jokainen tehtävä erilliselle konseptiarkille! Kirjoittamasi luokat, funktiot ja aliohjelmat
16. Ohjelmoinnin tekniikkaa 16.1
16. Ohjelmoinnin tekniikkaa 16.1 Sisällys For-lause lyhemmin. Vaihtoehtoisia merkintöjä aritmeettisille lauseille. Useiden muuttujien esittely ja alustaminen yhdellä lauseella. If-else-lause vaihtoehtoisesti
ITKP102 Ohjelmointi 1 (6 op)
ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 7. huhtikuuta 2017 Vastaa kaikkiin tehtäviin. Tee jokainen tehtävä erilliselle konseptiarkille. Kirjoittamasi luokat, funktiot ja aliohjelmat
5. HelloWorld-ohjelma 5.1
5. HelloWorld-ohjelma 5.1 Sisällys Lähdekoodi. Lähdekoodin (osittainen) analyysi. Lähdekoodi tekstitiedostoon. Lähdekoodin kääntäminen tavukoodiksi. Tavukoodin suorittaminen. Virheiden korjaaminen 5.2
ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti
ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti Tentaattori: Antti-Jussi Lakanen 8. kesäkuuta 2018 Yleistä Tentti 1 meni pistekeskiarvon (11.2) perusteella välttävästi. Omasta tehtäväpaperista saa kopion
815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset
815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset Harjoituksen aiheena ovat aliohjelmat ja abstraktit tietotyypit sekä olio-ohjelmointi. Tehtävät tehdään C-, C++- ja Java-kielillä.
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 25.1.2010 T-106.1208 Ohjelmoinnin perusteet Y 25.1.2010 1 / 41 Valintakäsky if Tähänastiset ohjelmat ovat toimineen aina samalla tavalla. Usein ohjelman pitäisi
Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen
Ohjelmointitaito (ict1td002, 12 op) Kevät 2009 Raine Kauppinen [email protected] 1. Java-ohjelmoinnin alkeita Tietokoneohjelma Java-kieli ja Eclipse-kehitysympäristö Java-ohjelma ja luokka
Kerta 2. Kerta 2 Kerta 3 Kerta 4 Kerta 5. 1. Toteuta Pythonilla seuraava ohjelma:
Kerta 2 Kerta 3 Kerta 4 Kerta 5 Kerta 2 1. Toteuta Pythonilla seuraava ohjelma: 2. Tulosta Pythonilla seuraavat luvut allekkain a. 0 10 (eli, näyttää tältä: 0 1 2 3 4 5 6 7 8 9 10 b. 0 100 c. 50 100 3.
Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 15.3
15. Lohkot 15.1 Sisällys Tutustutaan lohkoihin. Muuttujien ja vakioiden näkyvyys sekä elinikä erityisesti operaation lohkossa. Nimikonfliktit. Muuttujat operaation alussa vai myöhemmin? 15.2 Lohkot Aaltosulkeet
11. Javan valintarakenteet 11.1
11. Javan valintarakenteet 11.1 Sisällys If- ja if-else-lauseet. Orpo else. Valintaa toisin: switch-lause. 11.2 If-lause Merkitään varatulla sanalla if. Kuvaa yksisuuntaisen päätöksen: rakenteen lauseet
Ohjelmointi 1 Taulukot ja merkkijonot
Ohjelmointi 1 Taulukot ja merkkijonot Jussi Pohjolainen TAMK Tieto- ja viestintäteknologia Johdanto taulukkoon Jos ohjelmassa käytössä ainoastaan perinteisiä (yksinkertaisia) muuttujia, ohjelmien teko
tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla
2.5. YDIN-HASKELL 19 tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla kirjaimilla. Jos Γ ja ovat tyyppilausekkeita, niin Γ on tyyppilauseke. Nuoli kirjoitetaan koneella
Sisällys. 15. Lohkot. Lohkot. Lohkot
Sisällys 15. Lohkot Tutustutaan lohkoihin. Muuttujien ja vakioiden näkyvyys sekä elinikä erityisesti operaation lohkossa. Nimikonfliktit. Muuttujat operaation alussa vai myöhemmin? 15.1 15.2 Lohkot Aaltosulkeet
Ohjelmoinnin perusteet, syksy 2006
Ohjelmoinnin perusteet, syksy 2006 Esimerkkivastaukset 1. harjoituksiin. Alkuperäiset esimerkkivastaukset laati Jari Suominen. Vastauksia muokkasi Jukka Stenlund. 1. Esitä seuraavan algoritmin tila jokaisen
Tutoriaaliläsnäoloista
Tutoriaaliläsnäoloista Tutoriaaliläsnäolokierroksella voi nyt täyttää anomuksen läsnäolon merkitsemisestä Esim. tagi ei toiminut, korvavaltimon leikkaus, yms. Hyväksyn näitä omaa harkintaa käyttäen Tarkoitus
Javan perusteet. Ohjelman tehtävät: tietojen syöttö, lukeminen prosessointi, halutun informaation tulostaminen tulostus tiedon varastointi
1 Javan perusteet Ohjelmointi IPO-malli Java lähdekoodista suoritettavaksi ohjelmaksi Vakio Muuttuja Miten Javalla näytetään tietoa käyttäjälle, miten Javalla luetaan käyttäjän antama syöte Miten Javalla
Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta
C++ - perusteet Java-osaajille luento 5/7: operaattoreiden ylikuormitus, oliotaulukko, parametrien oletusarvot, komentoriviparametrit, constant, inline, Operaattoreiden ylikuormitus Operaattoreiden kuormitus
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CS-A1111 14.9.2016 CS-A1111 Ohjelmoinnin peruskurssi Y1 14.9.2016 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,
System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);
Mikäli tehtävissä on jotain epäselvää, laita sähköpostia vastuuopettajalle ([email protected]). Muista nimetä muuttujat hyvin sekä kommentoida ja sisentää koodisi. Ohjelmointitehtävien osalta palautetaan
System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);
Kysy Karilta tai Kimmolta, jos tehtävissä on jotain epäselvää. Kerro WETOon liittyvät ongelmat suoraan Jormalle sähköpostitse ([email protected]). Muista nimetä muuttujat hyvin sekä kommentoida ja
Sisällys. 12. Javan toistorakenteet. Yleistä. Laskurimuuttujat
Sisällys 12. Javan toistorakenteet Ylstä toistorakentsta. Laskurimuuttujat. While-, do-while- ja for-lauseet. Laskuri- ja lippumuuttujat. Tyypillisiä ohjelmointivirhtä. Silmukan rajat asetettu kierroksen
ITKP102 Ohjelmointi 1 (6 op)
ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 20. huhtikuuta 2018 Vastaa kaikkiin tehtäviin. Tee kukin tehtävä omalle konseptiarkille. Noudata ohjelmointitehtävissä kurssin koodauskäytänteitä.
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CS-A1111 13.9.2017 CS-A1111 Ohjelmoinnin peruskurssi Y1 13.9.2017 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CSE-A1111 21.9.2015 CSE-A1111 Ohjelmoinnin peruskurssi Y1 21.9.2015 1 / 25 Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute.
1. luento. Ohjelmointi (C) T0004 Syksy 2003. 1. luento. 1. luento. 1. luento. 1. luento. kurssin sisältö ja tavoitteet työmuodot.
EVTEK Teknillinen ammattikorkeakoulu Ohjelmointi (C) T0004 Syksy 2003 Olli Hämäläinen kurssin sisältö ja tavoitteet työmuodot luennot 1-2/2003 laboratorioharjoitukset 1-2/2003 kotitehtävät, laboratoriokerrat
5. HelloWorld-ohjelma 5.1
5. HelloWorld-ohjelma 5.1 Sisällys Lähdekoodi. Lähdekoodin (osittainen) analyysi. Lähdekoodi tekstitiedostoon. Lähdekoodin kääntäminen tavukoodiksi. Tavukoodin suorittaminen. Virheiden korjaaminen 5.2
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CSE-A1111 16.9.2015 CSE-A1111 Ohjelmoinnin peruskurssi Y1 16.9.2015 1 / 26 Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute.
2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)
2. Lisää Java-ohjelmoinnin alkeita Muuttuja ja viittausmuuttuja Vakio ja literaalivakio Sijoituslause Syötteen lukeminen ja Scanner-luokka 1 Muuttuja ja viittausmuuttuja (1/4) Edellä mainittiin, että String-tietotyyppi
Ohjausrakenteet. Valinta:
Ohjausrakenteet Luento antaa yleiskuvan siitä kuinka ohjelmassa suorittaan vaihtoehtoisia tehtäviä valintarakenteiden avulla ja kuinka samanlaisia ohjelma-askeleita toistetaan toistorakenteiden avulla
C++ rautaisannos. Kolme tapaa sanoa, että tulostukseen käytetään standardikirjaston iostreamosassa määriteltyä, nimiavaruuden std oliota cout:
C++ rautaisannos Kolme tapaa sanoa, että tulostukseen käytetään standardikirjaston iostreamosassa määriteltyä, nimiavaruuden std oliota cout: # include #include main ( ) main (
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CSE-A1111 21.9.2016 CSE-A1111 Ohjelmoinnin peruskurssi Y1 21.9.2016 1 / 22 Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute.
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 1.4.2009 T-106.1208 Ohjelmoinnin perusteet Y 1.4.2009 1 / 56 Tentti Ensimmäinen tenttimahdollisuus on pe 8.5. klo 13:00 17:00 päärakennuksessa. Tämän jälkeen
Harjoitus 3 (viikko 39)
Mikäli tehtävissä on jotain epäselvää, laita sähköpostia vastuuopettajalle ([email protected]). Muista nimetä muuttujat hyvin sekä kommentoida ja sisentää koodisi. Vältä liian pitkiä rivejä. Ohjelmointitehtävien
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CS-A1111 26.9.2018 CS-A1111 Ohjelmoinnin peruskurssi Y1 26.9.2018 1 / 21 Oppimistavoitteet: tämän luennon jälkeen Osaat kirjoittaa for-käskyn avulla ohjelman, joka toistaa haluttua
Ohjelmointiharjoituksia Arduino-ympäristössä
Ohjelmointiharjoituksia Arduino-ympäristössä Yleistä Arduino-sovelluksen rakenne Syntaksi ja käytännöt Esimerkki ohjelman rakenteesta Muuttujat ja tietotyypit Tietotyypit Esimerkkejä tietotyypeistä Ehtolauseet
IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit
IDL - proseduurit 25. huhtikuuta 2017 Viimeksi käsiteltiin IDL:n interaktiivista käyttöä, mutta tämä on hyvin kömpelöä monimutkaisempia asioita tehtäessä. IDL:llä on mahdollista tehdä ns. proseduuri-tiedostoja,
Johdatus Ohjelmointiin
Johdatus Ohjelmointiin Syksy 2006 Viikko 2 13.9. - 14.9. Tällä viikolla käsiteltävät asiat Peruskäsitteitä Kiintoarvot Tiedon tulostus Yksinkertaiset laskutoimitukset Muuttujat Tiedon syöttäminen Hyvin
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CS-A1111 12.9.2018 CS-A1111 Ohjelmoinnin peruskurssi Y1 12.9.2018 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CS-A1111 11.9.2019 CS-A1111 Ohjelmoinnin peruskurssi Y1 11.9.2019 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,
ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014
18. syyskuuta 2014 IDL - proseduurit Viimeksi käsiteltiin IDL:n interaktiivista käyttöä, mutta tämä on hyvin kömpelöä monimutkaisempia asioita tehtäessä. IDL:llä on mahdollista tehdä ns. proseduuri-tiedostoja,
Zeon PDF Driver Trial
Matlab-harjoitus 2: Kuvaajien piirto, skriptit ja funktiot. Matlabohjelmoinnin perusteita Numeerinen integrointi trapezoidaalimenetelmällä voidaan tehdä komennolla trapz. Esimerkki: Vaimenevan eksponentiaalin
Sisällys. 3. Pseudokoodi. Johdanto. Johdanto. Johdanto ja esimerkki. Pseudokoodi lauseina. Kommentointi ja sisentäminen.
Sisällys 3. Pseudokoodi Johdanto ja esimerkki. Pseudokoodi lauseina. Kommentointi ja sisentäminen. Ohjausrakenteet: Valinta if- ja if--rakenteilla. oisto while-, do-while- ja for-rakenteilla. 3.1 3.2 Johdanto
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 1.3.2010 T-106.1208 Ohjelmoinnin perusteet Y 1.3.2010 1 / 36 Monikko Monikko (engl. tuple) muistuttaa listaa, mutta monikon sisältöä ei voi muuttaa sen jälkeen,
15. Ohjelmoinnin tekniikkaa 15.1
15. Ohjelmoinnin tekniikkaa 15.1 Sisällys For-each-rakenne. Lueteltu tyyppi enum. Override-annotaatio. Geneerinen ohjelmointi. 15.2 For-each-rakenne For-rakenteen variaatio taulukoiden ja muiden kokoelmien
Harjoitus 5. Esimerkki ohjelman toiminnasta: Lausekielinen ohjelmointi I Kesä 2018 Avoin yliopisto 1 / 5
Kysy Karilta tai Kimmolta, jos tehtävissä on jotain epäselvää. Kerro WETOon liittyvät tekniset ongelmat suoraan Jormalle sähköpostitse ([email protected]). Muista nimetä muuttujat hyvin sekä kommentoida
Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 16.3
16. Lohkot 16.1 Sisällys Tutustutaan lohkoihin. Muuttujien ja vakioiden näkyvyys sekä elinikä erityisesti operaation lohkossa. Nimikonfliktit. Muuttujat operaation alussa vai myöhemmin? 16.2 Lohkot Kaarisulut
4. Lausekielinen ohjelmointi 4.1
4. Lausekielinen ohjelmointi 4.1 Sisällys Konekieli, symbolinen konekieli ja lausekieli. Hyvä ohjelmointitapa. Lausekielestä konekieleksi: - Lähdekoodi, tekstitiedosto ja tekstieditorit. - Kääntäminen
Palautetta viime luennosta
Palautetta viime luennosta Kuka saa ja kenen täytyy suorittaa 5op kokonaisuus? Sivuaineopiskelijat suorittavat jos heidän sivuainekokonaisuuteen on merkitty niin Kokonaisuuksia on useita eri tiedekunnittain,
C-ohjelmoinnin peruskurssi. Pasi Sarolahti
C! C-ohjelmoinnin peruskurssi Pasi Sarolahti Mitä haluan oppia C-kurssilla? ja miksi? Tutustu lähimpään naapuriin Keskustelkaa miksi halusitte / jouduitte tulemaan kurssille 3 minuuttia è kootaan vastauksia
C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys
Loogisia operaatioita - esimerkkejä Tänään on lämmin päivä ja perjantai Eilen satoi ja oli keskiviikko tai tänään on tiistai. On perjantai ja kello on yli 13 Ei ole tiistai tai ei sada. Ei pidä paikkaansa,
Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä 12.1 12.2 12.3 12.4
Sisällys 12. Näppäimistöltä lukeminen Arvojen lukeminen näppäimistöltä yleisesti. Arvojen lukeminen näppäimistöltä Java-kielessä.. Luetun arvon tarkistaminen. Tietovirrat ja ohjausmerkit. Scanner-luokka.
