Muuttujien, tietotyyppien ja aritmeettisten lausekkeiden käyttäminen C-ohjelmointikielessä

C-ohjelmointikielessä on runsaasti erilaisia matemaattisia operaattoreita, joita voit käyttää datan käsittelyyn. Tässä luvussa luvusta Programming in C, 4. painos, Stephen G. Kochan käsittelee tietotyyppejä int, float, double, char ja _Bool, tietotyyppien muokkaamista short-, long- ja long long-tyypeillä, muuttujien nimeämissääntöjä, perusmatemaattisia operaattoreita ja aritmeettisia lausekkeita sekä tyypinvalintaa.

Luomaamiesi ohjelmien todellista voimaa on niiden tekemä datan manipulointi. Jotta voit todella hyödyntää tätä tehoa, sinun on ymmärrettävä paremmin eri tietotyyppejä, joita voit käyttää, sekä muuttujien luomista ja nimeämistä. C:ssä on runsaasti erilaisia matemaattisia operaattoreita, joita voit käyttää datan käsittelyyn. Tässä luvussa käsitellään mm:

  • Datatyypit int, float, double, char ja _Bool
  • Datatyyppien muokkaaminen short, long, ja long long
  • Muuttujien nimeämissäännöt
  • Perusmatemaattiset matemaattiset operaattorit ja aritmeettiset lausekkeet
  • Tyypin valu

Datatyyppien ja vakioiden ymmärtäminen

Olet jo tutustunut C:n perustietotyyppiin int. Kuten muistat, muuttujaa, joka on ilmoitettu int-tyyppiseksi, voidaan käyttää sisältämään vain kokonaislukuarvoja – eli arvoja, joissa ei ole desimaalilukuja.

C-ohjelmointikielessä on neljä muuta perustietotyyppiä: float, double, char ja _Bool. Float-tyyppiseksi ilmoitettua muuttujaa voidaan käyttää liukulukujen (desimaaleja sisältävien arvojen) tallentamiseen. Double-tyyppi on sama kuin float-tyyppi, mutta sen tarkkuus on noin kaksinkertainen. Char-tietotyyppiä voidaan käyttää yksittäisen merkin, kuten kirjaimen ’a’, numeromerkin ’6’ tai puolipisteen (’;’) tallentamiseen (tästä lisää myöhemmin). Lopuksi _Bool-tietotyyppiä voidaan käyttää vain arvojen 0 tai 1 tallentamiseen. Tämän tyypin muuttujia käytetään on/off-, kyllä/ei- tai true/false-tilanteen ilmaisemiseen. Näitä yksi tai toinen -valintoja kutsutaan myös binäärivalinnoiksi.

C:ssä mikä tahansa luku, yksittäinen merkki tai merkkijono tunnetaan vakiona. Esimerkiksi luku 58 edustaa vakioarvoa kokonaislukuna. Merkkijono ”Ohjelmointi C:llä on hauskaa.\n” on esimerkki vakiomerkkijonosta. Kokonaan vakioarvoista koostuvia lausekkeita kutsutaan vakioilmaisuiksi. Lauseke

128 + 7 - 17

on siis vakioilmaus, koska jokainen lausekkeen termi on vakioarvo. Mutta jos i julistettaisiin kokonaislukumuuttujaksi, lauseke

128 + 7 – i

ei edustaisi vakioilmaisua, koska sen arvo muuttuisi i:n arvon perusteella. Jos i on 10, lauseke on yhtä suuri kuin 125, mutta jos i on 200, lauseke on yhtä suuri kuin -65.

Kokonaislukutyyppi int

C:ssä kokonaislukuvakio koostuu yhden tai useamman numeron sarjasta. Jaksoa edeltävä miinusmerkki osoittaa, että arvo on negatiivinen. Arvot 158, -10 ja 0 ovat kaikki kelvollisia esimerkkejä kokonaislukuvakioista. Numeroiden välissä ei saa olla välilyöntejä, ja arvoja, jotka ovat suurempia kuin 999, ei voi ilmaista pilkulla. (Arvo 12 000 ei siis ole kelvollinen kokonaislukuvakio, vaan se on kirjoitettava muodossa 12000.)

Kaksi C:n erikoismuotoa mahdollistavat kokonaislukuvakioiden ilmaisemisen muussa kuin desimaaliperustassa (perusta 10). Jos kokonaisluvun arvon ensimmäinen numero on 0, kokonaislukua pidetään ilmaistuna oktaalimuodossa – eli 8-alkuisena. Tällöin arvon jäljelle jäävien numeroiden on oltava kelvollisia 8-kantaisia numeroita, joten niiden on oltava 0-7. Jos siis halutaan ilmaista arvo 50 8-alkuisena C:ssä, joka vastaa arvoa 40 desimaalilukuna, käytetään merkintää 050. Vastaavasti oktaalivakio 0177 edustaa desimaaliarvoa 127 (1 × 64 + 7 × 8 + 7). Kokonaislukuarvo voidaan näyttää päätelaitteessa oktaalimuodossa käyttämällä printf()-lauseen muotoilumerkkejä %o muotoilujonossa. Tällöin arvo näytetään oktaalilukuna ilman etunollaa. Muotoilumerkki %#o saa aikaan sen, että oktaaliarvon edessä näytetään johtava nolla.

Jos kokonaislukuvakion edessä on nolla ja kirjain x (joko pieni tai iso), arvoa pidetään ilmaistuna heksadesimaalisena (16-alkuisena) merkintänä. Välittömästi x-kirjaimen jälkeen ovat heksadesimaalisen arvon numerot, jotka voivat koostua numeroista 0-9 ja kirjaimista a-f (tai A-F). Kirjaimet edustavat vastaavasti arvoja 10-15. Jos siis haluat määrittää heksadesimaaliarvon FFEF0D kokonaislukumuuttujaan nimeltä rgbColor, voidaan käyttää lauseketta

rgbColor = 0xFFEF0D;

. Muotoilumerkit %x näyttävät arvon heksadesimaalimuodossa ilman etumerkkiä 0x ja käyttävät pieniä kirjaimia a-f heksadesimaalilukuja varten. Jos haluat näyttää arvon johtavan 0x:n kanssa, käytät muotoilumerkkejä %#x, kuten seuraavassa:

printf ("Color is %#x\n", rgbColor);

Isolla x-kirjaimella, kuten %X tai %#X, voit näyttää johtavan x:n ja sitä seuraavat heksadesimaaliluvut käyttäen isoja kirjaimia.

Tallennuskoot ja -alueet

Jokaiseen arvoon, olipa se sitten merkki, kokonaisluku tai liukuluku, liittyy arvoalue. Tämä vaihteluväli liittyy siihen, kuinka paljon tallennustilaa on varattu tietyn tietotyypin tallentamiseen. Yleensä tätä määrää ei ole määritelty kielessä. Se riippuu yleensä käyttämästäsi tietokoneesta, ja siksi sitä kutsutaan toteutuksesta tai koneesta riippuvaiseksi. Esimerkiksi kokonaisluku voi viedä tietokoneellasi 32 bittiä, tai se voidaan tallentaa 64 bittiin. Sinun ei pitäisi koskaan kirjoittaa ohjelmia, jotka tekevät oletuksia tietotyyppien koosta. Sinulle kuitenkin taataan, että jokaiselle perustietotyypille varataan vähimmäismäärä tallennustilaa. On esimerkiksi taattu, että kokonaislukuarvo tallennetaan vähintään 32 bitin tallennustilaan, joka on ”sanan” koko monissa tietokoneissa.

Liukulukutyyppi float

Muuttujaa, joka on ilmoitettu tyypiltään float, voidaan käyttää sellaisten arvojen tallentamiseen, jotka sisältävät desimaaleja. Liukulukuvakion erottaa desimaalipisteen olemassaolosta. Voit jättää pois numerot ennen desimaalipistettä tai numerot desimaalipisteen jälkeen, mutta et tietenkään voi jättää pois molempia. Arvot 3., 125.8 ja -.0001 ovat kaikki kelvollisia esimerkkejä liukulukuvakioista. Jos haluat näyttää liukulukuarvon päätelaitteessa, käytetään printf-muunnosmerkkejä %f.

Liukulukuvakio voidaan ilmaista myös tieteellisellä merkistöllä. Arvo 1.7e4 on tällä merkintätavalla ilmaistu liukulukuarvo, joka edustaa arvoa 1.7 × 104. Ennen e-kirjainta olevaa arvoa kutsutaan mantissaksi, kun taas sitä seuraavaa arvoa kutsutaan eksponentiksi. Eksponentti, jota voi edeltää valinnainen plus- tai miinusmerkki, edustaa 10:n potenssia, jolla mantissa kerrotaan. Vakion 2,25e-3 tapauksessa 2,25 on siis mantissan arvo ja -3 on eksponentin arvo. Tämä vakio edustaa arvoa 2,25 × 10-3 eli 0,00225. Muuten e-kirjain, joka erottaa mantissan eksponentista, voidaan kirjoittaa joko pienellä tai isolla alkukirjaimella.

Jos haluat näyttää arvon tieteellisessä merkintätavassa, printf()-muotoilujonossa on määriteltävä muotomerkit %e. Printf()-muotoilumerkkien %g avulla voidaan antaa printf()-ohjelman päättää, näytetäänkö liukulukuarvo normaalissa liukulukumerkinnässä vai tieteellisessä merkinnässä. Tämä päätös perustuu eksponentin arvoon: Jos se on pienempi kuin -4 tai suurempi kuin 5, käytetään %e-muotoa (tieteellinen merkintätapa); muussa tapauksessa käytetään %f-muotoa.

Käytä %g-muotomerkkejä liukulukujen näyttämiseen – se tuottaa esteettisesti miellyttävimmän tulosteen.

Heksadesimaalinen liukuvakio koostuu johtavasta 0x:stä tai 0X:stä, jota seuraa yksi tai useampi desimaali- tai heksadesimaaliluku, jota seuraa p tai P, jonka jälkeen seuraa valinnaisesti allekirjoitettu binäärinen eksponentti. Esimerkiksi 0x0.3p10 edustaa arvoa 3/16 × 210 = 0,5.

Lisätty tarkkuustyyppi double

Tyyppi double on hyvin samankaltainen kuin float-tyyppi, mutta sitä käytetään aina, kun float-muuttujan tarjoama alue ei riitä. Muuttujat, jotka on ilmoitettu double-tyyppisiksi, voivat tallentaa noin kaksi kertaa enemmän merkitseviä numeroita kuin float-tyyppiset muuttujat. Useimmat tietokoneet esittävät double-arvoja 64 bittiä käyttäen.

Ellei toisin ilmoiteta, C-kääntäjä pitää kaikkia liukulukuvakioita double-arvoina. Ilmaistaaksesi eksplisiittisesti float-vakion, liitä numeron loppuun joko f tai F seuraavasti:

12.5f

Kaksoisarvon esittämiseen voidaan käyttää muotoilumerkkejä %f, %e tai %g, jotka ovat samoja muotoilumerkkejä, joita käytetään float-arvon esittämiseen.

Yksittäisen merkin tyyppi char

Muuttujaa char voidaan käyttää yksittäisen merkin tallentamiseen.1 Merkkikantainen vakio muodostetaan sulkemalla merkki parin yksinkertaisten lainausmerkkien sisään. Näin ollen ’a’, ’;’ ja ’0’ ovat kaikki kelvollisia esimerkkejä merkkivakioista. Ensimmäinen vakio edustaa kirjainta a, toinen on puolipiste ja kolmas on merkki nolla, joka ei ole sama kuin luku nolla. Älä sekoita merkkivakiota, joka on yksittäinen merkki yksinkertaisten lainausmerkkien sisällä, merkkijonoon, joka on mikä tahansa määrä merkkejä kaksinkertaisten lainausmerkkien sisällä.

Hahmovakio ’\n’ – rivinvaihtomerkki – on kelvollinen merkkivakio, vaikka se näyttääkin olevan ristiriidassa aiemmin mainitun säännön kanssa. Tämä johtuu siitä, että backslash-merkki on C-järjestelmässä erikoismerkki eikä sitä itse asiassa lasketa merkiksi. Toisin sanoen C-kääntäjä käsittelee merkkiä ’\n’ yhtenä merkkinä, vaikka se todellisuudessa muodostuu kahdesta merkistä. On muitakin erikoismerkkejä, jotka aloitetaan backslash-merkillä. Täydellinen luettelo löytyy liitteestä A, ”C-kielen yhteenveto”.

Muotoilumerkkejä %c voidaan käyttää printf()-kutsussa näyttämään char-muuttujan arvo päätelaitteessa.

Bool-tietotyyppi _Bool

_Bool-muuttuja määritellään kielessä riittävän suureksi tallentamaan vain arvot 0 ja 1. Käytettävän muistin tarkkaa määrää ei ole määritelty. _Bool-muuttujia käytetään ohjelmissa, joiden on osoitettava Boole-ehto. Tämäntyyppistä muuttujaa voidaan esimerkiksi käyttää ilmaisemaan, onko kaikki tiedot luettu tiedostosta.

Konvention mukaan 0 ilmaisee väärää arvoa ja 1 oikeaa arvoa. Kun _Bool-muuttujalle annetaan arvo, arvo 0 tallennetaan muuttujan sisälle arvona 0, kun taas kaikki muut kuin nolla-arvot tallennetaan arvona 1.

Jotta _Bool-muuttujien kanssa työskentelyä ohjelmassasi olisi helpompaa, vakio-otsikkotiedosto <stdbool.h> määrittelee arvot bool, true ja false. Esimerkki tästä on esitetty ohjelmassa 5.10A luvussa 5, ”Päätösten tekeminen.”

Ohjelmassa 3.1 käytetään C:n perustietotyyppejä.

Ohjelma 3.1 Perustietotyyppien käyttäminen

Ohjelman 3.1 tulostaminen

integerVar = 100floatingVar = 331.790009doubleVar = 8.440000e+11doubleVar = 8.44e+11charVar = WboolVar = 0;

Ohjelman 3.1 ensimmäinen lauseke.1 julistaa muuttujan integerVar kokonaislukumuuttujaksi ja antaa sille myös alkuarvon 100, ikään kuin sen sijaan olisi käytetty seuraavia kahta lausetta:

int integerVar;integerVar = 100;

Ohjelman ulostulon toisella rivillä huomataan, että floatingVar-muuttujalle annettu arvo 331,79 näytetään todellisuudessa muodossa 331,790009. Todellinen näytetty arvo riippuu itse asiassa käyttämästäsi tietokonejärjestelmästä. Syynä tähän epätarkkuuteen on erityinen tapa, jolla numerot esitetään tietokoneen sisällä. Olet luultavasti törmännyt samantyyppiseen epätarkkuuteen, kun olet käsitellyt lukuja taskulaskimellasi. Jos jaat 1:n kolmella laskimellasi, saat tulokseksi 0,3333333333, ja lopussa on ehkä vielä muutama ylimääräinen kolmonen. Nämä 3:t ovat laskimen likiarvo kolmannekselle. Teoriassa kolmosia pitäisi olla ääretön määrä. Mutta laskimeen mahtuu vain tietty määrä numeroita, joten kone on luonnostaan epätarkka. Samantyyppinen epätarkkuus pätee myös tässä tapauksessa: Tiettyjä liukulukuarvoja ei voida esittää täsmällisesti tietokoneen muistin sisällä.

Kun näytät liukuluku- tai kaksoismuuttujien arvoja, voit valita kolmen eri muodon välillä. %f-merkkejä käytetään arvojen näyttämiseen vakiomuodossa. Ellei toisin sanota, printf() näyttää float- tai double-arvon aina kuuden desimaalin tarkkuudella pyöristettynä. Myöhemmin tässä luvussa näet, miten näytettävien desimaalien määrä valitaan.

%e-merkkejä käytetään näyttämään liuku- tai kaksoismuuttujan arvo tieteellisessä merkintätavassa. Jälleen kerran järjestelmä näyttää automaattisesti kuusi desimaalia.

Merkeillä %g printf()-ohjelma valitsee %f:n ja %e:n välillä ja poistaa myös automaattisesti näytöstä kaikki perässä olevat nollat. Jos desimaalipistettä ei seuraa yhtään numeroa, se ei myöskään näytä sitä.

Viimeisimmässä printf()-lausekkeessa %c-merkkejä käytetään näyttämään yksittäinen merkki ’W’, jonka osoitit muuttujalle charVar, kun muuttujaa julistettiin. Muista, että kun merkkijono (kuten printf()-lausekkeen ensimmäinen argumentti) suljetaan kaksinkertaisten lainausmerkkien sisään, merkkivakio on aina suljettava yksinkertaisten lainausmerkkien sisään.

Viimeisessä printf()-lausekkeessa osoitetaan, että _Bool-muuttujan arvo voidaan näyttää kokonaislukumuodossa olevien merkkien %i avulla.

Tyyppimääritteet: long, long long long, short, unsigned ja signed

Jos määrite long on sijoitettu suoraan int-ilmoituksen eteen, ilmoitetulla kokonaislukumuuttujalla on joissakin tietokonejärjestelmissä laajennettu alue. Esimerkki long int -deklaraatiosta voisi olla

long int factorial;

Tässä deklaroidaan muuttuja factorial pitkäksi kokonaislukumuuttujaksi. Kuten liukulukujen ja kaksoismuuttujien kohdalla, pitkän muuttujan erityinen tarkkuus riippuu tietokonejärjestelmästäsi. Monissa järjestelmissä int:llä ja long int:llä on sama vaihteluväli, ja kumpaakin voidaan käyttää jopa 32 bitin levyisten kokonaislukuarvojen tallentamiseen (231 – 1 eli 2 147 483 647).

Tyyppiä long int oleva vakioarvo muodostetaan liittämällä kokonaislukuvakion loppuun valinnaisesti L-kirjain (iso tai pieni). Luvun ja L:n välissä ei saa olla välilyöntejä. Deklaraatiossa

long int numberOfPoints = 131071100L;

deklaroidaan siis muuttuja numberOfPoints tyypiltään long int, jonka alkuarvo on 131,071,100.

Jos halutaan näyttää pitkän int:n arvo printf()-toiminnon avulla, l-kirjainta käytetään modifiointimerkkinä ennen kokonaislukumuotoilumerkkejä i, o, ja x. Tämä tarkoittaa, että muotoilumerkkejä %li voidaan käyttää pitkän int:n arvon näyttämiseen desimaalimuodossa, merkkejä %lo voidaan käyttää arvon näyttämiseen oktaalimuodossa ja merkkejä %lx voidaan käyttää arvon näyttämiseen heksadesimaalimuodossa.

On olemassa myös pitkä pitkä pitkä kokonaisluku -tietotyyppi, joten

long long int maxAllowedStorage;

ilmoittaa ilmoitetun muuttujan olevan määritellyn laajennetun tarkkuuden omaava muuttuja, jonka leveyden taataan olevan vähintään 64 bittiä. Yksittäisen l-kirjaimen sijasta printf-merkkijonossa käytetään kahta l-kirjainta pitkien pitkien kokonaislukujen esittämiseen, kuten ”%lli”.

Long-määrite on sallittu myös double-ilmoituksen edessä seuraavasti:

long double US_deficit_2004;

Pitkä double-vakio kirjoitetaan liukuvakioina, joiden välittömässä perässä on l-kirjain tai L-kirjain, kuten esimerkiksi

1.234e+7L

Pitkän double-vakiomääritteen esittämiseen käytetään L-määrettä. Näin ollen %Lf näyttää pitkän double-arvon liukulukumerkinnällä, %Le näyttää saman arvon tieteellisessä merkinnässä, ja %Lg kertoo printf()-ohjelmalle, että sen on valittava %Lf:n ja %Le:n välillä.

Määritelmä short, kun se asetetaan int-julistuksen eteen, kertoo C-kääntäjälle, että juuri kyseistä julistettavaa muuttujaa käytetään melko pienten kokonaislukuarvojen tallentamiseen. Lyhyiden muuttujien käytön motiivina on ensisijaisesti muistitilan säästäminen, mikä voi olla ongelma tilanteissa, joissa ohjelma tarvitsee paljon muistia ja käytettävissä olevan muistin määrä on rajallinen.

Jossain koneissa lyhyt int-muuttuja vie puolet vähemmän muistia kuin tavallinen int-muuttuja. Joka tapauksessa on taattu, että short int -muuttujalle varattua tilaa on vähintään 16 bittiä.

C:ssä ei voi kirjoittaa eksplisiittisesti short int -tyyppistä vakiota. Short int -muuttujan näyttämiseksi aseta h-kirjain minkä tahansa normaalin kokonaislukumuunnosmerkin eteen: %hi, %ho tai %hx. Vaihtoehtoisesti voit myös käyttää mitä tahansa kokonaislukumuunnosmerkkiä lyhyiden ints-muuttujien näyttämiseen, koska ne voidaan muuntaa kokonaisluvuiksi, kun ne välitetään argumentteina printf()-rutiinille.

Viimeistä määrittelymerkkiä, joka voidaan sijoittaa int-muuttujan eteen, käytetään silloin, kun kokonaislukumuuttujaa käytetään vain positiivisten lukujen tallentamiseen. Deklaraatio

unsigned int counter;

ilmoittaa kääntäjälle, että muuttujan laskuria käytetään vain positiivisten arvojen tallentamiseen. Rajoittamalla kokonaislukumuuttujan käyttö pelkästään positiivisten kokonaislukujen tallentamiseen, laajennetaan kokonaislukumuuttujan tarkkuutta.

Merkitsemätön int-vakio muodostetaan sijoittamalla kirjain u (tai U) vakion perään seuraavasti:

0x00ffU

Kokonaislukuvakion kirjoittamisessa voi yhdistää kirjaimet u (tai U) ja l (tai L), joten

20000UL

kertoo kääntäjälle, että se käsittelee vakiota 20000 merkitsemättömänä pitkänä.

Kääntäjä käsittelee kokonaislukuvakiota, jota ei seuraa mikään kirjaimista u, U, l tai L ja joka on liian suuri mahtuakseen normaalikokoiseen int-kirjaimeen, unsigned int:nä. Jos se on liian pieni mahtuakseen unsigned int:iin, kääntäjä käsittelee sitä long int:nä. Jos se ei vieläkään mahdu long int:n sisään, kääntäjä tekee siitä unsigned long int:n. Jos se ei mahdu sinne, kääntäjä käsittelee sitä long long int:nä, jos se mahtuu, ja unsigned long long int:nä muuten.

Kun ilmoitat muuttujia tyypiltään long long int, long int, short int tai unsigned int, voit jättää avainsanan int pois. Näin ollen muuttuja counter olisi voitu julistaa vastaavalla tavalla seuraavasti:

unsigned counter;

Voit myös julistaa char-muuttujat merkitsemättömiksi.

Signed-ominaisuutta voidaan käyttää kertomaan kääntäjälle yksiselitteisesti, että tietty muuttuja on merkillinen suure. Sen käyttö on ensisijaisesti char-ilmoituksen edessä, ja sen tarkempi käsittely siirretään lukuun 13, ”Lisää tietotyypeistä.”

Ei hätää, jos keskustelut näistä määritteistä tuntuvat sinulle tässä vaiheessa hieman esoteerisilta. Kirjan myöhemmissä osissa monia näistä eri tyypeistä havainnollistetaan todellisilla ohjelmaesimerkeillä. Luvussa 13 käsitellään tarkemmin tietotyyppejä ja muunnoksia.

Taulukossa 3.1 on yhteenveto perustietotyypeistä ja määritteistä.

Taulukko 3.1 Perustietotyypit