Siirry sisältöön

C++/Muuttujat

Wikikirjastosta
< C++

Tämä luku kertoo muuttujista. Muuttujat ovat nimiä, joilla käsitellään tiettyä paikkaa muistissa. Muuttujalla on nimen lisäksi tyyppi. Muuttuja on määriteltävä ennen kuin sitä voi käyttää. Määrittely tapahtuu näin:

tyyppi nimi;

Tyyppi kertoo minkä tyyppinen muuttuja on (kokonaisluku, merkkijono, jne.). Nimi on yksinkertaisesti nimi jolla muuttujaa kutsutaan. Nimi voi olla mikä tahansa, kunhan se ei ole varattu sana, ei sisällä erikoismerkkejä kuten ääkkösiä, eikä ala numerolla. Kuten C-kielessä, kirjainkoolla on merkitystä. Näin ollen esimerkiksi auto ei ole sama kuin Auto tai auTo. Näin määritellään int-tyyppinen muuttuja:

int luku;

Jos haluat määritellä monta samantyyppistä muuttujaa kerralla, ne voi erotella pilkuilla:

int luku, toinen, kolmas;

Kun muuttuja on esitelty, siihen voi sijoittaa arvoja. Tämä tapahtuu käyttämällä sijoitusoperaattoria, joka on yksi yhtäläisyysmerkki. Muuttujan arvoksi voi sijoittaa myös toisen muuttujan arvon.

luku = 5;
toinen = 2;
luku = toinen; // luku on nyt 2

Muuttujia määriteltäessä voidaan se alustaa jollakin tietyllä arvolla:

int luku = 0;
int toinen = 5, kolmas = 5;

Merkeissä käytetään puolilainausmerkkejä:

char merkki = 'a';

Merkkijonoissa käytetään lainausmerkkejä:

char* merkkijono = "Merkkijono";
std::string toinen = "Merkkijono2";

Koska C-tyyliset merkkijonot ovat vain char-tyyppisiä taulukoita, ne voidaan määritellä myös seuraavasti:

char merkkijono[] = { 'M', 'e', 'r', 'k', 'k', 'i', 'j', 'o', 'n', 'o', '\0' }; 

Muuttujatyypit

[muokkaa | muokkaa wikitekstiä]

C++ sisältää viisi perustyyppiä muuttujille.

Tyyppi Kuvaus
bool totuusarvo
char merkki
int kokonaisluku
float liukuluku
double tarkempi liukuluku

Lisäksi näitä tyyppejä voidaan laajentaa etuliitteillä short, long, signed ja unsigned. Esimerkiksi unsigned int tarkoittaa etumerkitöntä kokonaislukua, joten se voi olla vain positiivinen. Kun listaamme kaikki mahdolliset muuttujatyypit, saamme alla olevan listan. Muuttujien arvoalueet ovat suuntaa antavia. Todellisuudessa arvoalueet ovat järjestelmäriippuvaisia, koska eri arkkitehtuureilla muuttujatyypit vievät eri määrän tavuja. Oikean muuttujan vaatiman tavujen määrän saa selville sizeof()-operaattorilla.

Tyyppi Kuvaus Arvoalue
bool totuusarvo 0…1 (false tai true)
char merkki −128…127
unsigned char etumerkitön merkki 0…255
signed char etumerkillinen merkki −128…127
int kokonaisluku −32768…32767
unsigned int etumerkitön kokonaisluku 0…65535
signed int etumerkillinen kokonaisluku −32768…32767
short int lyhyt kokonaisluku −32768…32767
unsigned short int etumerkitön lyhyt kokonaisluku 0…65535
signed short int etumerkillinen lyhyt kokonaisluku −32768…32767
long int suuri kokonaisluku −2147483648…2147483647
unsigned long int etumerkitön pitkä kokonaisluku 0…4294967295
signed long int etumerkillinen pitkä kokonaisluku −2147483648…2147483647
float liukuluku 1,2E−38…3,4E38
double tarkempi liukuluku 2,2E−308…1,8E308
long double suuri tarkempi liukuluku 2,2E−308…1,8E308
long long erittäin pitkä kokonaisluku −9223372036854775808…9223372036854775807
unsigned long long etumerkitön erittäin pitkä kokonaisluku 0…18446744073709551615

Lyhyet ja pitkät kokonaisluvut short int ja long int voidaan vaihtoehtoisesti kirjoittaa myös short ja long.

C++ sisältää kuusi operaattoria joiden avulla muuttujia ja muita arvoja voi vertailla toisiinsa.

Operaattori Kuvaus
== yhtäläisyys
!= eri suuri kuin
< pienempi kuin
<= pienempi tai yhtä suuri kuin
> suurempi kuin
>= suurempi tai yhtä suuri kuin

Nämä operaattorit palauttavat totuusarvon joka kertoo, onko vertailun tulos tosi vai epätosi. Jos vertailu pitää paikkansa, palautetaan true (1, tosi), ja false (0, epätosi), jos vertailu ei pidä paikkaansa. Huomaa, että operaattori joka vertaa yhtäsuuruutta on == eikä =, joka on sijoitusoperaattori.

(4 == 4) // tosi
(2 == 4) // epätosi
(2 < 4)  // tosi

// 
// Muuttujia voi vertailla samalla tavalla
//

int muuttuja, toinen;
muuttuja = 7;
toinen = 5;

(muuttuja == toinen) // epätosi
(muuttuja >= toinen) // tosi

// 
// Seuraava vertailu olisi virheellinen, sillä yhtäläisyysmerkkiä
// käytetään sijoitusoperaattorina, ei vertailussa.
//

(muuttuja = 4) // VIRHE!

Tyyppimuunnokset

[muokkaa | muokkaa wikitekstiä]

Tyyppimuunnos tarkoittaa muuttujan tyypin muuttamista joksikin toiseksi. Koska C++ on staattisesti tyypitetty kieli, et voi käyttää samaa muuttujatyyppiä kaikissa tilanteissa, vaan joudut tekemään tyyppimuunnoksia. Jotkut funktiot saattavat vaatia parametreikseen int-tyyppisen muuttujan, jolloin saatat joutua muuntamaan esimerkiksi float-muuttujan int-tyypiksi.

Tyyppimuunnokset voivat aiheuttaa tarkkuuden menetystä. Jos muunnat esimerkiksi double-muuttujan tyypiksi int, menetät kaikki desimaalit, koska int pystyy sisältämään vain kokonaislukuja.

C-tyyliset tyyppimuunnokset

[muokkaa | muokkaa wikitekstiä]

Voit tehdä C-tyylisen tyyppimuunnoksen laittamalla muuttujan eteen sulkuihin tyypin, johon haluat muuntaa:

tyyppi muuttuja = (tyyppi)muutettava;

Alla on esimerkkejä erilaisista tyyppimuunnoksista.

int kokonaisluku = 5;
float liukuluku = 1.6;
char merkki = 'c';

int toinenluku = (int)merkki;
liukuluku = (float)kokonaisluku;
kokonaisluku = (int)liukuluku;

C++-tyyliset tyyppimuunnokset

[muokkaa | muokkaa wikitekstiä]

C++ tukee C-tyylisiä tyyppimuunnoksia, mutta sisältää muitakin tapoja muuntaa muuttujan tyyppi. Eräs tapa on funktiokutsua muistuttava tyyppimuunnos. Tällainen muunnos vastaa C-tyylistä tyyppimuunnosta.

tyyppi(muutettava)

Alla esimerkkejä tällaisista tyyppimuunnoksista:

int kokonaisluku = 5;
float liukuluku = 1.6;
char merkki = 'c';

int toinenluku = int(merkki);
liukuluku = float(kokonaisluku + toinenluku);
kokonaisluku = int(merkki) + toinenluku;

Joissakin tapauksissa tällaiset tyyppimuunnokset voivat luoda virhetilanteita, eikä niiden käyttöä yleensä suositella. ISO-standardin mukainen C++ määrittelee muitakin tyyppimuunnoksia, jotka ovat turvallisempia kuin vanhat C-tyyliset muunnokset.

Staattinen tyyppimuunnos static_cast-operaattorilla on C++:n normaali tyyppimuunnos. Se tekee puhtaan tyyppimuunnoksen kääntämisvaiheessa, ja toimii melkein samalla tavalla kuin C-tyylinen tyyppimuunnos. Tällaista muunnosta käytetään sellaisten tyyppien kanssa, joille voidaan tehdä myös päinvastainen muunnos.

static_cast<tyyppi>(muutettava)

Esimerkkejä tällaisista tyyppimuunnoksista:

double a = 3.0;
int b = static_cast<int>(a);   // b on nyt 3
int c = static_cast<int>(7.5); // desimaalit häviävät

Toisin kuin C-tyylinen muunnos, static_cast ei varoita vaikka tietotyypin muuntamisessa tapahtuisi tarkkuuden menetystä. Näin käy yllä olevassa esimerkissä, jossa desimaaliluku 7.5 muunnetaan kokonaisluvuksi.

Jos operaattorilla muunnetaan osoitinta, osoitin muunnetaan halutun tyyppiseksi osoittimeksi. Osoittimien kanssa kannattaa kuitenkin olla tarkkana, sillä static_cast ei varmista että osoittimen tyyppi on yhteensopiva sen tyypin kanssa johon muunnetaan. static_cast ei kuitenkaan salli esimerkiksi const-arvon muuntamista muokattavaksi.

dynamic_cast on turvallisempi vaihtoehto static_cast-operaattorille, koska se tekee ajonaikaisen tyyppitarkistuksen, varmistaen että tyyppimuunnos on laillinen. Tästä syystä se on kuitenkin yleensä myös hitaampi. Operaattoria käytetään osoittimien ja viittausten kanssa.

dynamic_cast<tyyppi>(muutettava)

Dynaamista muunnosta kannattaa käyttää kun ei olla varmoja minkä tyyppinen muutettava arvo on. Jos operaattorilla yritetään muuntaa osoitin jonka tyyppi ei ole yhteensopiva, dynamic_cast palauttaa nollaosoittimen. Jos palautettu arvo on siis NULL, tyyppimuunnos ei onnistunut eikä muunnettua arvoa näin ollen voi käyttää. Samassa tilanteessa static_cast ei huomaisi virhettä.

Jos operaattorilla yritetään muuntaa viittausta ja se epäonnistuu, dynamic_cast aiheuttaa poikkeuksen std::bad_cast.

const_cast-operaattorilla voi poistaa tai lisätä vakion const- tai volatile-määreen.

const_cast<tyyppi>(muutettava)

Tämä operaattori on hyödyllinen erityisesti silloin, kun jokin funktio vaatii argumentikseen muuttujan, mutta sille annetaan vakio. Funktio voisi olla esimerkiksi seuraavanlainen:

int tee_jotakin(int &argumentti);

Saattaisit käyttää funktiota toisessa funktiossa esimerkiksi näin:

void kayta_funktiota(const int &luku)
{
    int arvo = tee_jotakin(luku);
}

Tässä tapauksessa kääntäjä ilmoittaa virheestä, koska funktio tee_jotakin saattaisi muuttaa luku-vakion arvoa. Tämä ei tietenkään ole mahdollista, sillä vakioiden arvoja ei voi muuttaa. Ongelman voi korjata helposti poistamalla muuttujan vakioisuuden käyttämällä const_cast-operaattoria ennen kuin arvo syötetään funktiolle.

void kayta_funktiota(const int &luku)
{
    int arvo = tee_jotakin(const_cast<int&>(luku));
}
reinterpret_cast
[muokkaa | muokkaa wikitekstiä]
reinterpret_cast<tyyppi>(muutettava)

Vakiot ovat muuttujia, joiden arvoa ei voi muuttaa. C++:ssa vakioita määritellään avainsanalla const (engl. constant = pysyvä). Vakioita käytetään silloin, kun arvoa kirjoitetaan useita kertoja, mutta sitä ei tarvitse ikinä muuttaa. Muuttuja määritellään vakioksi alustuksen yhteydessä.

const tyyppi nimi = arvo;

Esimerkkejä vakioiden määrittelyistä:

const int luku = 32;
const float liukuluku = 2.47;
const std::string merkkijono = "Päivää.";

Esimerkiksi yllä olevassa koodissa luku-vakion arvoksi on määritelty 32. Tätä arvoa ei voi enää muuttaa. Jos ohjelmoija yrittää muuttaa arvoa, kääntäjä ilmoittaa virheestä.

Muuttujien näkyvyys

[muokkaa | muokkaa wikitekstiä]