Lisää perustietotyypeistä
|
|
|
- Hilja Hyttinen
- 10 vuotta sitten
- Katselukertoja:
Transkriptio
1 Perustietotyypit ja laskutoimitukset 3 Lisää perustietotyypeistä Tässä luvussa käsittelemme lisää jo edellisessä luvussa käsittelemiämme perustietotyyppejä. Näemme, kuinka eri tyyppiset muuttujat vaikuttavat toisiinsa monimutkaisemmissa tilanteissa. Käsittelemme myöskin joitakin uusia C++:n ominaisuuksia sekä joitakin tapoja, joilla näitä ominaisuuksia käytetään. Tässä luvussa käsittelemme: Kuinka lasketaan lausekkeet, joissa on useita eri tietotyyppejä Miten arvo muunnetaan perustietotyypistä toiseksi perustietotyypiksi Mitä ovat bittioperaatiot ja kuinka niitä käytetään Kuinka määritellään uusi tyyppi, jonka arvot on rajoitettu tietylle arvovälille Kuinka olemassa oleville tietotyypeille annetaan toinen nimi Kuinka kauan muuttuja säilyy muistissa ja mikä sen määrää Mikä on muuttujan näkyvyysalue ja mikä sen määrää Eri tietotyyppejä sisältävät lausekkeet Kuten jo saatatkin tietää, tietokoneesi pystyy suorittamaan laskutoimituksia vain kahden saman tyyppisen arvon välillä. Se voi laskea yhteen kaksi kokonaislukua tai kaksi samanlaista liukulukua, mutta se ei pysty suoraan lisäämään kokonaislukuun liukulukua. Esimerkiksi lauseketta se ei pysty laskemaan tällaisenaan. Ainoa tapa, jolla tämä laskutoimitus voidaan suorittaa, on muuntaa toinen arvoista saman tyyppiseksi kuin toinenkin on - tyypillisesti kokonaisluku muunnetaan vastaavaksi liukuluvuksi, joten lauseke laskettaisiin kuten Tämä pätee kaikkiin C++:n lausekkeisiin, joissa on useita eri tyyppejä. Jokaisen binäärioperaation kummankin operandin tulee olla samaa tyyppiä; jos ne ovat eri tyyppiä, toinen pitää muuntaa toista vastaavaksi. Katsotaanpa seuraavia lauseita: int arvo1 = 10; long arvo2 = 25L; float arvo3 = 30.0f; double tulos = arvo1 + arvo2 + arvo3; 71
2 C++ Ohjelmoijan käsikirja Arvo tulos lasketaan kolmen erityyppisen muuttujan summana. Jokaisen laskutoimituksen kohdalla toinen operandeista muunnetaan toista operandia vastaavaksi ennen kuin laskutoimitus voidaan suorittaa. Tehtävä muunnos ja mikä operandi muunnetaan määrätään tiettyjen sääntöjen mukaan. Näitä sääntöjä tarkistetaan peräkkäin, kunnes löytyy sopiva kyseiseen tilanteeseen. Edellä oleva lause suoritetaan itse asiassa seuraavissa vaiheissa: arvo1 + arvo2 lasketaan muuntamalla arvo arvo1 long-tyyppiseksi ennen laskutoimitusta. Tuloksena on myös long-tyyppinen arvo, eli arvo lasketaan 10L + 25L = 35L. Seuraava operaatio on 35L + arvo3. Edellisen laskutoimituksen tulos 35L muunnetaan liukuluvuksi ennen kuin se lasketaan yhteen muuttujan arvo3 kanssa. Tulos on tyyppiä float, eli arvo lasketaan 35.0f f = 65.0f. Lopuksi tulos muunnetaan double-tyyppiseksi ja talletetaan muuttujaan tulos. Eri tyyppejä sisältävien lausekkeiden muunnossääntöjä käytetään vain, jos binäärisen operaattorin operandit ovat erit. Nämä säännöt on seuraavassa lueteltu siinä järjestyksessä kuin ne tarkistetaan: 1. Jos toinen operandeista on tyyppiä long double, toinenkin muunnetaan long double -tyyppiseksi. 2. Jos toinen operandeista on tyyppiä double, toinenkin muunnetaan double -tyyppiseksi. 3. Jos toinen operandeista on tyyppiä float, toinenkin muunnetaan float-tyyppiseksi. 4. Operandi, joka on tyyppiä char, signed char, unsigned char, short tai unsigned short muunnetaan int-tyyppiseksi, jos tyyppi int pystyy esittämään kaikki operandin alkuperäisen tyypin arvot. Muutoin operandi muunnetaan unsigned int-tyyppiseksi. 5. Lueteltu tietotyyppi muunnetaan ensin tyypiksi int, unsigned int, long tai unsigned long sen mukaan mikä näistä tyypeistä pystyy esittämään kaikki luetellut arvot. 6. Jos toinen operandeista on tyyppiä unsigned long, toinenkin muunnetaan unsigned long-tyyppiseksi. 7. Jos toinen operandi on tyyppiä long ja toinen tyyppiä unsigned int, unsigned int - tyyppinen muunnetaan long-tyyppiseksi, jos tyyppi long pystyy esittämään kaikki unsigned int-tyypin arvot. Muutoin molemmat operandit muunnetaan unsigned long -tyyppisiksi. 8. Jos toinen operandeista on tyyppiä long, toinenkin muunnetaan long-tyyppiseksi. 72 Et ole vielä tavannut lueteltuja tyyppejä, mutta käsittelemme niitä hiukan myöhemmin tässä luvussa. Ne esiintyvät tässä jo nyt, jotta säännöt olisivat täydelliset. Tämä kaikki näyttää varsin monimutkaiselta, mutta se ei ole sitä. Osa monimutkaisuudesta tulee siitä, että kokonaislukutyyppien arvovälit riippuvat laitteistoympäristöstä ja sääntöjen tulee ottaa tämä huomioon. Kääntäjä tarkistaa säännöt ylläolevassa järjestyksessä, kunnes löytyy käyttökelpoinen sääntö. Jos operandit ovat samaa tyyppiä säännön soveltamisen jälkeen, itse operaatio suoritetaan. Jos näin ei ole, etsitään toinen sääntö. Perusidea on varsin yksinkertainen. Jos kaksi operandia on eri, pienemmän arvovälin omaavan tyypin operandi muunnetaan. Muodolliset säännöt voidaankin yksinkertaistaa:
3 Perustietotyypit ja laskutoimitukset 1. Jos operaatiossa on kaksi eri liukulukutyyppiä, pienemmän tarkkuuden operandi muunnetaan. 2. Jos operaatiossa on kokonaisluku ja liukuluku, kokonaisluku muunnetaan liukuluvuksi. 3. Jos operaatiossa on erilaisia kokonaislukutyyppejä, pienimmän arvovälin operandi muunnetaan. 4. Jos operaatiossa on lueteltuja tyyppejä, ne muunnetaan sopiviksi kokonaislukutyypeiksi. Termillä muunto tarkoitetaan automaattista muuntoa tyypistä toiseksi. Voit myös eksplisiittisesti muuntaa tyypin toiseksi. Tähän palaamme hetken päästä. Sijoitukset ja eri tietotyypit Jos sijoituslausekkeen oikealla puolella olevan lausekkeen tyyppi on eri kuin vasemmalla puolella olevan muuttujan, lausekkeen laskettu arvo muunnetaan automaattisesti muuttujaa vastaavaksi tyypiksi ennen sijoitusta. Monissa tilanteissa voit menettää tässä kohtaa tietoa. Oletetaan, että olemme määritelleet liukuluvun seuraavasti: double juuri = 1.732; Jos nyt kirjoitamme lauseen: int arvo = juuri; Muuttujan juuri arvon muuntaminen int-tyyppiseksi saa aikaan sen, että muuttujaan arvo sijoitetaan arvo 1. Tyyppiä int oleva muuttuja pystyy tallettamaan vain kokonaisia lukuja, joten muuttujaan juuri talletetun arvon desimaaliosaa ei huomioida muunnoksessa. Voit jopa hävittää tietoa erityyppisten kokonaislukujen sijoituksissa: long laskuri = 60000; short arvo = laskuri; Jos tyyppi short on kahden tavun kokoinen ja long nelitavuinen, muuttujan laskuri arvo ei mahdu muuttujaan arvo ja tuloksena on väärä arvo. Monet kääntäjät huomaavat tällaiset tilanteet ja näyttävät varoituksen, mutta älä luota, että näin tapahtuisi aina. Välttääksesi tämäntyyppiset ongelmat, vältä sijoittamasta erityyppistä tietoa toiseen, pienemmän arvovälin muuttujaan. Jos et voi välttää tällaista sijoitusta, voit määritellä muunnoksen eksplisiittisesti, jolloin samalla ilmoitat, että todella haluat näin tehdä. Eksplisiittiset tyypinmuunnokset Kääntäjä huolehtii automaattisesti tyypinmuunnoksista perustietotyyppien kohdalla, mutta voit myös eksplisiittisen tyypinmuunnoksen avulla pakottaa muunnoksen tietotyypistä toiseen. Kun haluat muuntaa lausekkeen arvon toiseksi tyypiksi, kirjoitat tyypinmuunnoksen muodossa: static_cast<tyyppi, joksi muunnetaan>(lauseke) 73
4 C++ Ohjelmoijan käsikirja Avainsana static_cast kertoo, että tyypinmuunnos tarkastetaan staattisesti - eli ohjelman käännösvaiheessa. Myöhemmin, kun käsittelemme luokkia, tapaamme dynaamisia tyypinmuunnoksia, jossa muunnos tarkastetaan dynaamisesti - eli ohjelman suorituksen aikana. Eksplisiittisessä tyypinmuunnoksessa lausekkeen lauseke arvo muunnetaan kulmasulkeiden välissä olevan tyypin mukaiseksi. Lauseke voi olla hyvinkin monimutkainen. Seuraavassa käytetään eksplisiittistä tyypinmuunnosta static_cast<>(): double arvo1 = 10.5; double arvo2 = 15.5; int kokonaisluku = static_cast<int>(arvo1) + static_cast<int>(arvo2); Muuttujan kokonaisluku alkuarvo lasketaan muuttujien arvo1 ja arvo2 kokonaislukuosien summana, joten ne muunnetaan eksplisiittisesti int-tyyppisiksi. Muuttujan kokonaisluku alkuarvoksi tulee täten arvo 25. Tyypinmuunnokset eivät vaikuta muuttujien arvo1 ja arvo2 arvoihin, ne säilyvät arvoissa 10.5 ja Tyypinmuunnosten tuottamat arvot 10 ja 15 talletetaan väliaikaisesti laskutoimitusta varten, minkä jälkeen ne hävitetään. Vaikka molemmissa tyypinmuunnoksissa menetetään tietoa, kääntäjä olettaa aina, että eksplisiittistä tyypinmuunnosta käyttäessäsi tiedät, mitä olet tekemässä. Aikaisemmassa esimerkissä, jossa käsittelimme eri tyyppien sijoitusta, voit eksplisiittisen tyypinmuunnoksen avulla tehdä selväksi, että tiedät tyypinmuunnoksen tarpeellisuuden: int arvo = static_cast<int>(juuri); Yleisesti ottaen, eksplisiittisten tyypinmuunnosten tarve on melko pieni, varsinkin perustietotyyppien kohdalla. Jos joudut käyttämään ohjelmassasi runsaasti eksplisiittisiä tyypinmuunnoksia, on se yleensä merkki siitä, että sinun tulisi valita muuttujille sopivammat tyypit. On kuitenkin olemassa tilanteita, joissa näin täytyy tehdä, joten katsotaan esimerkkiä tällaisesta tilanteesta. Kokeile itse - Eksplisiittinen tyypinmuunnos Oletetaan, että meidän tarvitsee muuntaa pituus jaardeina (desimaaliosalla) jaardeiksi, jaloiksi ja tuumiksi (kokonaislukuina). Seuraavassa on esimerkki tästä: // Esimerkki Eksplisiittinen tyypinmuunnos #include <iostream> using namespace std; int main() { const long jalkoja_jaardissa = 3; const long tuumia_jalassa = 12; double jaardeja = 0.0; long jaardit = 0; long jalat = 0; long tuumat = 0; // Pituus jaardeina (desimaaliosineen) // Kokonaiset jaardit // Kokonaiset jalat // Kokonaiset tuumat 74
5 } cout << "Syötä pituus jaardeina (desimaaliosineen): "; cin >> jaardeja; Perustietotyypit ja laskutoimitukset // Lasketaan pituus jaardeina, jalkoina ja tuumina jaardit = static_cast<long>(jaardeja); jalat = static_cast<long>((jaardeja - jaardit) * jalkoja_jaardissa); tuumat = static_cast<long>(jaardeja * jalkoja_jaardissa * tuumia_jalassa) % tuumia_jalassa; << jaardeja << " jaardia on muunnettu: " << jaardit << " jaardia " << jalat << " jalkaa " << tuumat << " tuumaa."; ; return 0; Ohjelman tyypillinen tulostus on: Syötä pituus jaardeina (desimaaliosineen): jaardia on muunnettu: 2 jaardia 2 jalkaa 3 tuumaa. Kuinka se toimii Ensimmäisillä kahdella funktion main() lauseella esitellään kaksi muunnosarvoa: const long jalkoja_jaardissa = 3; const long tuumia_jalassa = 12; Esittelemme nämä muuttujat vakioiksi const-määreellä, koska emme halua niitä muutettavan ohjelmassa ja tyyppinä käytämme long-tyyppiä yhteensopivuuden takia. Vaikka tyyppi short olisikin ollut riittävä näille arvoille, sen käyttö olisi itse asiassa kasvattanut (eikä pienentänyt) ohjelman kokoa. Tämä siitä syystä, että tällöin ohjelmassa tulisi käyttää automaattista tyypinmuunnosta. Seuraavat neljä esittelyä määrittelevät laskennassa tarvittavat muuttujat: double jaardeja = 0.0; long jaardit = 0; long jalat = 0; long tuumat = 0; // Pituus jaardeina (desimaaliosineen) // Kokonaiset jaardit // Kokonaiset jalat // Kokonaiset tuumat Seuraavaksi pyydämme käyttäjältä syötettä ja luemme syötteen näppäimistöltä: cout << "Syötä pituus jaardeina (desimaaliosineen): "; cin >> jaardeja; Seuraava lause laskee jaardien määrän kokonaisina eksplisiittisen tyypinmuunnoksen avulla: jaardit = static_cast<long>(jaardeja); 75
6 C++ Ohjelmoijan käsikirja Tyypinmuunnos muuntaa tyypiksi long ja hävittää desimaaliosat ja tallettaa kokonaislukutuloksen muuttujaan jaardit. Jos et käyttäisi eksplisiittistä tyypinmuunnosta tässä kohdassa, jotkut kääntäjät kääntäisivät ohjelman ilman varoitusta lisätystä automaattisesta tyypinmuunnoksesta. Tässä muunnoksessa on kuitenkin suuri mahdollisuus tiedon häviämiselle ja tällaisissa tapauksissa sinun tulee aina käyttää eksplisiittistä tyypinmuunnosta kertomaan, että todella haluat niin tehdä. Jos jättäisit sen pois, ei olisi selvää, että olet ymmärtänyt muunnoksen tarpeellisuuden ja mahdollisen tiedon häviämisen. Kokonaisten jalkojen määrän laskemme lauseella: jalat = static_cast<long>((jaardeja - jaardit) * jalkoja_jaardissa); Haluamme niiden kokonaisten jalkojen määrän, jotka eivät ole kokonaisissa jaardeissa, joten vähennämme muuttujan jaardeja arvosta jaardit. Kääntäjä huolehtii muuttujan jaardit automaattisesta muunnoksesta double-tyyppiseksi ja vähennyslaskun tulos on myös tyyppiä long. Muuttujan jalkoja_jaardissa arvo muunnetaan sitten automaattisesti double-tyyppiseksi kertolaskua varten. Lopuksi tulos muunnetaan eksplisiittisen tyypinmuunnoksen avulla tyypistä double tyyppiin long. Laskennan viimeisenä vaiheena on laskea jäljellä oleva pituus kokonaisissa tuumissa: tuumat = static_cast<long>(jaardeja * jalkoja_jaardissa * tuumia_jalassa) % tuumia_jalassa; Tämä tapahtuu laskemalla koko alkuperäinen pituus tuumina, muuntamalla se eksplisiittisesti long-tyyppiseksi ja jakamalla tulos tuumien määrällä jalassa. Lopuksi tulostamme tulokset: << jaardeja << " jaardia on muunnettu: " << jaardit << " jaardia " << jalat << " jalkaa " << tuumat << " tuumaa."; Vanhantyyliset tyypinmuunnokset Ennen kuin eksplisiittinen tyypinmuunnos static_cast<>() (sekä muut vastaavat: const_cast<>(), dynamic_cast<>() ja reinterpret<>(), joita käsittelemme myöhemmin) esiteltiin C++:ssa, tyypin muuntaminen eksplisiittisesti toiseksi kirjoitettiin seuraavasti: (tyyppi, joksi muunnetaan)lauseke Lausekkeen tulos muunnetaan tässä sulkeiden sisällä olevaksi tyypiksi. Esimerkiksi edellisen esimerkkimme tuumien laskenta tapahtuisi seuraavasti: tuumat = (long)(jaardeja * jalkoja_jaardissa * tuumia_jalassa) % tuumia_jalassa; 76
7 Perustietotyypit ja laskutoimitukset Itse asiassa käytössä on neljä erilaista eksplisiittistä tyypinmuunnosta ja vanhantyylinen kattaa ne kaikki. Tästä syystä ohjelma, jossa käytetään vanhantyylistä tyypinmuunnosta, on herkempi virheille - aina ei ole selvää, mitä tarkoitetaan, eikä tulos ole aina haluttu. Vanhantyylistä tyypinmuunnosta käytetään kuitenkin vielä runsaasti (se on yhä osa kieltä), mutta suosittelemme uusien käyttämistä koodissasi. Tyyppien tiedot Tyypin tarvitsemaa muistimäärää tavuissa ei ole määritelty C++:n standardissa; kääntäjä määrää sen. Joskus saattaa olla hyödyllistä saada selville tietyn tyypin tarvitsema muistimäärä. Tämän voit saada selville kääntäjäsi ohjekirjoista, mutta saat sen selville myös sizeof() -operaattorilla. sizeof() on unaarinen operaattori, joten se tarvitsee vain yhden operandin. Se palauttaa yhden kokonaislukuarvon, joka on halutun muuttujan tai tyypin viemä muistimäärä. Palautettava arvo on itse asiassa tyypin char kerrannaisina, mutta koska tyypin char koko on 1 tavu, palautettava arvo on operandin tarvitsema tila tavuina. Jos haluat saada selville tyypin tyyppi viemän muistimäärän, käytät lauseketta sizeof(tyyppi). Näin ollen tyypin int koon saat selville lauseella: << Tyypin int koko on << sizeof(int); // Tulostetaan tyypin int koko Lauseke sizeof(int) palauttaa kaiken int-tyyppiseksi esitellyn koon. Tällä tavalla saat selville minkä tahansa tietotyypin koon. Tyypin long double koon saat selville lauseella: << Tyypin long double koko on << sizeof(long double); // Tulostetaan tyypin long double koko Voit käyttää sizeof() -operaattoria tietyn muuttujan tai jopa lausekkeenkin kanssa. Tällaisessa tapauksessa lausekkeen ei tarvitse olla sulkeiden sisällä, mutta voit käyttää niitä halutessasi. Seuraavassa tulostetaan muuttujan numero viemä muistimäärä: long numero = ; << Muuttujan numero koko on << sizeof numero; // Tulostetaan muuttujan numero koko Voit käsitellä sizeof() -operaattorin palauttamaa arvoa kokonaislukuna, mutta itse asiassa se palauttaa size_t-tyyppisen arvon. Tämä tyyppi on määritelty standardiotsikkotiedostossa cstddef tavallisesti unsigned int -tyyppiseksi. Kysytkin varmasti mielessäsi: Miksi uusi tyypin nimi tässä kohdassa? Miksei voida käyttää suoraan tyyppiä unsigned int? Tämä johtuu siitä, että halutaan mahdollistaa joustavuus. Operaattori sizeof() palauttaa aina size_t-tyyppisen arvon, jonka kääntäjäsi voi hyvinkin olla määritellyt unsigned int -tyyppiseksi, mutta näin ei välttämättä tarvitse olla. C++ -kääntäjän tekijöille voisi mahdollisesti olla 77
8 C++ Ohjelmoijan käsikirja järkevämpää määritellä tyyppi size_t jonkin muun tyyppiseksi, ja he voisivat myös tehdä niin. Se ei vaikuttaisi sinun koodiisi, koska oletat tuloksen olevan vain tyyppiä size_t. Käsittelemme synonyymin määrittelyä olemassa olevalle tyypille myöhemmin tässä luvussa. Kokeile itse - Tietotyyppien koko Seuraavassa esimerkissä tulostetaan kaikkien jo käsittelemiemme tyyppien koot: // Esimerkki Tietotyyppien koko #include <iostream> using namespace std; int main() { // Tulostetaan kokonaislukutyyppien koot << "Tyypin char koko on " << sizeof(char); << "Tyypin short koko on " << sizeof(short); << "Tyypin int koko on " << sizeof(int); << "Tyypin long koko on " << sizeof(long); } // Tulostetaan liukulukutyyppien koot << "Tyypin float koko on " << sizeof(float); << "Tyypin double koko on " << sizeof(double); << "Tyypin long double koko on " << sizeof(long double); ; return 0; Ohjelman tyypillinen tulostus on: Tyypin char koko on 1 Tyypin short koko on 2 Tyypin int koko on 4 Tyypin long koko on 4 Tyypin float koko on 4 78
9 Perustietotyypit ja laskutoimitukset Tyypin double koko on 8 Tyypin long double koko on 8 Voisit yhtä hyvin tässä esimerkissä käyttää sizeof() -operaattoria muuttujien ja lausekkeiden kanssa. Tietotyyppien raja-arvot Joskus saattaa olla tilanne, että haluat tietää tietystä tietotyypistä muutakin kuin pelkän koon. Saatat esimerkiksi haluta tietää tyypin arvojen ylä- ja alarajan. Standardi otsikkotiedosto limits sisältää tällaisen tiedon kaikista perustietotyypeistä. Tietoja voidaan käyttää kullekin tyypille määritellyn luokan avulla ja koska emme ole vielä käsitelleet luokkia, tämän toiminta saattaa olla hieman epäselvä tässä ja nyt. Näytämme kuitenkin, miten saat tämän tiedon, mutta emme käsittele yksityiskohtia ennen kuin käsittelemme luokkia luvussa 12. Katsotaan esimerkkiä. Tulostaaksesi double-tyyppiseen muuttujaan talletettavan suurimman mahdollisen arvon, voit kirjoittaa: << Tyypin double maksimiarvo on << numeric_limits<double>::max(); Lauseke numeric_limits<double>::max() tuottaa haluamamme tuloksen. Kirjoittamalla kulmasulkeiden sisään muita tietotyyppejä, saat selville niiden maksimiarvot. Voit myöskin korvata max():n min():llä, jolloin saat minimiarvon. Saat selville myös monia muita tietoja eri tyypeistä. Esimerkiksi binääristen numeroiden lukumäärän saat selville lausekkeella: numeric_limits<tyypin_nimi>::digits Tässä kirjoitat haluamasi tyypin tyypin_nimi kulmasulkeiden sisään. Liukulukujen kohdalla tuloksena on binääristen numeroiden lukumäärä mantissassa. Etumerkillisten kokonaislukutyyppien kohdalla tuloksena on binääristen numeroiden lukumäärä merkkibitti poislukien. Havainnollistamme edellä mainittuja asioita seuraavassa esimerkissä, joka tulostaa numeeristen tietotyyppien maksimi- ja minimiarvot. Kokeile itse - Maksimi- ja minimiarvot Seuraavassa on ohjelman koodi: // Esimerkki Maksimi- ja minimiarvot #include <limits> #include <iostream> using namespace std; 79
10 C++ Ohjelmoijan käsikirja int main() { << "Tyypin short arvoväli on " << numeric_limits<short>::min() << " - " << numeric_limits<short>::max(); << "Tyypin int arvoväli on " << numeric_limits<int>::min() << " - " << numeric_limits<int>::max(); << "Tyypin long arvoväli on " << numeric_limits<long>::min() << " - " << numeric_limits<long>::max(); << "Tyypin float arvoväli on " << numeric_limits<float>::min() << " - " << numeric_limits<float>::max(); << "Tyypin double arvoväli on " << numeric_limits<double>::min() << " - " << numeric_limits<double>::max(); << "Tyypin long double arvoväli on " << numeric_limits<long double>::min() << " - " << numeric_limits<long double>::max(); ; return 0; } Ohjelman tyypillinen tulostus on: Tyypin short arvoväli on Tyypin int arvoväli on Tyypin long arvoväli on Tyypin float arvoväli on e e+038 Tyypin double arvoväli on e e+308 Tyypin long double arvoväli on e e+308 Otsikkotiedostossa limits määritellään myöskin raja-arvojen symbolit. Esimerkiksi vakio INT_MAX tarkoittaa tyypin int maksimiarvoa ja SCHAR_MIN tarkoittaa tyypin signed char minimiarvoa. Nämä ovat kuitenkin vain symboleja, jotka korvataan koodissasi vastaavilla numeroilla. Esimerkkiohjelmassamme haetuilla arvoilla on tyyppi ja siksi kääntäjä tarkastaa niiden tyypin, kun käytät niitä. Symbolit ovat olemassa historiallisista syistä ja edellä esitetty tapa on suositeltavampi tapa saada nämä tiedot selville. 80
11 Bittioperaattorit Perustietotyypit ja laskutoimitukset Kuten nimikin jo kertoo, bittioperaattoreilla voit käsitellä kokonaislukumuuttujaa bittitasolla. Voit käyttää niitä millaisen kokonaisluvun kanssa tahansa, niin signed, unsigned kuin char - muotoistenkin kanssa. Useimmiten niitä käytetään kuitenkin unsigned-muotoisten kokonaislukujen kanssa. Tavallinen käyttötarkoitus näille operaattoreille on, kun haluat käyttää kokonaislukumuuttujan yksittäisiä bittejä. Esimerkkinä olisi liput, joilla tarkoitetaan binäärisiä indikaattoreita. Voit käyttää bittiä aina, kun tarvitaan vain kahta arvoa: on tai off, mies tai nainen, tosi tai epätosi. Voit myöskin käyttää bittioperaattoreita, kun muuttujaan on talletettu useampia tietoalkioita. Oletetaan, että sinun täytyy pitää kirjaa fonteista. Haluat tallettaa tietoa kunkin fontin tyylistä ja koosta sekä onko fontti lihavoitu tai kursivoitu. Voit pakata kaiken tämän yhteen kaksitavuiseen kokonaislukumuuttujaan: Tyyli 6 Ei käytetä Pistekoko Kursivoitu Ei lihavoitu Bittien käyttö fontin tietoina Voit käyttää yhtä bittiä pitämään kirjaa, onko fontti kursivoitu, ja toista bittiä, onko se lihavoitu. Yhden tavun avulla voit tallettaa 256 eri tyyliä. Viidellä lisäbitillä voit tallettaa fontin pistekoon aina arvoon 32 saakka. Bittioperaattoreilla pääset käsiksi ja voit muuttaa kokonaisluvun yksittäistä bittiä tai bittiryhmää helposti. Bittien siirto-operaattori Bittien siirto-operaattori siirtää kokonaislukumuuttujan bittejä halutun määrän biteissä oikealle tai vasemmalle. Operaattori >> siirtää bittejä oikealle ja operaattori << vasemmalle. Bitit, jotka valuvat yli jommasta kummasta päästä, häviävät. Katsotaan esimerkkiä, jossa oletamme tyypin int olevan kahden tavun mittainen, jotta esimerkki pysyy yksinkertaisena. Määrittelemme ja alustamme muuttujan numero lauseella: unsigned int numero = 16387U; Kuten näimme edellisessä luvussa, etumerkittömien literaalivakioiden yhteydessä tulisi käyttää liitteitä U tai u. Voimme siirtää tämän muuttujan sisältöä sekä tallettaa tuloksen lauseella: unsigned int tulos = numero << 2; //Vasemmalle kaksi bittiä 81
12 C++ Ohjelmoijan käsikirja Siirto-operaattorin vasemmanpuoleinen operandi on arvo, jota siirretään ja oikeanpuoleinen operandi on lukumäärä, montako bittiä siirretään. Seuraava kuva selventää tätä operaatiota: 16,387 on binäärisenä: Lisätään nollia oikealta Vasemmalle 2: Nämä kaksi bittiä häviää = 12 Lisätään nollia vasemmalta Oikealle 2: Nämä kaksi bittiä häviää = 4096 Kuten huomaat, kun siirrämme luvun bittejä kaksi bittiä vasemmalle, tuloksena on luku 12. Eniten merkitsevän bitin menettäminen vaikuttaa hyvin suuresti arvoon. Siirtääksemme oikealle, kirjoitamme: tulos = numero >> 2: //Oikealle kaksi bittiä Tämä siirtää arvoa oikealle kaksi bittiä ja tuloksena on luku Siirtäminen kaksi bittiä oikealle tarkoittaa itse asiassa jakamista luvulla 4. Niin kauan, kun bittejä ei menetetä, siirtäminen vasemmalle n bittiä on sama asia kuin kertominen n kertaa luvulla 2. Toisin sanoen se vastaa kertomista luvulla 2 n. Vastaavasti siirtäminen oikealle n bittiä vastaa jakamista luvulla 2 n. Mutta huomaa: kuten näimme muuttujan numero vasemmalle siirtämisessä, jos merkitseviä bittejä menetetään, tuloksena on arvo, jota et varmastikaan odottanut. Tämä ei kuitenkaan eroa mitenkään oikeasta kertolaskusta. Jos kerrot kaksitavuisen luvun neljällä, saat saman tuloksen, joten siirto vasemmalle ja kertominen ovat yhä vastaavia. Tarkkuudessa tulee ongelmia, koska kertolaskun tulos on kaksitavuisen kokonaisluvun arvoalueen ulkopuolella. Jos haluat muuttaa alkuperäistä arvoa, voit käyttää op=-operaattoria. Tässä tapauksessa käyttäisimme >>= tai <<= -operaattoria: numero >>= 2; //Oikealle kaksi bittiä 82
13 Perustietotyypit ja laskutoimitukset Tämä on sama kuin: numero = numero >> 2; //Oikealle kaksi bittiä Saatat ajatella, että näiden siirto-operaattoreiden ja tulostuksessa jo käyttämiemme >> ja <<operaattoreiden välillä tapahtuisi sekaannuksia. Kääntäjä pystyy kuitenkin yleensä erottamaan tarkoituksen. Jos se ei pysty, se antaa varoituksen. Sinun tulee kuitenkin olla varovainen. Jos esimerkiksi haluat tulostaa muuttujan numero, kun olet ensin siirtänyt sen arvoa vasemmalle kaksi bittiä, voit kirjoittaa: cout << (number << 2); Tässä sulkeet ovat välttämättömät. Ilman niitä kääntäjä tulkitsee siirto-operaattorin virran tulostus -operaattoriksi, eli tuloksena ei ole sitä mitä olit ajatellut. Etumerkillisten kokonaislukujen bittisiirto Voit käyttää bittisiirto-operaattoreita sekä etumerkillisten että etumerkittömien kokonaislukujen yhteydessä. Siirto oikealle -operaattorin toiminta saattaa kuitenkin vaihdella eri järjestelmissä etumerkillisten kokonaislukujen yhteydessä; toiminta riippuu kääntäjäsi toteutuksesta. Joissakin tapauksissa oikealle siirrossa lisätään nollia vapautuviin kohtiin ja joissain tapauksissa merkkibitti siirtyy oikealle, eli vapautuviin kohtiin lisätään ykkösiä. Syy miksi merkkibitti siirtyy oikealle on se, että säilytetään yhteensopivuus oikealle siirron ja jakolaskun välillä. Voimme havainnollistaa tätä char-tyyppisellä muuttujalla. Oletetaan, että määrittelemme char-tyyppisen muuttujan arvo ja asetamme siihen desimaalisen alkuarvon -104: signed char arvo = -104; Tämän binäärinen arvo on Seuraavalla lauseella siirrämme sitä kaksi bittiä oikealle: arvo >>= 2; //Tulos: Binäärinen tulos näytetään kommentissa. Kaksi nollaa häviää oikeasta reunasta ja koska merkkibitti on 1, vasemmalta lisättään ykkösiä. Tuloksen desimaaliarvo on -26, mikä on sama kuin jos olisimme jakaneet luvulla 4. Näinhän pitikin olla. unsigned-tyyppisillä kokonaisluvuilla merkkibittiä lisätään vasemmalta päin. Kuten mainittu, mitä todella tapahtuu kokonaislukujen bittien oikealle siirrossa, riippuu kääntäjästä, joten älä luota, että tämä toimii tällä tavalla. Koska käytät näitä operaattoreita pääasiassa bittitasolla työskennellessäsi - eli kun bittien eheys on tärkeää - sinun tulee aina käyttää unsigned kokonaislukuja. 83
14 C++ Ohjelmoijan käsikirja Bittitason loogiset operaattorit Käytössä on neljä bittioperaattoria, joilla voidaan muokata kokonaisluvun bittejä: Op Kuvaus ~ Tämä on bittitason komplementtioperaattori. Tämä on unaarinen operaattori, joka kääntää operandinsa bitit vastakkaisiksi, eli ykkösestä tulee nolla ja päinvastoin. & Tämä on bittitason AND-operaattori, joka suorittaa AND-operaation operandiensa biteille. Jos kummankin samassa kohdassa oleva bitti on 1, tulos on 1, muutoin tulos on 0. ^ Tämä on bittitason poissulkeva OR-operaattori, joka suorittaa poissulkevan OR - operaation operandiensa biteille. Jos samassa kohdassa olevat bitit ovat erit (eli jos toinen on 0 ja toinen 1), tulos on 1. Jos samassa kohdassa olevat bitit ovat samat, tulos on 0. Tämä on bittitason OR-operaattori, joka suorittaa OR-operaation operandiensa biteille. Jos jompi kumpi samassa kohdassa olevista biteistä on 1, tulos on 1. Jos molemmat ovat 0, tulos on 0. Operaattorit lueteltiin edellä suoritusjärjestyksessä, eli bittitason komplementtioperaattori suoritetaan näistä ensimmäisenä ja bittitason OR viimeisenä. Kuten näet täydellisestä operaattoreiden suoritusjärjestystaulukosta liitteestä D, siirto-operaattorit << ja >> ovat suoritusjärjestyksessä samalla tasolla ja ne ovat ~-operaattorin alapuolella, mutta &-operaattorin yläpuolella. Jos et ole käyttänyt tällaisia operaattoreita aikaisemmin, kysyt varmastikin: Erittäin mielenkiintoista, mutta mihin näitä käytetään? Katsotaan, saammeko niille jotain järkevää käyttöä. Bittitason AND-operaattori Tavallisesti käyttäisit bittitason AND-operaattoria valitessasi kokonaisluvun tietyn bitin tai bittiryhmän. Jotta näemme mitä tämä tarkoittaa, käytämme uudelleen tämän osan alussa ollutta esimerkkiä, jossa käytettiin kokonaislukua tallettamaan fontin tietoja. Oletetaan, että määrittelimme ja alustimme muuttujan sisällöksi 12 pisteen, kursivoidun, tyylin 6 fontin - eli itse asiassa juuri saman kuin käytimme esimerkkikuvassammekin. Binäärimuodossa tyyli on , kursivoitu-bitti on 1, lihavoitu-bitti on 0 ja koko on Kun vielä muistamme, että muuttujassa on yksi bitti, jota ei käytetä, muuttuja fontti tulee alustaa binääriarvolla Koska neljän bitin ryhmä vastaa yhtä heksadesimaalista numeroa, helpoin tapa määritellä alkuarvo on käyttää heksadesimaalista muotoa: unsigned int fontti = 0x064C; // Tyyli 6, kursivoitu, 12 pist. 84! Kun bittejä asetetaan tällä tavalla, heksadesimaalinen esitysmuoto on poikkeuksetta parempi tapa kuin desimaalisten arvojen käyttö.
15 Perustietotyypit ja laskutoimitukset Käyttääksemme fontin kokoa, meidän tulee saada se selville muuttujasta fontti; tämä voidaan tehdä bittitason AND-operaattorilla. Koska bittitason AND-operaattorin tuloksena on 1 vain silloin kun molemmat bitit ovat ykkösiä, voimme määritellä arvon, joka valitsee fontin koon, kun suoritamme bittitason AND-operaation muuttujalle fontti. Tämä tapahtuu yksinkertaisesti määrittelemällä arvo, jossa on ykkösiä niissä kohdissa, joista olemme kiinnostuneita ja nollia muissa kohdissa. Tällaista arvoa kutsutaan maskiksi. Tällainen maski voidaan määritellä lauseella: unsigned int maski_koko = 0x1F; //Maski on Viisi vähiten merkitsevää bittiä määrittelee fontin koon, joten ne asetetaan maskissa ykkösiksi. Muut bitit ovat 0, joten niitä ei oteta huomioon. Voimme nyt irrottaa muuttujan fontti koon lauseella: unsigned int koko = fontti & maski_koko; Kun samassa kohdassa olevat bitit ovat molemmat 1, tulosbitti on 1. Muutoin tulosbitti on 0. Arvot muodostuvat seuraavalla tavalla: fontti maski_koko fontti & maski_koko Bittien jakamisella neljän bitin ryhmiin ei ole varsinaista merkitystä; se vain helpottaa näkemään montako bittiä luvussa on. Kuten näet maskin tarkoituksena on erottaa viisi oikeanpuolimmaista bittiä, jotka kuvaavat pistekokoa. Voimme käyttää samaa menetelmää fontin tyylin erottamiseen, mutta tällöin tarvitsemme myöskin siirto-operaattoria siirtämään fontin tyyliä oikealle. Voimme määritellä maskin, jolla valitaan kahdeksan vasemmanpuoleisinta bittiä: unsigned int maski_tyyli = 0XFF00; //Maski on Fontin tyyli valitaan lauseella: unsigned int tyyli = (fontti & maski_tyyli) >> 8; Lauseen vaikutus on seuraava: fontti maski_tyyli fontti & maski_tyyli (fontti & maski_tyyli) >> Yhtä helposti voit irrottaa kursivointia ja lihavointia ilmaisevat bitit. Tarvitset luonnollisestikin tavan, jolla voit testata tulosbitin arvon. Tämän opimme seuraavassa luvussa. Toinen käyttötapa bittitason AND-operaattorille on bittien muuttaminen nollaksi. Edellä näimme, että jos bitti on maskissa 0, tulosbittinäkin on 0. Muuttaaksesi esimerkiksi kursivointibitin nollaksi, suoritat bittitason AND-operaation maskilla, jossa kursivoitu-bitti on 0 ja kaikki muut bitit 1. Katsomme, miten tämä tehdään, kun käsittelemme bittitason ORoperaattoria. 85
16 C++ Ohjelmoijan käsikirja Bittitason OR Bittitason poissulkevan OR-operaattorin avulla voit asettaa yksittäisiä bittejä tai bittiryhmiä. Jos jatkamme esimerkkimuuttujamme fontti käsittelyä, on varmasti loogista, että haluamme asettaa kursivointi- ja lihavointibitit tarvittaessa ykkösiksi. Voimme muodostaa maskin näiden bittien valitsemiseksi: unsigned int kursivoitu = 0X40U; unsigned int lihavoitu = 0X20U; //7. bitti oikealta //6. bitti oikealta Nyt voimme asettaa lihavoinnin päälle lauseella: fontti = lihavoitu; //Asetetaan lihavointi Bitit muodostuvat tässä seuraavasti: fontti lihavoitu fontti lihavoitu Nyt muuttuja fontti määrittelee, että fontti on lihavoitu sekä kursivoitu. Huomaa, että tämä operaatio asettaa bitin arvoksi ykkösen riippumatta alkuperäisestä arvosta. Jos bitti oli jo ennen 1, se säilyy ykkösenä. Voit myös asettaa useita bittejä yhtä aikaa usean maskin avulla. Seuraava lause asettaa sekä lihavoitu- että kursivoitu-bitin: fontti = lihavoitu kursivoitu;//asetetaan lihav. ja kursivointi Tässä yhteydessä on helppo mennä lankaan valitsemalla väärä operaattori. Koska ajattelemme mielessämme: Aseta kursivointi ja lihavointi, houkutuksena on käyttää &-operaattoria, mikä olisi väärin. Käyttämällä &-operaattoria kahdelle maskille olisi tuloksena arvo, jossa kaikki bitit ovat nollia, eli et muuttaisi mitään varsinaisessa muuttujassa. Kuten mainitsimme edellisen osan lopussa, voimme käyttää &-operaattoria asettamaan bittien arvoksi 0. Tarvitset vain maskin, jossa on 0 sen bitin kohdalla, jonka haluat asettaa nollaksi ja 1 muissa kohdissa. Miten sitten määritellään tällainen maski? Jos haluat määritellä sen eksplisiittisesti, sinun täytyy tietää, montako bittiä muuttujassa on - ei niinkään hyvä tapa, jos haluat ohjelmasi olevan siirrettävän. Voit kuitenkin saada maskin selville käyttämällä bittitason komplementtioperaattoria maskille, jolla asettaisit kyseisen bitin ykköseksi. Voimme ratkaista maskin, jolla lihavointi poistetaan, lihavoitu-maskista itsestään: lihavoitu ~lihavoitu Komplementtioperaattori saa aikaan sen, että alkuperäisen muuttujan kaikki bitit käännetään. Kuten huomaat, tämä muodostaa haluamamme tuloksen riippumatta siitä, onko tyyppi unsigned int kaksitavuinen vai nelitavuinen. Bittitason komplementtioperaattoria kutsutaan joskus NOT-operaattoriksi, koska alkuperäinen bitti muuttuu aina vastakkaiseksi. 86
17 Perustietotyypit ja laskutoimitukset Näin ollen voimme poistaa lihavoinnin seuraavalla lauseella: fontti &= ~lihavoitu; //Poistetaan lihavointi Voit myös asettaa useamman bitin yhdellä kertaa nollaksi yhdistämällä monta maskia &- operaattorilla: fontti &= ~lihavoitu & ~kursivoitu; //Poistetaan lihav. ja kursivointi Tämä asettaa muuttujan fontti lihavoinnin ja kursivoinnin pois päältä. Huomaa, että tässä ei tarvita sulkeita, koska ~-operaattori on suoritusjärjestyksessä ennen &-operaattoria. Bittitason poissulkeva OR Bittitason poissulkevaa OR-operaattoria käytetään huomattavasti harvemmin kun & ja - operaattoreita ja sen käytöstä ei ole monia esimerkkejä. Eräs tärkeä käyttökohta on grafiikan ohjelmoinnissa. Yksi tapa muodostaa vaikutelma, että kuvio liikkuu näytöllä, on piirtää kuvio, poistaa se ja piirtää se uuteen kohtaan. Tämä pitää toistaa hyvin nopeasti, jos haluat pehmeän animaation. Kuvion poistaminen on tässä kriittisessä osassa. Et tietenkään halua tyhjentää koko näyttöä ja piirtää sitä uudelleen. Se olisi liian hidasta ja näyttö vilkkuisi. Ideana on, että poistat vain kuvion tai kuviot, joita olet siirtämässä. Tämä voidaan tehdä ns. poissulkevalla OR -tilalla. Piirtäminen poissulkevassa OR -tilassa Piirretöään alkuperäisellä värillä Piirretään taustan värillä uudelleen ja piirretään uuteen kohtaan Piirretään taustan värillä uudelleen ja piirretään uuteen kohtaan Piirretään taustan värillä uudelleen ja piirretään uuteen kohtaan Piirretään taustan värillä uudelleen ja piirretään uuteen kohtaan Piirretään taustan värillä uudelleen ja piirretään uuteen kohtaan Poissulkeva OR -tila perustuu ideaan, että kun olet piirtänyt kuvion näytölle tietyllä värillä, se häviää näytöltä, jos piirrät sen uudelleen taustan värillä. Kun piirrät kuvion näytölle poissulkevassa OR -tilassa, väri vuorottelee automaattisesti kuvion värin ja taustan värin välillä aina kun piirrät kuvion. Tämä saavutetaan käyttämällä bittitason poissulkevaa OR -operaattoria, jolla värit muutetaan automaattisesti ja nopeasti. Eli jos käytät poissulkevaa OR -operaattoria kahdelle arvolle ja sen jälkeen käytät uudelleen poissulkevaa OR -operaattoria jommalle kummalle alkuperäisistä arvoista äskeisen tuloksella, saat toisen alkuperäisistä arvoista. Kuulostaa monimutkaiselta, joten katsotaan, kuinka se toimii esimerkin avulla. 87
18 C++ Ohjelmoijan käsikirja Oletetaan, että haluamme vaihdella piirtovärin (käytämme punaista) ja taustavärin (valkoinen) välillä. Väri ilmaistaan usein kolmella 8-bittisellä arvolla, jotka vastaavat punaisen, sinisen ja vihreän voimakkuuksia. Muuttamalla punaisen, sinisen ja vihreän suhteita, voit muodostaa noin 16 miljoonaa eri väriä valkoisesta mustaan. Kirkas punainen on 0xFF0000, jossa punaisen arvo on maksimissa ja muut kaksi väriä ovat nollassa. Samaan tapaan vihreä olisi 0xFF00 ja sininen 0xFF. Valkoisessa on kaikki värit maksimissa, eli se on 0xFFFFFF. Voimme nyt määritellä muuttujat, jotka esittävät punaista ja valkoista: unsigned long punainen = 0XFF0000UL; unsigned long valkoinen = 0XFFFFFFUL; //Punainen //Valkoinen Seuraavaksi teemme maskin, jolla muutamme värin valkoisen ja punaisen välillä sekä asetamme piirtovärin muuttujan alkuarvoksi punaisen: unsigned long maski = punainen ^ valkoinen; unsigned long piirtovari = punainen; //Värien vaihdon maski //Piirtoväri Muuttuja maski alustetaan haluamistamme väreistä bittitason poissulkevan OR -operaattorin avulla: punainen valkoinen maski (punainen ^ valkoinen) Jos käytämme poissulkevaa OR -operaattoria maskin ja punaisen välillä, saamme valkoisen ja päinvastoin. Näin ollen, kun olemme piirtäneet kuvion piirtovari-värillä, voimme vaihtaa värin lauseella: piirtovari ^= maski; //Vaihdetaan piirtoväri Tämän vaikutus on seuraava: piitovari maski piirtovari ^ maski Eli olemme muuttaneet värin punaisesta valkoiseen. Suorittamalla saman lauseen uudelleen vaihtuu väri takaisin punaiseksi: piirtovari ^= maski; //Vaihdetaan piirtoväri Tämän vaikutus on seuraava: 88 piitovari maski piirtovari ^ maski Kuten huomaat, piirtovari on jälleen punainen. Tämä tekniikka toimii minkä kahden värin kohdalla tahansa, vaikka itse asiassa sillä ei ole mitään tekemistä itse värien kanssa: voit käyttää sitä minkä tahansa kahden kokonaislukuarvon välillä siirtymiseen.
19 Perustietotyypit ja laskutoimitukset Kokeile itse - Bittitason operaattorit Seuraava esimerkki selventää bittioperaattoreiden käyttöä. Havainnollistamme myöskin poissulkevan OR -operaattorin käyttöä kahden arvon välillä vaihtelemiseen sekä miten maskeja käytetään yksittäisten bittien valitsemiseen ja asettamiseen: // Esimerkki Bittitason operaattorit #include <iostream> #include <iomanip> using namespace std; int main() { unsigned long punainen = 0XFF0000UL; unsigned long valkoinen = 0XFFFFFFUL; cout << hex; cout.fill('0'); // Punainen // Valkoinen // Heksadesimaalinen tulostus // Asetetaan tulostuksen täyttömerkki cout << "\nkokeillaan bittitason AND ja OR -operaattoreita."; cout << "\nalkuarvo punainen = " << setw(8) << punainen; cout << "\nkomplementti ~punainen = " << setw(8) << ~punainen; cout << "\nalkuarvo valkoinen = " << setw(8) << valkoinen; cout << "\nkomplementti ~valkoinen = " << setw(8) << ~valkoinen; cout << "\nand punainen & valkoinen = " << setw(8) << (punainen & valkoinen); cout << "\nor punainen valkoinen = " << setw(8) << (punainen valkoinen); cout << "\n\nperäkkäisiä poissulkevia OR-operaatioita."; unsigned long maski = punainen ^ valkoinen; cout << "\nmaski = punainen ^ valkoinen = " << setw(8) << maski; cout << "\nmaski ^ punainen = " << setw(8) << (maski ^ punainen); cout << "\nmaski ^ valkoinen = " << setw(8) << (maski ^ valkoinen); unsigned long liput = 0xFF; // Liput-muuttuja unsigned long bit1maski = 0x1; // Valitsee bitin 1 unsigned long bit6maski = 0x20; // Valitsee bitin 6 unsigned long bit20maski = 0x80000; // Valitsee bitin 20 cout << "\n\nvalitaan tai asetetaan maskien avulla tietty lippu."; cout << "\nvalitaan 1. bitti lipuista: " << setw(8) << (liput & bit1maski); cout << "\nvalitaan 6. bitti lipuista: " << setw(8) << (liput & bit6maski); cout << "\nasetetaan lippujen 6. bitti: " << setw(8) << (liput &= ~bit6maski); cout << "\nasetetaan lippujen 20. bitti: " << setw(8) << (liput = bit20maski); ; return 0; } 89
20 C++ Ohjelmoijan käsikirja Ohjelma tulostaa seuraavaa: Kokeillaan bittitason AND ja OR -operaattoreita. Alkuarvo punainen = 00ff0000 Komplementti ~punainen = ff00ffff Alkuarvo valkoinen = 00ffffff Komplementti ~valkoinen = ff AND punainen & valkoinen = 00ff0000 OR punainen valkoinen = 00ffffff Peräkkäisiä poissulkevia OR-operaatioita. maski = punainen ^ valkoinen = 0000ffff maski ^ punainen = 00ffffff maski ^ valkoinen = 00ff0000 Valitaan tai asetetaan maskien avulla tietty lippu. Valitaan 1. bitti lipuista: Valitaan 6. bitti lipuista: Asetetaan lippujen 6. bitti: df Asetetaan lippujen 20. bitti: df Kuinka se toimii Tarvitsemme #include-esikäsittelijäkomentoa sisällyttämään iomanip-otsikkotiedoston, koska ohjelmamme käyttää muokkausfunktioita kontrolloimaan tulostusta. Aluksi määrittelemme kaksi kokonaislukumuuttujaa, jotka sisältävät arvot väreille, joita käytämme bittioperaatioissamme: unsigned long punainen = 0XFF0000UL; unsigned long valkoinen = 0XFFFFFFUL; // Punainen // Valkoinen Haluamme tulostaa tiedot heksadesimaalisina. Tämän määrittelemme lauseella: cout << hex; // Heksadesimaalinen tulostus Tässä hex asettaa tulostuksen siten, että kokonaislukuarvot tulostetaan heksadesimaalisina. Huomaa, että tämä on modaalinen - kaikki sitä seuraavat kokonaislukujen tulostukset tulostuvat heksadesimaalisina. Eli hex tarvitsee lähettää cout-tulostusvirtaan vain kerran. Jos haluat, voit palauttaa tulostuksen desimaaliseksi: cout << dec; //Desimaalinen tulostus Tässä dec asettaa tulostuksen siten, että kokonaislukuarvot tulostuvat oletusarvoisessa desimaalisessa muodossa. Huomaa, että tulostuksen muuttaminen heksadesimaaliseksi vaikuttaa vain kokonaislukuarvojen tulostamiseen. Liukuluvut tulostuvat edelleen normaalissa desimaalimuodossa. Asioiden selkeyttämiseksi tulostamme kokonainaisluvut alkunollilla. Tämä asetetaan seuraavalla lauseella: cout.fill('0'); // Asetetaan tulostuksen täyttömerkki 90
21 Perustietotyypit ja laskutoimitukset Tässä fill() on funktio, joka asettaa täyttömerkiksi sulkeiden sisällä olevan merkin. Tämä on myöskin modaalinen, joten kaikki seuraavat kokonaislukujen tulostukset käyttävät tätä täyttömerkkiä tarvittaessa. Tämä vaikuttaa sekä desimaalisiin että heksadesimaalisiin tulostuksiin. Jos olisit halunnut täytteeksi * -merkit, olisit kirjoittanut: cout.fill( * ); // Asetetaan tulostuksen täyttömerkki Jos haluat täyttömerkin takaisin oletusarvoonsa, kirjoita sulkeiden sisään välilyönti: cout.fil( ); // Asetetaan tulostuksen täyttömerkki Älä sijoita funktion fill() kutsua tulostuslauseeseen. Jos teet näin, edellinen täyttömerkki tulostetaan, koska funktio fill() palauttaa sen. Tämä selvenee, kun käsittelemme funktioita luvussa 8. Punaisen ja sen komplementin arvot tulostetaan lauseilla: cout << "\nalkuarvo punainen = " << setw(8) << punainen; cout << "\nkomplementti ~punainen = " << setw(8) << ~punainen; Käytämme setw()-muokkausfunktiota, jolla asetamme tulostuksen kentän leveyden arvoksi 8. Jos varmistamme, että kaikki tulostetut arvot ovat saman levyisissä kentissä, niiden vertaileminen on helpompaa. Kentän leveyden asettaminen ei ole modaalinen; se vaikuttaa vain seuraavaan tulostuslauseeseen. Punaisen ja valkoisen tulostuksesta näet, että ~-operaattori tekee sen minkä odotimmekin: kääntää operandinsa bitit. Vertailemme muuttujia punainen ja valkoinen bittitason AND ja OR -operaattoreilla: cout << "\nand punainen & valkoinen = " << setw(8) << (punainen & valkoinen); cout << "\nor punainen valkoinen = " << setw(8) << (punainen valkoinen); Huomaa sulkeet tulostuslausekkeessa. Ne ovat tarpeelliset, koska << on suoritusjärjestyksessä operaattoreiden & ja edellä. Ilman sulkeita lauseet eivät käänny. Tulostuksesta huomaat, että näin todella tapahtuu. Seuraavaksi teemme maskin, jonka avulla vaihtelemme punaisen ja valkoisen välillä. Tähän käytämme poissulkevaa OR-operaattoria: unsigned long maski = punainen ^ valkoinen; Jos tutkit maskin tulostusta, huomaat, että poissulkevan OR-operaattorin tuloksen bitin arvo on 1, kun bitit ovat erit ja 0, kun ne ovat samat. Käyttämällä maskia jomman kumman värin kanssa, saamme toisen väreistä: cout << "\nmaski ^ punainen = " << setw(8) << (maski ^ punainen); cout << "\nmaski ^ valkoinen = " << setw(8) << (maski ^ valkoinen); 91
22 C++ Ohjelmoijan käsikirja Viimeiset lauseet havainnollistavat, miten valitaan yksittäinen bitti lippubittien joukosta. Maskissa, joka valitsee halutun bitin, kyseisen bitin tulee olla 1 ja kaikissa muissa kohdissa 0. Näin ollen maskit, joilla valitaan 32-bittisestä long-muuttujasta bitit 1, 6 ja 20, ovat seuraavanlaiset: unsigned long bit1maski = 0x1; // Valitsee bitin 1 unsigned long bit6maski = 0x20; // Valitsee bitin 6 unsigned long bit20maski = 0x80000; // Valitsee bitin 20 Valitaksemme bitin muuttujasta liput, käytämme bittitason AND-operaattoria halutun maskin kanssa: cout << "\nvalitaan 6. bitti lipuista: " << setw(8) << (liput & bit6maski); Asettaaksesi bitin nollaksi, sinun tulee käyttää bittitason AND-operaattoria maskin kanssa, jossa on 0 bitin kohdalla, jonka haluat asettaa nollaksi ja 1 muualla. Tällainen maski saadaan aikaan helposti komplementtioperaattorilla maskista, jossa halutun bitin arvo on 1. Maski bit6maski on juuri tällainen maski. Lause, joka asettaa nollaksi bitin 6 ja tulostaa tuloksen, on: cout << "\nasetetaan lippujen 6. bitti: " << setw(8) << (liput &= ~bit6maski); Jos bitti 6 oli jo nolla, se tietysti säilyy sellaisena. Asettaaksesi bitin arvoksi ykkösen, käytät bittitason OR-operaattoria maskilla, jossa haluamasi bitin arvo on 1: cout << "\nasetetaan lippujen 20. bitti: " << setw(8) << (liput = bit20maski); Tämä asettaa muuttujan liput bitin 20 arvoksi ykkösen ja tulostaa tuloksen. Edelleen, jos bitin arvo oli jo 1, se säilyy sellaisena. Lisää muokkausfunktioista Olemme tähän mennessä tutustuneet viiteen modaaliseen tulostuksen muokkausfunktioon, jotka määritellään otsikkotiedostossa iostream: scientific, fixed, dec, hex ja oct. Nyt listaamme kaikki muutkin tällaiset funktiot. Älä välitä viimeisissä kahdessa mainittuja bool-arvoja - käsittelemme niitä seuraavassa luvussa. Muokkausf. Toiminta dec Muotoilee kokonaisluvut 10-kantaisina (desimaalisina). Oletuksena. hex Muotoilee kokonaisluvut 16-kantaisina (heksadesimaalisina). oct Muotoilee kokonaisluvut 8-kantaisina (oktaalisina). left Tasaa arvot tulostuskentän vasempaan reunaan ja täyttää oikealta täyttömerkillä. Oletustäyttömerkkinä on välilyönti. 92
23 Perustietotyypit ja laskutoimitukset Muokkausf. Toiminta right fixed scientific Tasaa arvot tulostuskentän oikeaan reunaan ja täyttää vasemmalta täyttömerkillä. Tämä on oletustasaus. Tulostaa liukuluvut fixed-muodossa, eli ilman eksponenttia. Tulostaa liukuluvut tieteellisessä muodossa, eli mantissan ja eksponentin avulla. Oletusarvoisesti liukuluvut tulostetaan joko fixed tai scientific, riippuen tulostettavasta arvosta. showpoint Tulostaa desimaalipisteen ja liukuluvun loppunollat. noshowpoint Vastakohtainen edelliselle muokkausfunktiolle. Tämä on oletusarvona. showbase Tulostaa oktaaliluvun eteen 0 ja heksadesimaalisen eteen 0x tai 0X. noshowbase Tulostaa oktaaliset ja heksadesimaaliset luvut ilman etuliitettä. Oletusarvona. showpos Tulostaa plus-merkin (+) positiivisille arvoille. noshowpos Positiivisille arvoille ei tulosteta plus-merkkiä. Tämä on oletusarvona. uppercase Tulostaa isot merkit A - F heksadesimaalinumeroina, kun kokonaisluvut tulostetaan heksadesimaalisina ja 0X jos showbase on asetettu. Tulostaa E eksponentille, jos arvot tulostetaan tieteellisessä muodossa. nouppercase Tulostaa pienet merkit edellä olleille. Tämä on oletusarvona. boolalpha Tulostaa bool-arvot sanoilla true ja false. noboolalpha Tulostaa bool-arvot lukuina 1 ja 0. Jos haluat asetta samalla kertaa useamman näistä tiloista, voit tehdä sen tulostamalla useamman muokkausfunktion tulostusvirtaan. Jos esimerkiksi haluat tulostaa kokonaisluvut heksadesimaalisina vasemmalta tasattuun tulostuskenttään, voit kirjoittaa: cout << hex << left << arvo; Tämä tulostaa muuttujan arvo (sekä kaikki seuraavat kokonaisluvut, kunnes nämä tulostusasetukset muutetaan) vasemmalle tasattuna heksadesimaalisena lukuna. Luetellut tietotyypit Joskus tarvitaan muuttujia, joihin voidaan sijoittaa vain tiettyjä, nimettyjä arvoja, kuten viikonpäivät tai kuukaudet. Tällaiseen tarkoitukseen on C++:ssa luetellut tietotyypit. Kun käytät lueteltua tietotyyppiä, teet itse asiassa uuden tietotyypin. Katsotaan esimerkkiä käyttämällä juuri mainittuja viikonpäiviä. Voimme määritellä tämän seuraavasti: enum Viikonpaiva { Maanantai, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai, Sunnuntai }; 93
24 C++ Ohjelmoijan käsikirja Tämä määrittelee luetellun tietotyypin Viikonpaiva, jonka tyyppiset muuttujat voivat saada vain aaltosulkeiden välissä määriteltyjä arvoja. Jos yrität asettaa Viikonpaiva-tyyppiseen muuttujaan arvoja, jotka eivät ole lueteltujen arvojen joukossa, saat virheilmoituksen. Itse asiassa kukin viikonpäivä määritellään automaattisesti kokonaislukuarvoksi. Luettelon ensimmäinen nimi, Maanantai, saa arvon 0, Tiistai saa arvon 1 ja Sunnuntai saa lopulta arvon 6. Voimme määritellä muuttujan tanaan luetellun tyypin Viikonpaiva tyyppiseksi lauseella: Viikonpaiva tanaan = Tiistai; Tyyppiä Viikonpaiva käytetään aivan samaan tapaan kuin perustietotyyppejäkin. Tämä määrittely myöskin alustaa muuttujan tanaan arvoksi Tiistai. Jos tulostat muuttujan tanaan arvon, tulostuu luku 1. Oletusarvoisesti luetellun arvon kokonaislukuarvo on edellisen luetellun arvon kokonaislukuarvo + 1 ja ensimmäisen kokonaislukuarvo on 0. Jos haluat, että numerointi alkaa esimerkiksi arvosta 1, voit tehdä sen seuraavasti (kokonaislukuarvot ovat 1-7): enum Viikonpaiva { Maanantai = 1, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai, Sunnuntai }; Kaikilla tunnisteilla ei tarvitse olla eri arvoa. Voit määritellä tunnisteille Maanantai ja Ma arvon 1 lauseella: enum Viikonpaiva { Maanantai = 1, Ma = 1, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai, Sunnuntai }; Tämä mahdollistaa viikon ensimmäistä päivää kutsuttavan joko tunnisteella Maanantai tai Ma. Muuttuja eilen, joka on määritelty Viikonpaiva-tyyppiseksi, voidaan asettaa lauseella: eilen = Ma; Voit myöskin määritellä tunnisteen luettelossa aiemmin olleen tunnisteen perusteella. Sijoitetaan kaikki jo tästä aiheesta käsittelemämme samaan lauseeseen: enum Viikonpaiva { Maanantai, Ma = Maanantai, Tiistai = Maanantai + 2, Ti = Tiistai, Keskiviikko = Tiistai + 2, Ke = Keskiviikko, Torstai = Keskiviikko + 2, To = Torstai, Perjantai = Torstai + 2, Pe = Perjantai, Lauantai = Perjantai + 2, La = Lauantai, Sunnuntai = Lauantai + 2, Su = Sunnuntai }; Nyt Viikonpaiva-tyyppisillä muuttujilla voi olla arvo Maanantai - Sunnuntai ja Ma - Su, joita vastaavat kokonaislukuarvot ovat 0, 2, 4, 6, 8, 10 ja 12. Halutessasi voit myöskin antaa eksplisiittisesti arvon kaikille tunnisteille. Voimme esimerkiksi määritellä luetellun tietotyypin: 94
25 Perustietotyypit ja laskutoimitukset enum Pisteet { Pilkku =,, Huutomerkki =!, Kysymysmerkki =? }; Tässä määrittelimme Pisteet-tyyppiselle muuttujalle mahdolliset arvot näiden symboleiden numeroarvoiksi. Liitteessä A olevassa ASCII-taulukosta huomaat, että näiden symboleiden kokonaislukuarvot ovat 44, 33 ja 63. Tämä havainnollistaa myös sen, että arvojen ei tarvitse olla nousevassa järjestyksessä. Jos et määrittele kaikkia arvoja eksplisiittisesti, arvoja annetaan tunnisteille automaattisesti lisäämällä aina 1 edellisen tunnisteen arvoon. Tunnisteille annettavat arvot täytyy olla käännösaikaisia vakioita - eli vakiolausekkeita, jotka kääntäjä pystyy laskemaan. Tällaiset lausekkeet voivat sisältää vain literaalivakioita, aikaisemmin määriteltyjä luetellun tyypin tunnisteita ja muuttujia, jotka on määritelty const-määreellä. Et voi käyttää ei-const -muuttujia vaikka olisit alustanutkin ne. Nimettömät luetellut tietotyypit Jos määrittelet muuttujat samalla kertaa, kun määrittelet luetellun tietotyypin, voit jättää varsinaisen luetellun tietotyypin tekemättä, jos et tarvitse samanlaista tyyppiä myöhemmin. Esimerkiksi: enum { Maanantai, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai, Sunnuntai } eilen, tanaan, huomenna; Tässä määrittelimme kolme muuttujaa, jotka voivat saada arvot Maanantai - Sunnuntai. Koska lueteltua tietotyyppiä ei ole määritelty, emme voi viitata siihen. Et voi määritellä samantyyppisiä muuttujia lainkaan, koska silloin sinun tulisi toistaa määrittely, mikä ei ole sallittua. Tällainen uusi määrittely tarkoittaisi, että määrittelisit uudelleen arvot Maanantai - Sunnuntai ja sehän ei ole sallittua. Nimettömiä lueteltuja tietotyyppejä käytetään usein toisena tapan määritellä kokonaislukuvakioita, kuten seuraavassa: enum { jalkoja_jaardissa = 3, tuumia_jalassa = 12, jaardeja_mailissa = 1760 }; Tässä on kolme tunnistetta, joiden arvo annetaan eksplisiittisesti. Vaikka emme ole määritelleet tälle yhtään muuttujaa, voimme silti käyttää tunnisteita lausekkeissa. Eli voimme kirjoittaa lauseen: << Jalkoja 5 mailissa = << 5 * jalkoja_jaardissa * jaardeja_mailissa; Tunnisteiden arvo muunnetaan automaattisesti kokonaisluvuiksi. Näyttäisi kuitenkin siltä, että kokonaislukuvakioiden määrittelyllä luetellun tietotyypin avulla ei saavuteta juuri mitään etua, mutta huomaamme käsitellessämme luokkia, että tällä tavalla voimme kätevästi sisällyttää vakion luokkaan. Katsotaan nyt hieman tarkemmin lueteltujen tietotyyppien muunnoksia. 95
26 C++ Ohjelmoijan käsikirja Tyypinmuunnokset kokonaislukujen ja lueteltujen tietotyyppien välillä Kuten itse luetellun tietotyypin tunnisteita, voit käyttää myös luetellun tietotyypin tyyppistä muuttujaa laskutoimituksissa. Tunnisteen tyyppi muunnetaan automaattisesti sopivaksi, mutta ei toisinpäin: kokonaislukutyypistä luetellun tietotyypin tunnisteeksi ei suoriteta automaattista muunnosta. Jos olemme määritelleet muuttujan tanaan edellä määrittelemämme Viikonpaiva-tyyppiseksi, voimme kirjoittaa: tanaan = Tiistai; int paivan_arvo = tanaan + 1; //Sijoitetaan tunniste //Lasketaan tunnisteen avulla Muuttujan tanaan arvo on Tiistai, mikä vastaa kokonaislukua 1, joten muuttujan paivan_arvo arvoksi sijoitetaan 2. Vaikka tunniste Keskiviikko vastaa kokonaislukua 2, seuraava lause ei käänny: tanaan = paivan_arvo; //Virhe - ei muunnosta! Voimme kuitenkin suorittaa tämän lauseen tehtävän, jos käytämme eksplisiittistä tyypinmuunnosta: tanaan = static_cast<viikonpaiva>(paivan_arvo); //OK Eksplisiittisessä tyypinmuunnoksessa muunnettavan kokonaislukuarvon tulee olla lueteltujen tunnisteiden arvojen joukossa. Jos näin ei ole, tulos on määrittelemätön. Tämä ei tarkoita sitä, että sen täytyy olla jonkin tietyn tunnisteen arvo, vaan sen täytyy olla suurempi kuin pienimmän tunnisteen arvo ja pienempi kuin suurimman tunnisteen arvo. Voimme esimerkiksi määritellä luetellun tietotyypin Korkeus ja määritellä sen tyyppinen muuttuja lauseella: enum Korkeus { Pohja, Huippu = 20 } sijainti; Tunnisteen Pohja arvo on 0 ja tunnisteen Huippu arvo on 20. Arvovälinä on siis 0-20, joten voimme sijoittaa arvon muuttujaan sijainti seuraavalla lauseella: sijainti = static_cast<korkeus>(10); Muuttujaan sijainti sijoitettu arvo ei vastaa kumpaakaan lueteltua tunnistetta, mutta se on sallittu arvo, koska se on luetellun tietotyypin arvovälissä. Aikaisemmin käsittelemäämme Pisteet-tyypin mukaiseen muuttujaan voit sijoittaa minkä tahansa kokonaisluvun välillä 33-63, vaikka onkin vaikea kuvitella mitä hyötyä tällaisesta sijoituksesta olisi. Kokeile itse - Luetellut tietotyypit 96 Luetellut tietotyypit tulevat käyttökelpoisemmiksi, kun voit verrata luetellun tietotyypin mukaisen muuttujan arvoja luetellun tietotyypin tunnisteisiin. Käsittelemme tätä seuraavassa luvussa, joten tässä on yksinkertainen esimerkki, joka havainnollistaa jo käsittelemiämme lueteltujen tietotyyppien operaatioita:
27 Perustietotyypit ja laskutoimitukset // Esimerkki 3.5 Luetellut tietotyypit #include <iostream> using namespace std; int main() { enum Kieli { Suomi, Englanti, Ranska, Saksa, Espanja }; } // Tulostetaan tunnisteet cout << "\nmahdolliset kielet ovat:\n" << Suomi << ". Suomi\n" << Englanti << ". Englanti\n" << Ranska << ". Ranska\n" << Saksa << ". Saksa\n" << Espanja << ". Espanja\n ; Kieli nyk_kieli = Saksa; cout << "\n Nykyinen kieli on " << nyk_kieli; nyk_kieli = static_cast<kieli>(nyk_kieli + 1); cout << "\n Nykyinen kieli on nyt " << nyk_kieli; return 0; Ohjelman tulostus on: Mahdolliset kielet ovat: 0. Suomi 1. Englanti 2. Ranska 3. Saksa 4. Espanja Nykyinen kieli on 2 Nykyinen kieli on nyt 3 Kuinka se toimii Ensiksi määrittelemme luetellun tietotyypin Kieli seuraavalla lauseella: enum Kieli { Suomi, Englanti, Ranska, Saksa, Espanja }; Kieli-tyyppisen muuttujan arvona voi olla mikä tahansa luetelluista tunnisteista. Seuraavalla lauseella luettelemme kaikki mahdolliset arvot: cout << "\nmahdolliset kielet ovat:\n" << Suomi << ". Suomi\n" << Englanti << ". Englanti\n" << Ranska << ". Ranska\n" << Saksa << ". Saksa\n" << Espanja << ". Espanja\n ; 97
28 C++ Ohjelmoijan käsikirja Lueteltu tunniste tulostetaan numeerisena arvona, joten tulostamme myös merkkijonon kunkin numeron viereen. Määrittelemme ja alustamme Kieli-tyyppisen muuttujan lauseella: Kieli nyk_kieli = Saksa; Tämän muuttujan arvo tulostuu lukuna 2, jonka jälkeen annamme sille uuden arvon lauseella: nyk_kieli = static_cast<kieli>(nyk_kieli + 1); Lausekkeessa nyk_kieli + 1 muuttujan nyk_kieli muunnetaan tyypiksi int, jonka jälkeen siihen lisätään luku 1 ja tuloksena on 3 ja tyyppinä int. Tämä muunnetaan eksplisiittisellä tyypinmuunnoksella takaisin Kieli-tyyppiseksi ennen kuin se sijoitetaan muuttujaan nyk_kieli. Ilman eksplisiittistä tyypinmuunnosta lause ei kääntyisi, koska kokonaislukutyypistä ei suoriteta automaattista tyypinmuunnosta luetelluksi tyypiksi. Tämän jälkeen muuttuja nyk_kieli tulostuu arvona 3. Tietotyyppien synonyymit Olemme jo nähneet kuinka lueteltujen tietotyyppien avulla voimme määritellä omia tietotyyppejä. typedef-komennolla voit määritellä peitenimen jollekin toiselle tietotyypille. Käyttämällä typedef-komentoa voit esimerkiksi määritellä tunnisteen Suuret synonyymiksi perustietotyypille long: typedef long Suuret; Tämä määrittelee tyypin Suuret tyypin long synonyymiksi, joten voit määritellä muuttujan omanum long-tyyppiseksi lauseella: Suuret omanum = 0; //Määrittelee ja alustaa long int -muuttujan Tämän määrittelyn ja standardin tietotyypin käyttämisen välillä ei ole mitään eroa. Voisit siis aivan yhtä hyvin käyttää lausetta: long int omanum = 0; //Määrittelee ja alustaa long int -muuttujan 98 Tämän tulos on aivan sama. Itse asiassa, jos määrittelet oman peitenimen (kuten Suuret), voit käyttää samassa ohjelmassa molempia määrittelytapoja määritellessäsi muuttujia, jotka ovat lopulta saman tyyppisiä. On kuitenkin varsin vaikea keksiä syytä miksi näin kannattaisi tehdä. Koska typedef yksinkertaisesti luo synonyymin (peitenimen) jo olemassa olevalle tyypille, se saattaa kuulostaa tarpeettomalta. Näin ei kuitenkaan todellakaan ole. Yksi tärkeä typedef:n käyttö on mahdollistaa tietotyyppien joustavuus ohjelmassa, jonka on tarkoitus toimia erilaisissa tietokoneissa. Katsotaan esimerkkiä, joka selventää, miten tämä toimii. Oletetaan, että kirjoitamme ohjelmaa, joka käyttää useita muuttujia laskemaan tiettyjä tapahtumia - voisimme kirjoittaa vaikka ohjelman, joka laskee suuressa tehtaassa tunnissa tuotettujen suklaapatukoiden määrää. Tiedämme, että tyypilliset arvot tällaiselle muuttujalle tarvitsevat neljää tavua.
29 Perustietotyypit ja laskutoimitukset Joissakin tietokoneissa tyyppi int on kaksi tavua, mikä ei riitä ohjelmaamme. Toisissa tietokoneissa int on neljä tavua, mikä on juuri se mitä haluammekin. Voisimme ratkaista tämän käyttämällä tyyppiä long, joka on yleisesti vähintään neljä tavua. Mutta joissain tietokoneissa se voi olla kahdeksan tavua, joka tuhlaa muistia - varsinkin, jos ohjelmassamme käytetään runsaasti tällaisia kokonaislukuja. Voimme ratkaista tilanteen määrittelemällä oman tietotyyppimme, jota sitten käytetään ohjelmassamme, kuten seuraavassa: typedef int Laskuri; //Määrittelee kokonaislukutyypin Nyt voimme kirjoittaa ohjelmamme käyttämällä tyyppiä Laskuri perustietotyypin int sijaan. Näin voimme vain muuttaa Laskuri-tyyppiä, jos haluamme kääntää ohjelman tietokoneessa, joissa tyypin int arvoväli on liian pieni: typedef long Laskuri; //Määrittelee kokonaislukutyypin Nyt kaikki kokonaisluvut, jotka on määritelty Laskuri-tyyppisiksi, ovat tyyppiä long. Huomaamme myöhemmin, että typedef on hyvin merkittävässä roolissa, kun voimme yksinkertaistaa monimutkaisempia tyypinmäärityksiä kuin olemme tähän saakka käsitelleet. Näemme myöhemmin myös, kuinka luokkien avulla voimme määritellä aivan uusia tietotyyppejä, joiden ominaisuuksia ja operaatioita voimme täydellisesti kontrolloida. Muuttujan elinaika Kaikilla muuttujilla on äärellinen elinaika ohjelmaa suoritettaessa. Niiden olemassaolo alkaa siitä kohtaa, kun määrittelet ne, ja jossain kohdassa ne häviävät - viimeistään silloin, kun ohjelman suoritus päättyy. Kuinka kauan tietty muuttuja säilyy muistissa kutsutaan säilytysajaksi. Muuttujalla voi olla kolmentyyppisiä säilytysaikoja: automaattinen säilytysaika staattinen säilytysaika dynaaminen säilytysaika Se, miten määrittelet muuttujan, määrittelee säilytysajan. Dynaamiseen säilytysaikaan palaamme luvussa 7, mutta katsotaan ensin kahta ensimmäistä säilytysaikaa. Muuttujilla on myöskin niiden näkyvyysalue. Muuttujan näkyvyysalueella tarkoitetaan yksinkertaisesti sitä ohjelman osaa, jossa muuttujan nimi on käytettävissä. Muuttujan näkyvyysalueella voit huoletta viitata siihen, muuttaa sen arvoa tai käyttää sitä laskutoimituksissa. Muuttujan näkyvyysalueen ulkopuolella et voi viitata sen nimeen - jos yrität, saat kääntäjän virheilmoituksen. Huomaa, että muuttuja voi hyvinkin olla olemassa näkyvyysalueen ulkopuolellakin, mutta et voi viitata siihen muuttujan nimellä. Näemme esimerkkejä tällaisesta tilanteesta myöhemmin. Kaikkien tähän saakka määrittelemiemme muuttujien säilytysaika on ollut automaattinen, joten kutsummekin niitä automaattisiksi muuttujiksi. Katsotaan tätä hieman tarkemmin. 99
30 C++ Ohjelmoijan käsikirja Automaattiset muuttujat Tähän saakka määrittelemämme muuttujat on määritelty lohkossa - eli aaltosulkeiden sisällä. Tällaisia kutsutaan automaattisiksi muuttujiksi ja niiden näkyvyysaluetta sanotaan paikalliseksi. Automaattinen muuttuja on näkyvissä siitä kohdasta alkaen, jossa se määritellään, aina sen lohkon loppuun saakka, jossa se määriteltiin. Automaattinen muuttuja syntyy, kun se määritellään ja häviää määrittelyn sisältävän lohkon päättyessä. Joka kerta, kun lohko, jossa on automaattisen muuttujan määrittely, suoritetaan, muuttuja luodaan uudelleen, ja jos asetat muuttujalle alkuarvon, se asetetaan joka kerta uudelleen. Käytössä on avainsana auto, jolla voit määritellä muuttujan automaattisesti. Sitä käytetään kuitenkin hyvin harvoin, koska se on oletusarvona automaattisesti. Kootaan edellä esitetty esimerkiksi. Kokeile itse - Automaattiset muuttujat Seuraava esimerkki havainnollistaa automaattisten muuttujien elinaikaa: // Esimerkki Automaattiset muuttujat #include <iostream> using namespace std; int main() { // Funktion näkyvyysalue alkaa tästä int laskuri1 = 10; int laskuri3 = 50; << "Ulompi laskuri1 = " << laskuri1; { // Uusi näkyvyysalue alkaa tästä... int laskuri1 = 20; // Tämä piilotta ulomman laskuri1:n int laskuri2 = 30; << "Sisempi laskuri1 = " << laskuri1; laskuri1 += 3; // Tämä muuttaa sisempää laskuri1:tä laskuri3 += laskuri2; } //...ja päättyy tähän. << "Ulompi laskuri1 = " << laskuri1 << endl << "Ulompi laskuri3 = " << laskuri3; // << laskuri2; // Poista kommentointi niin saat virheen ; return 0; } // Funktion näkyvyysalue päättyy tähän 100
31 Perustietotyypit ja laskutoimitukset Esimerkin tulostus on: Ulompi laskuri1 = 10 Sisempi laskuri1 = 20 Ulompi laskuri1 = 10 Ulompi laskuri3 = 80 Kuinka se toimii Kaksi ensimmäistä lausetta esittelee ja määrittelee kaksi kokonaislukumuuttujaa laskuri1 ja laskuri2. Niiden alkuarvoiksi alustetaan 10 ja 50: int laskuri1 = 10; int laskuri3 = 50; Nämä molemmat muuttujat ovat olemassa tästä kohdasta eteenpäin ohjelman päättävään aaltosulkeeseen saakka. Näiden muuttujien näkyvyysalue ulottuu siis funktion main() loppuun. Muista, että muuttujan elinaika ja näkyvyysalue ovat kaksi eri asiaa. On tärkeää, ettet sekoita näitä kahta käsitettä. Muuttujien määrittelyn jälkeen tulostetaan muuttujan laskuri1 arvo, jolloin muodostuu ensimmäinen yllä esitetyistä riveistä: << "Ulompi laskuri1 = " << laskuri1; Tämän jälkeen tulee toinen avaava aaltosulje, joka aloittaa uuden lohkon. Kaksi muuttujaa, laskuri1 ja laskuri2 määritellään tässä lohkossa. Niiden alkuarvoiksi asetetaan 20 ja 30. Tässä määritelty muuttuja laskuri1 on eri muuttuja kuin ensimmäinen laskuri1. Vaikka ensimmäinen laskuri1 on yhä olemassa, toinen laskuri1 peittää sen nimen. Kaikki viittaukset nimeen laskuri1 sisemmän lohkon määrittelyn jälkeen viittaa sisemmässä lohkossa määriteltyyn muuttujaan laskuri1. Olemme tässä käyttäneet samaa nimeä kahdesti vain havainnollistaaksemme mitä tapahtuu: se ei ole hyvän ohjelmointityylin mukaista. Saman nimen käyttäminen omissa ohjelmissasi on harhaanjohtavaa ja tarpeetonta ja tuottaa koodia, joka on hyvin virhealtista. Tulostuslauseen tulostuksesta huomaamme, että olemme todellakin käyttäneet sisemmän lohkon muuttujaa laskuri1 - eli sisempien aaltosulkeiden sisällä olevaa: { // Uusi näkyvyysalue alkaa tästä... int laskuri1 = 20; // Tämä piilotta ulomman laskuri1:n int laskuri2 = 30; << "Sisempi laskuri1 = " << laskuri1; Jos olisimme yhä käyttäneet ulompaa muuttujaa laskuri1, lause olisi tulostanut arvon 10. Muuttujan laskuri1 arvoa kasvatetaan tämän jälkeen: laskuri1 += 3; // Tämä muuttaa sisempää laskuri1:tä Lisäys vaikuttaa sisempään muuttujaan, koska ulompi on yhä piilossa. 101
32 C++ Ohjelmoijan käsikirja Muuttujan laskuri3, joka määriteltiin ulommassa lohkossa, lisäys onnistuu kuitenkin normaalisti seuraavalla lauseella: laskuri3 += laskuri2; Tämä havainnollistaa sen, että muuttujat, jotka määrittelimme ulomman lohkon alussa, ovat käytettävissä sisemmässä lohkossa. Ne olisi voitu määritellä myös sisemmän lohkon päättävän aaltosulkeen jälkeenkin, mutta silloin ne eivät olisi käytettävissä kohdassa, jossa nyt käytämme niitä. Sisemmän lohkon päättävän aaltosulkeen jälkeen muuttujat laskuri2 ja laskuri2 häviävät. Muuttujat laskuri1 ja laskuri3 ovat yhä olemassa ulommassa lohkossa ja niiden arvot tulostuvat seuraavalla lauseella, joka havainnollistaa, että muuttujaa laskuri3 todella kasvatettiin sisemmässä lohkossa: << "Ulompi laskuri1 = " << laskuri1 << endl << "Ulompi laskuri3 = " << laskuri3; Jos poistat kommentoinnin seuraavasta rivistä: // << laskuri2;// Poista kommentointi niin saat virheen Ohjelma ei enää käänny normaalisti, koska se yrittää tulostaa muuttujan, joka ei ole enää olemassa. Muuttujan määrittelyjen sijainti Voit vapaasti päättää, mihin sijoitat muuttujiesi määrittelyt. Tärkein valintakriteeri on, millaisen näkyvyysalueen muuttujillesi haluat. Tämän lisäksi muuttujan määrittely tulisi sijoittaa lähelle kohtaa, jossa sitä käytetään ensimmäisen kerran. Sinun tulisi aina kirjoittaa ohjelmasi siten, että ne olisivat mahdollisimman helppolukuisia muillekin ohjelmoijille. Muuttujien määrittelyn sijoittaminen juuri ennen sen ensimmäistä käyttökertaa helpottaa helppolukuisuuden saavuttamista. Muuttujan määrittely voidaan sijoittaa myös ohjelman kaikkien lohkojen ulkopuolelle. Katsotaan, mikä vaikutus tällä on. 102 Globaalit muuttujat Muuttujia, jotka määritellään kaikkien lohkojen ja luokkien ulkopuolella, kutsutaan globaaleiksi ja niiden näkyvyysalue on globaali. Tämä tarkoittaa sitä, että ne ovat käytettävissä kaikissa niiden määrittelykohdan jälkeen olevissa sen lähdetekstitiedoston funktioissa. Jos määrittelet ne aivan alussa, ne ovat käytettävissä kaikkialla tiedostossa. Globaaleilla muuttujilla on oletusarvoisesti staattinen säilytysaika. Globaalit muuttujat ovat olemassa ohjelman suorituksen alusta ohjelman suorituksen päättymiseen saakka. Jos et alusta globaalia muuttujaa, se alustetaan automaattisesti arvolla 0. Globaalisten muuttujien alustus tapahtuu ennen kuin funktion main() suoritus alkaa, joten ne ovat käytettävissä heti kaikkialla näkyvyysalueen koodissa.
33 Perustietotyypit ja laskutoimitukset Alla olevassa kuvassa on lähdetekstitiedoston Esimerkki.cpp sisältö ja nuolet kuvaavat kunkin muuttujan näkyvyysaluetta. Lähdeteksti Esimerkki.cpp l ong ar vo1; int mai n( ) { i nt ar vo2;... { Ar vo2 int arvo3; Ar vo3 }... Ar vo1 } i nt ar vo4; int funktio(int) { l ong ar vo5; i nt ar vo1;... Ar vo1 Ar vo5 Ar vo4 } Muuttujan arvo1, joka on määritelty heti tiedoston alussa, näkyvyysalue on globaali. Samaten muuttujan arvo4, joka määritellään funktion main() jälkeen. Globaalien muuttujien näkyvyysalue alkaa kohdasta, jossa ne määritellään ja päättyy tiedoston loppuun. Vaikka muuttuja arvo4 onkin olemassa suorituksen alkaessa, siihen ei voida viitata funktiossa main(), koska main() ei ole sen näkyvyysalueella. Jos haluat käyttää muuttujaa arvo4 myös main()-funktiossa, sen määrittely tulee siirtää tiedoston alkuun. Muuttujat arvo1 ja arvo4 alustetaan automaattisesti arvolla 0. Näin ei tehdä automaattisten muuttujien kohdalla. Muista, että paikallinen muuttuja arvo1 funktiossa funktio() peittää samannimisen globaalin muuttujan. Koska globaalit muuttujat ovat olemassa ohjelman suorituksen loppuun saakka, mieleesi saattaa tulla kysymys: Miksei kaikkia muuttujia määritellä globaaleiksi, jolloin vältetään kaikki paikallisten muuttujien näkyvyysalueongelmat? Tämä kuulostaa aluksi varsin houkuttelevalta, mutta siitä on niin vakavia haittoja, että ne syrjäyttävät kaikki mahdolliset edut. Oikeat ohjelmat muodostuvat suuresta joukosta lauseita, varsin suuresta joukosta funktioita ja monista muuttujista. Kaikkien niiden määrittely globaaleiksi lisää suuresti vaaraa, että muuttujan arvoa muutetaan virheellisesti. Myös muuttujien nimeäminen muodostuisi varsin hankalaksi. 103
34 C++ Ohjelmoijan käsikirja Ne vievät myöskin muistia koko ohjelman suorituksen ajan. Pitämällä muuttujat paikallisina funktiossa tai lohkossa voit olla varma, että niiden arvo on lähes täydellisesti suojattu ulkopuolisilta. Ne ovat olemassa ja vievät muistia vain niiden määrittelykohdasta eteenpäin päättävään aaltosulkeeseen saakka. Näin koko ohjelman kehitysprosessi tulee helpommaksi hallita. Kokeile itse - Näkyvyysalueoperaattori Kuten olemme nähneet, paikallinen muuttuja voi peittää samannimisen globaalin muuttujan. Globaaliin muuttujaan pääsee kuitenkin käsiksi käyttämällä näkyvyysalueoperaattoria (::), johon törmäsimme jo luvussa 1, kun käsittelimme nimiavaruuksia. Voimme havainnollistaa sen toimintaa uudella versiolla edellisestä esimerkistä: // Esimerkki Näkyvyysalueoperaattori #include <iostream> using namespace std; int laskuri1 = 100; // laskuri1:n globaali versio int main() { // Funktion näkyvyysalue alkaa tästä int laskuri1 = 10; int laskuri3 = 50; << "Ulompi laskuri1 = " << laskuri1; << "Globaali laskuri1 = " << ::laskuri1; { // Uusi näkyvyysalue alkaa tästä... int laskuri1 = 20; // Tämä piilottaa ulomman laskuri1:n int laskuri2 = 30; << "Sisempi laskuri1 = " << laskuri1; << "Globaali laskuri1 = " << ::laskuri1; laskuri1 += 3; // Tämä muuttaa sisempää laskuri1:tä laskuri3 += laskuri2; } //...ja päättyy tähän. << "Ulompi laskuri1 = " << laskuri1 << endl << "Ulompi laskuri3 = " << laskuri3; // << laskuri2; // Poista kommentointi niin saat virheen ; return 0; } // Funktion näkyvyysalue päättyy tähän Jos käännät ja suoritat tämän esimerkin, saat seuraavanlaisen tulostuksen: Ulompi laskuri1 = 10 Globaali laskuri1 = 100 Sisempi laskuri1 = 20 Globaali laskuri1 = 100 Ulompi laskuri1 = 10 Ulompi laskuri3 =
35 Perustietotyypit ja laskutoimitukset Kuinka se toimii Värjätyt rivit kertovat muutokset edelliseen esimerkkiin ja tässä meidän täytyy käsitellä vain niitä. Muuttujan laskuri1 määrittely ennen funktion main() määrittelyä on globaali määrittely, joten periaatteessa se on käytettävissä kaikkialla funktiossa main(). Tämä globaali muuttuja alustetaan määrittelyn yhteydessä arvolla 100: int laskuri1 = 100 // laskuri1:n globaali versio Ohjelmassa on kuitenkin kaksi muutakin laskuri1 nimistä muuttujaa, jotka määritellään funktiossa main(), joten ne peittävät globaalin laskuri1:n. Itse asiassa, sisemmässä lohkossa se peittyy kahdella laskuri1-muuttujalla: sisemmällä ja ulommalla. Ensimmäinen uusi tulostuslause on: int laskuri1 = 10; int laskuri3 = 50; << "Ulompi laskuri1 = " << laskuri1; << "Globaali laskuri1 = " << ::laskuri1; Tässä käytetään näkyvyysalueoperaattoria, jotta kääntäjä varmasti tietää, että halutaan viitata globaaliin laskuri1-muuttujaan, ei paikalliseen. Huomaat tulostetusta arvosta, että tämä toimii. Näkyvyysalueoperaattori toimii myöskin sisemmässä lohkossa, kuten huomaat seuraavan lauseen tulostuksesta: int laskuri1 = 20; // Tämä piilottaa ulomman laskuri1:n int laskuri2 = 30; << "Sisempi laskuri1 = " << laskuri1; << "Globaali laskuri1 = " << ::laskuri1; Tämä tulostaa arvon 100 ja kuten aikaisemminkin, näkyvyysalueoperaattorin avulla pääsemme aina käsiksi globaaliin muuttujaan. Kuten huomaat, operaattorin toiminta on tässä varsin samanlainen kuin luvussa 1. Koska emme kerro operaattorin edessä nimiavaruutta, haluamme, että se etsii nimeä globaalista nimiavaruudesta. Käytämme tätä operaattoria hyvinkin paljon, kun käsittelemme olio-ohjelmointia, jossa sitä käytetään useasti. Käsittelemme myöskin lisää nimiavaruuksista luvussa 10, mm. miten voit luoda omia nimiavaruuksia. Staattiset muuttujat Joskus saatat tarvita muuttujaa, joka on määritelty ja jota käsitellään paikallisesti lohkossa, mutta joka olisi olemassa vielä tämän lohkon jälkeenkin. Toisin sanoen sinun tulee määritellä muuttuja paikalliseksi, mutta antaa sille staattinen säilytysaika. Tämän voit tehdä staticavainsanan avulla. Sen tarve korostuu entisestään, kun käsittelemme funktioita luvussa
36 C++ Ohjelmoijan käsikirja Muuttuja, jonka määrittelet static-avainsanalla, on olemassa koko ohjelman suoritusajan, vaikka se on määritelty lohkossa. Siihen pääsee kuitenkin käsiksi vain tästä lohkosta (tai sen sisällä olevista lohkoista). Sen näkyvyysalue on paikallinen, mutta sen säilytysaika on staattinen. Staattinen muuttuja laskuri määritellään seuraavanlaisella lauseella: static int laskuri; Muuttujat, joilla on staattinen säilytysaika, alustetaan aina automaattisesti, jollet itse niin tee. Äskeinen laskuri-muuttuja alustetaan arvolla 0. Jos et itse anna staattiselle muuttujalle alkuarvoa, se alustetaan aina arvolla 0, muunnettuna muuttujan tyypille sopivaksi. Huomaa, että näin ei tehdä automaattisten muuttujien kohdalla. Jos et erikseen alusta automaattisia muuttujiasi, niiden arvo on roskaa, jonka edellinen ohjelma oli siinä muistipaikassa säilyttänyt. Erikoismuokkausfunktiot Muuttujan määrittelyn yhteydessä voit käyttää kahta erikoismuokkausfunktiota register ja volatile. Muokkausfunktiota register käytetään, kun halutaan kertoa kääntäjälle, että muuttujan on suoritusnopeuden kannalta kriittinen ja se pitäisi sijoittaa rekisteriin (rekisteri on hyvin nopea muistipaikka, joka on erillään varsinaisesta muistista, yleensä prosessorin sisällä). Seuraavassa on esimerkki sen käytöstä: register int indeksi = 0; Tässä pyydämme, että muuttuja indeksi sijoitettaisiin rekisteriin. Kääntäjän ei kuitenkaan tarvitse noudattaa tätä pyyntöä ja monissa kääntäjissä rekisteriä ei käytettäisi tässä tilanteessa. Yleensä sinun ei pitäisi käyttää registeriä ellet ole aivan varma mitä olet tekemässä. Useimmat kääntäjät osaavat paremmin päättää miten rekistereitä käytetään. Muokkausfunktiota volatile käytetään kertomaan, että muuttujan arvoa voidaan muuttaa suoraan jostain ulkoisesta prosessista, kuten keskeytysrutiinista. Tarkoituksena on estää kääntäjän optimoinnit. Jos ohjelma esimerkiksi viittaa ei-volatile -muuttujaan, kääntäjä saattaa voida käyttää jo aikaisemmin rekisteriin tuotua arvoa, eikä enää hakisi muuttujan arvoa muistista. Jos muuttuja on määritelty volatile-tyyppiseksi, sen arvo haetaan joka kerta erikseen. Ulkoisten muuttujien määrittely Näimme jo luvussa 1, että ohjelmat voivat koostua useista lähdetekstitiedostoista ja useimmat ohjelmat näin tekevätkin. Jos sinulla on ohjelma, joka koostuu useammasta lähdetekstitiedostosta, saatat haluta päästä käsiksi globaaliin muuttujaan, joka on määritelty jossain toisessa lähdetekstitiedostossa. Tämän voit tehdä extern-avainsanalla. Oletetaan, että sinulla on yksi lähdetekstitiedosto, joka sisältää seuraavaa: //Tiedosto1.cpp int jaettu_arvo = 100; 106
37 Perustietotyypit ja laskutoimitukset //Muu ohjelmakoodi Jos sinulla on koodia jossain toisessa lähdetekstitiedostossa, jonka pitää päästä käsiksi muuttujaan jaettu_arvo, voit tehdä sen seuraavalla tavalla: //Tiedosto2.cpp extern int jaettu_arvo; //Määritellään muuttuja ulkoiseksi int main() { int paikallinen = jaettu_arvo + 10; //...muuta koodia... } Tässä ensimmäinen lause esittelee muuttujan jaettu_arvo ulkoiseksi, joten se on vain esittely, ei määrittely. Funktiossa main() oleva viittaus muuttujaan jaettu_arvo viittaa lähdetekstitiedostossa Tiedosto1.cpp määriteltyyn muuttujaan. Muuttujalle ei saa antaa alkuarvoa, kun se esitellään ulkoiseksi. Jos kirjoittaisit toisen rivin seuraavasti: extern int jaettu_arvo = 0; //Virhe! Ei ulkoinen esittely Muuttuja määriteltäisiin tässä paikalliseksi ja extern jätettäisiin huomioimatta. Suoritusjärjestys ja laskemissuunta Olemme käsitelleet varsin suuren joukon uusia operaattoreita tässä luvussa, joten tarkastellaan nyt tähän saakka käsittelemiemme operaattoreiden suoritusjärjestystä ja laskemissuuntaa: Operaattori Laskemissuunta Operaattori Laskemissuunta static_cast<>() oikealta jälkiliite ++ jälkiliite -- ~ unaarinen + oikealta unaarinen - etuliite ++ etuliite -- * / % vasemmalta binäärinen + vasemmalta binäärinen - << >> vasemmalta & vasemmalta ^ vasemmalta vasemmalta = op= oikealta Nämä ovat järjestyksessä ensimmäisenä suoritettavasta viimeisenä suoritettavaan ja samalla rivillä on suoritusjärjestyksessä samalla tasolla olevat operaattorit. Suoritusjärjestyksessä samanarvoisten operaattoreiden suoritusjärjestys määräytyy niiden laskemissuunnan mukaan. Kaikkien C++:n operaattoreiden suoritusjärjestys löytyy liitteestä D. 107
38 C++ Ohjelmoijan käsikirja Yhteenveto Tässä luvussa käsittelimme jo hieman monimutkaisempia C++:n laskutoimituksia. Puhuimme myöskin hieman omien tietotyyppien määrittelystä, vaikka tässä luvussa esitetyllä ei olekaan mitään tekemistä omien yleisten tietotyyppien määrittelyn kanssa. Niitä käsittelemme luvussa 11. Käsittelimme seuraavia aiheita: Lausekkeessa voi olla erityyppisiä muuttujia ja vakioita. Kääntäjä suorittaa tarvittaessa tyyppien automaattisen muunnon toiseksi tyypiksi. Automaattinen tyypinmuunnos tehdään myös, jos sijoitusoperaattorin oikealla puolella oleva tyyppi on eri kuin vasemmalla puolella oleva. Tämä saattaa johtaa tiedon häviämiseen, jos vasemmalla puolella oleva tyyppi ei voi sisältää samaa tietomäärää kuin oikealla puolella oleva: esimerkiksi, jos double muunnetaan tyypiksi int tai long muunnetaan tyypiksi short. Perustietotyyppi voidaan eksplisiittisesti muuntaa toiseksi perustietotyypiksi käyttämällä static_cast<>()-avainsanaa. Lohkossa määritelty muuttuja on oletusarvoisesti automaattinen, mikä tarkoittaa sitä, että se on olemassa määrittelykohdastaan sen lohkon loppuun, jossa se määriteltiin. Muuttuja voidaan määritellä staattiseksi static-avainsanalla, jolloin se on olemassa ohjelman koko suorituksen ajan. Siihen päästään kuitenkin käsiksi vain näkyvyysalueella, jossa se määriteltiin. Jos staattiselle muuttujalle ei anneta alkuarvoa, se alustetaan automaattisesti arvolla 0. Muuttuja voidaan määritellä ohjelman kaikkien lohkojen ulkopuolella, jolloin sillä on globaali näkyvyysalue ja staattinen muistin säilytysaika. Muuttujiin, joilla on globaali näkyvyysalue, päästään käsiksi kaikkialta lähdetekstitiedostosta sen kohdan jälkeen, jossa muuttuja määriteltiin. Paikallinen samanniminen muuttuja voi kuitenkin peittää globaalin muuttujan, mutta tällöinkin globaaliin muuttujaan päästään käsiksi näkyvyysalueoperaattorilla (::). typedef-komennolla voidaan määritellä synonyymejä olemassa oleville tyypeille. extern-avainsanalla voidaan viitata globaaliin muuttujaan, joka on määritelty toisessa lähdetekstitiedostossa. 108
39 Harjoituksia Perustietotyypit ja laskutoimitukset 3.1 Tee ohjelma, joka laskee käyttäjän syöttämän luvun (nollasta poikkeava) käänteisluvun (luvun n käänteisluku on 1/n). Ohjelman tulee sijoittaa laskennan tulos double-tyyppiseen muuttujaan ja tulostaa se. 3.2 Tee ohjelma, joka pyytää käyttäjää syöttämään kokonaisluvun desimaalimuodossa. Käännä sen binääriesityksen viimeinen bitti. Eli jos viimeinen bitti on 1, muuta se 0:ksi ja päinvastoin. Tulos tulee tulostaa desimaalimuodossa. Miten muutos vaikuttaa kokonaisluvun arvoon? (Vihje: käytä bittioperaattoria.) 3.3 Tee ohjelma, joka laskee, kuinka monta neliön muotoista laatikkoa voidaan sijoittaa yhdelle suorakaiteen muotoiselle hyllylle. Laatikot eivät saa tulla hyllyn ulkopuolelle. Käytä double-tyyppisiä muuttujia hyllyn pituudelle ja syvyydelle (jaloissa) sekä laatikon yhden sivun pituudelle (tuumissa). Määrittele ja alusta vakio, jonka avulla muunnat jalat tuumiksi. Laske yhdessä lausekkeessa hyllylle sijoitettavien laatikoiden maksimimäärä ja sijoita tulos longtyyppiseen muuttujaan. 3.4 Saatko selville, mitä seuraava ohjelmanpätkä saa aikaan, ilman että suoritat sitä? unsigned int k = 430U; unsigned int j = (k >> 4) & ~(~0 << 3); cout << j; 109
40 110 C++ Ohjelmoijan käsikirja
Perustietotyypit ja laskutoimitukset
Perustietotyypit ja laskutoimitukset 2 Perustietotyypit ja laskutoimitukset Tässä luvussa käsittelemme C++:n perustietotyyppejä, varsinkin sellaisia kuin sinä mitä todennäköisemmin tulet käyttämään omissa
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
Kappale 20: Kantaluvut
Kappale 20: Kantaluvut 20 Johdanto: Kantaluvut... 328 Kantalukujen syöttäminen ja muuntaminen... 329 Matemaattiset toiminnot Hex- ja Bin-luvuilla... 330 Bittien vertaileminen ja manipulointi... 331 Huom!
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
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,
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
Tietueet. Tietueiden määrittely
Tietueet Tietueiden määrittely Tietue on tietorakenne, joka kokoaa yhteen eri tyyppistä tietoa yhdeksi asiakokonaisuudeksi. Tähän kokonaisuuteen voidaan viitata yhteisellä nimellä. Auttaa ohjelmoijaa järjestelemään
Osoittimet. Mikä on osoitin?
Osoittimet 7 Osoittimet On aika siirtyä käsittelemään osoittimia, C++:lle elintärkeätä ominaisuutta. Osoittimet ovat tärkeitä, koska ne luovat perustan muistin dynaamiselle varaukselle ja käytölle. Ne
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
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
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
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
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
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,
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
811120P Diskreetit rakenteet
811120P Diskreetit rakenteet 2016-2017 2. Lukujen esittäminen ja aritmetiikka 2.1 Kantajärjestelmät ja lukujen esittäminen Käytettävät lukujoukot: Luonnolliset luvut IN = {0,1,2,3,... } Positiiviset kokonaisluvut
Virtuaalifunktiot ja polymorfismi
Virtuaalifunktiot ja polymorfismi 16 Virtuaalifunktiot ja polymorfismi Polymorfismi on niin tehokas olio-ohjelmoinnin ominaisuus, että tulet varmastikin käyttämään sitä lähes kaikissa C++-ohjelmissasi.
Ohjelmointi 2. Jussi Pohjolainen. TAMK» Tieto- ja viestintäteknologia , Jussi Pohjolainen TAMPEREEN AMMATTIKORKEAKOULU
Ohjelmointi 2 Jussi Pohjolainen TAMK» Tieto- ja viestintäteknologia Tietotyypeistä C++ - kielessä useita tietotyyppejä Kirjaimet: char, wchar_t Kokonaisluvut: short, int, long Liukuluvut: float, double
Moduli 4: Moniulotteiset taulukot & Bittioperaatiot
C! : Moniulotteiset taulukot & Bittioperaatiot 15.3.2016 Agenda Pieni kertausharjoitus Moniulotteiset taulukot Esimerkki taulukoista Tauko (bittitehtävä) Binäärioperaatioista Esimerkki (vilkaistaan IP
Datatähti 2019 loppu
Datatähti 2019 loppu task type time limit memory limit A Summa standard 1.00 s 512 MB B Bittijono standard 1.00 s 512 MB C Auringonlasku standard 1.00 s 512 MB D Binääripuu standard 1.00 s 512 MB E Funktio
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
815338A Ohjelmointikielten periaatteet Harjoitus 4 vastaukset
815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 4 vastaukset Harjoituksen aiheena ovat imperatiivisten kielten lauseisiin, lausekkeisiin ja aliohjelmiin liittyvät kysymykset. Tehtävä 1. Mitä
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,
Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö C-ohjelmassa
ssa ohjelman käytössä suoritusaikana oleva muisti jakautuu neljään osaan: koodisegmentti datasegmentti pinosegmentti (stack) kasa (heap) ssa ohjelman koodisegmentti sisältää käännetyn ohjelmakoodin sisältö
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.
Valinnat ja päätökset
Valinnat ja päätökset 4 Valinnat ja päätökset Päätöksenteko on erittäin tärkeässä asemassa kaikissa ohjelmointikielissä. Jos ohjelman lauseiden suoritusjärjestystä ei voitaisi muuttaa tietojen vertailun
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
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
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
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ä.
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
C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.
Taulukot C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa. Taulukon muuttujilla (muistipaikoilla) on yhteinen nimi. Jokaiseen yksittäiseen
Avaa ohjelma ja tarvittaessa Tiedosto -> Uusi kilpailutiedosto
Condess ratamestariohjelman käyttö Aloitus ja alkumäärittelyt Avaa ohjelma ja tarvittaessa Tiedosto -> Uusi kilpailutiedosto Kun kysytään kilpailun nimeä, syötä kuvaava nimi. Samaa nimeä käytetään oletuksena
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.
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
Sisällys. 6. Muuttujat ja Java. Muuttujien nimeäminen. Muuttujien nimeäminen. Muuttujien nimeäminen. Muuttujan tyypin määritys. Javan tietotyypit:
Sisällys 6. Muuttujat ja Java Muuttujien nimeäminen. Muuttujan tyypin määritys. Javan tietotyypit: Kokonais- ja liukuluvut, merkit, totuusarvot. Tyyppien yhteensopivuus. Viitetietotyypit ja merkkijonotietotyyppi
Binäärioperaatiot Tiedostot ja I/O
C! Binäärioperaatiot Tiedostot ja I/O 8.3.2018 Tiedotteita Viimeinen luento to 29.3. Ohjelmointitehtävä, ohjelmointikoe ja niiden järjestelyt Ohjelmointikokeeseen ilmoittautuminen auki 2 .c tiedostot ja.h
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
Algoritmit 1. Demot Timo Männikkö
Algoritmit 1 Demot 1 31.1.-1.2.2018 Timo Männikkö Tehtävä 1 (a) Algoritmi, joka tutkii onko kokonaisluku tasan jaollinen jollain toisella kokonaisluvulla siten, että ei käytetä lainkaan jakolaskuja Jaettava
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
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
7. Näytölle tulostaminen 7.1
7. Näytölle tulostaminen 7.1 Sisällys System.out.println- ja System.out.print-operaatiot. Tulostus erikoismerkeillä. Edistyneempää tulosteiden muotoilua. 7.2 Tulostusoperaatiot System.out.println-operaatio
Harjoitustyö: virtuaalikone
Harjoitustyö: virtuaalikone Toteuta alla kuvattu virtuaalikone yksinkertaiselle olio-orientoituneelle skriptauskielelle. Paketissa on testaamista varten mukana kaksi lyhyttä ohjelmaa. Ohjeita Noudata ohjelman
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,
Sisällys. 6. Muuttujat ja Java. Muuttujien nimeäminen. Muuttujien nimeäminen. salinovi tai syntymapaiva
Sisällys 6. Muuttujat ja Java Muuttujien nimeäminen. Muuttujan tyypin määritys. Javan tietotyypit: Kokonais- ja liukuluvut. boolean- ja char-tyypit. Tyyppien yhteensopivuus. Viitetietotyypit ja merkkijonotietotyyppi
6. Muuttujat ja Java 6.1
6. Muuttujat ja Java 6.1 Sisällys Muuttujien nimeäminen. Muuttujan tyypin määritys. Javan tietotyypit: Kokonais- ja liukuluvut. boolean- ja char-tyypit. Tyyppien yhteensopivuus. Viitetietotyypit ja merkkijonotietotyyppi
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
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
KAAVAT. Sisällysluettelo
Excel 2013 Kaavat Sisällysluettelo KAAVAT KAAVAT... 1 Kaavan tekeminen... 2 Kaavan tekeminen osoittamalla... 2 Kaavan kopioiminen... 3 Kaavan kirjoittaminen... 3 Summa-funktion lisääminen... 4 Suorat eli
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
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.
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:
Ohjelmoinnin peruskurssi Y1
Ohjelmoinnin peruskurssi Y1 CSE-A1111 30.9.2015 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 1 / 27 Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute.
Sisällys. 6. Muuttujat ja Java. Muuttujien nimeäminen. Muuttujien nimeäminen. salinovi tai syntymapaiva
Sisällys 6. Muuttujat ja Java Muuttujien nimeäminen. Muuttujan tyypin määritys. Javan tietotyypit: Kokonais- ja liukuluvut, merkit, totuusarvot. Tyyppien yhteensopivuus. Viitetietotyypit ja merkkijonotietotyyppi
6. Muuttujat ja Java 6.1
6. Muuttujat ja Java 6.1 Sisällys Muuttujien nimeäminen. Muuttujan tyypin määritys. Javan tietotyypit: Kokonais- ja liukuluvut, merkit, totuusarvot. Tyyppien yhteensopivuus. Viitetietotyypit ja merkkijonotietotyyppi
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.
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
OHJ-1010 Tietotekniikan perusteet 4 op Syksy 2012
OHJ-1010 Tietotekniikan perusteet 4 op Syksy 2012 Luento 6: Tiedon esittäminen tietokoneessa, osa 1 Tekijät: Antti Virtanen, Timo Lehtonen, Matti Kujala, Kirsti Ala-Mutka, Petri M. Gerdt et al. Luennon
Taulukkolaskentaa selkokielellä EXCEL
Taso 1 1 MICROSOFT Taulukkolaskentaa selkokielellä EXCEL Tuomas Seitsemän veljeksen Tuomas on vakaa ja vahva kuin tammi. Hänellä ei ole juuri mielikuvitusta, hän ei keksi mitään itse, vaan ideat tulevat
PERUSLASKUJA. Kirjoita muuten sama, mutta ota välilyönti 4:n jälkeen 3/4 +5^2
PERUSLASKUJA Matemaattisten lausekkeiden syöttäminen: Kirjoita ilman välilyöntejä /+^2 Kirjoita muuten sama, mutta ota välilyönti :n jälkeen / +^2 Kopioi molemmat matematiikka-alueet ja liiku alueen sisällä
5.6. C-kielen perusteet, osa 6/8, Taulukko 6.1.2008, pva, kuvat jma
5.6. C-kielen perusteet, osa 6/8, Taulukko 6.1.2008, pva, kuvat jma Every cloud has a silver line. - englantilainen sananlasku Tässä osiossa tärkeää: yksi- ja moniulotteinen taulukko Sisältö Yleistä Yksiulotteinen
Ohjelman virheet ja poikkeusten käsittely
Ohjelman virheet ja poikkeusten käsittely 17 Ohjelman virheet ja poikkeusten käsittely Poikkeukset ovat tapa ilmoittaa virheistä ja odottamattomista tilanteista C++-ohjelmassasi. Poikkeusten käyttö virheiden
Osa. Listaus 2.1. HELLO.CPP esittelee C++ -ohjelman osat. 14: #include <iostream.h> 15: 16: int main() 17: {
Osa I 2. oppitunti C++-ohjelman osat Ennen kuin menemme yksityiskohtaisemmin sisälle C++-luokkiin, -muuttujiin jne, katsokaamme ensin, millaisista osista C++-ohjelma koostuu. Tämän tunnin aikana opit seuraavat
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
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
Taulukot. Jukka Harju, Jukka Juslin 2006 1
Taulukot Jukka Harju, Jukka Juslin 2006 1 Taulukot Taulukot ovat olioita, jotka auttavat organisoimaan suuria määriä tietoa. Käsittelylistalla on: Taulukon tekeminen ja käyttö Rajojen tarkastus ja kapasiteetti
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
Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:
Merkkijonot C-kielessä merkkijono on taulukko, jonka alkiot ovat char -tyyppiä. Taulukon viimeiseksi merkiksi tulee merkki '\0', joka ilmaisee merkkijonon loppumisen. Merkkijono määritellään kuten muutkin
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.
Mallit standardi mallikirjasto parametroitu tyyppi
Mallit 18 Mallit Malli on tehokas mekanismi uusien luokkien generoimiseksi automaattisesti. Standardikirjaston suuri osa, standardi mallikirjasto, rakentuu kokonaan mallien määrittelymahdollisuuden ympärille,
Luku 8. Aluekyselyt. 8.1 Summataulukko
Luku 8 Aluekyselyt Aluekysely on tiettyä taulukon väliä koskeva kysely. Tyypillisiä aluekyselyitä ovat, mikä on taulukon välin lukujen summa tai pienin luku välillä. Esimerkiksi seuraavassa taulukossa
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,
Lukujärjestelmät. Digitaalitekniikan matematiikka Luku 9 Sivu 3 (26) Lukujärjestelmät ja lukujen esittäminen Fe
Digitaalitekniikan matematiikka Luku 9 Sivu 3 (26) Lukujärjestelmät ja lukujen esittäminen.9.2 Fe Lukujärjestelmät Kymmen- eli desimaalijärjestelmä: kantaluku perinteisesti käytetty ja tuttu numerot,,
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,
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 9.2.2009 T-106.1208 Ohjelmoinnin perusteet Y 9.2.2009 1 / 35 Listat Esimerkki: halutaan kirjoittaa ohjelma, joka lukee käyttäjältä 30 lämpötilaa. Kun lämpötilat
Luennon sisältö Tyypit int, char, float, double signed, unsigned short, long Vakiot const Rakenteet if, for, while, switch, do-while Syöttö ja tulostu
C-kurssi Viikko 1: tyypit, rakenteet, makrot Luennon sisältö Tyypit int, char, float, double signed, unsigned short, long Vakiot const Rakenteet if, for, while, switch, do-while Syöttö ja tulostus Makrot
SISÄLLYS - DIGITAALITEKNIIKKA
SISÄLLYS - DIGITAALITEKNIIKKA Digitaalitekniikan perusteita...2 Bitti (bit)...2 Tavu (bytes)...2 Sana (word)...2 Yksiköt...2 Binääri järjestelmän laskutapa...2 Esimerkki: Digikuvan siirron kestoaika...2
Tietotekniikan valintakoe
Jyväskylän yliopisto Tietotekniikan laitos Tietotekniikan valintakoe 2..22 Vastaa kahteen seuraavista kolmesta tehtävästä. Kukin tehtävä arvostellaan kokonaislukuasteikolla - 25. Jos vastaat useampaan
Taulukkolaskennan perusteet Taulukkolaskentaohjelmat
Taulukkolaskennan perusteet Taulukkolaskentaohjelmat MS Excel ja LO Calc H6: Lomakkeen solujen visuaalisten ja sisältöominaisuuksien käsittely ja soluviittausten perusteet Taulukkolaskennan perusteita
Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005
Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Tällä luennolla Algebralliset tietotyypit Hahmonsovitus (pattern matching) Primitiivirekursio Esimerkkinä binäärinen hakupuu Muistattehan...
Tietojen syöttäminen ohjelmalle. Tietojen syöttäminen ohjelmalle Scanner-luokan avulla
Tietojen syöttäminen ohjelmalle Tähän mennessä on käsitelty Javan tulostuslauseet System.out.print ja System.out.println sekä ohjelman perusrakenneosat (muuttujat, vakiot, lauseet). Jotta päästään tekemään
Yhtälönratkaisu oppilaan materiaali
Yhtälönratkaisu oppilaan materiaali Nimi: Luokka: 1 1. Tosia ja epätosia väitteitä Alkupalat Kirjoita taulukkoon T, jos väite on tosi ja E, jos väite on epätosi. Väite 5 > 3 16 < 8 19 = 26 9 < 28 64 =
Binäärioperaatiot Tiedostot ja I/O
C! Binäärioperaatiot Tiedostot ja I/O 16.3.2017 Tiedotteita Määräaikoja pidennetty Myös 7. kierros uudestaan auki perjantaihin asti Seuraava ja viimeinen luento 30.3. Makrot, funktio-osoittimet Kokeen
Ohjelmoijan binaarialgebra ja heksaluvut
Paavo Räisänen Ohjelmoijan binaarialgebra ja heksaluvut www.ohjelmoinaan.net Tätä opasta saa vapaasti kopioida, tulostaa ja levittää ei kaupallisissa tarkoituksissa. Kuitenkaan omille nettisivuille opasta
Toinen harjoitustyö. ASCII-grafiikkaa
Toinen harjoitustyö ASCII-grafiikkaa Yleistä Tehtävä: tee Javalla ASCII-merkkeinä esitettyä grafiikkaa käsittelevä ASCIIArt-ohjelma omia operaatioita ja taulukoita käyttäen. Työ tehdään pääosin itse. Ideoita
2.3 Virheitä muunnosten käytössä
2.3 Virheitä muunnosten käytössä Esimerkissä 1 yhtälönratkaisuprosessi näytetään kokonaisuudessaan. Yhtälön rinnalla ovat muunnokset ja sanallinen selitys, johon oppilaat täydentävät esimerkissä käytetyt
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
Condes. Quick Start opas. Suunnistuksen ratamestariohjelmisto. Versio 7. Quick Start - opas Condes 7. olfellows www.olfellows.net 1.
Condes Suunnistuksen ratamestariohjelmisto Versio 7 Quick Start opas Yhteystiedot: olfellows Jouni Laaksonen Poijukuja 4 21120 RAISIO [email protected] www.olfellows.net olfellows www.olfellows.net
Ohjelmoinnin perusteet Y Python
Ohjelmoinnin perusteet Y Python T-106.1208 3.2.2010 T-106.1208 Ohjelmoinnin perusteet Y 3.2.2010 1 / 36 Esimerkki: asunnon välityspalkkio Kirjoitetaan ohjelma, joka laskee kiinteistönvälittäjän asunnon
Taulukkolaskennan perusteet Taulukkolaskentaohjelmat
Taulukkolaskennan perusteet Taulukkolaskentaohjelmat MS Excel ja LO Calc H6: Lomakkeen solujen visuaalisten ja sisältöominaisuuksien käsittely ja soluviittausten perusteet Taulukkolaskennan perusteita
plot(f(x), x=-5..5, y=-10..10)
[] Jokaisen suoritettavan rivin loppuun ; [] Desimaalierotin Maplessa on piste. [] Kommentteja koodin sekaan voi laittaa # -merkin avulla. Esim. #kommentti tähän [] Edelliseen tulokseen voi viitata merkillä
13 Operaattoreiden ylimäärittelyjä
248 13 C++-kielessä voidaan operaattoreita ylimäärittää. Ylimääriteltävää operaattoria voidaan pitää ikäänkuin metodina, joka esitellään luokan esittelyssä ja määritellään luokan ulkopuolella kuten metoditkin.
Ohjeet Google kalenteriin. Kirjaudu palveluun saamillasi tunnuksilla
Ohjeet Google kalenteriin Kirjaudu palveluun saamillasi tunnuksilla Valitse käyttämäsi kalenteri Kalenterivaihtoehtojen vieressä oleva värillinen ruutu ilmaisee näytetäänkö kalenterin tiedot. Tapahtuman
Digitaalitekniikan matematiikka Luku 10 Sivu 1 (14) Lukujärjestelmämuunnokset. 2 s s
Digitaalitekniikan matematiikka Luku 10 Sivu 1 (14) k 10 2 10 2 s 10 10 8 10 16 10 2 10 2 s 2 8 8 2 2 16 16 2 Digitaalitekniikan matematiikka Luku 10 Sivu 2 (14) Johdanto Tässä luvussa perustellaan, miksi
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,
Matematiikan tukikurssi, kurssikerta 3
Matematiikan tukikurssi, kurssikerta 3 1 Epäyhtälöitä Aivan aluksi lienee syytä esittää luvun itseisarvon määritelmä: { x kun x 0 x = x kun x < 0 Siispä esimerkiksi 10 = 10 ja 10 = 10. Seuraavaksi listaus
8.1 Murtoluvun määritelmä - murtoluvulla tarkoitetaan aina osaa (osia) jostakin kokonaisuudesta
8. Murtoluvun määritelmä - murtoluvulla tarkoitetaan aina osaa (osia) jostakin kokonaisuudesta - oheisessa kuvassa ympyrä on jaettu kolmeen yhtä suureen osaan, joista kukin osa on yksi kolmasosa koko ympyrästä
