• Ei tuloksia

Table of Contents

N/A
N/A
Info
Lataa
Protected

Academic year: 2022

Jaa "Table of Contents"

Copied!
38
0
0

Kokoteksti

(1)

Tämän materiaalin lähteenä on käytetty osoitteesta http://www.cplusplus.com/doc/tutorial löytyvää “C+

+ Language Tutorial”. Tämän osan tarkoituksena on pääasiassa kerrata C-kielestä tuttuja perusasioita sekä opetella muutama C++-kielen keskeinen asia.

Table of Contents

1 C++-ohjelman rakenne...2

2 Muuttujat ja tietotyypit...3

2.1 Mikä on muuttuja ?...3

2.2 C++:n tietotyypit...4

2.3 Muuttujan nimeäminen, varatut sanat...5

2.4 Muuttujan määrittely...6

2.5 Sijoituslauseesta...6

2.6 C++:n merkkijono string...7

2.7 Totuusarvo-tietotyyppi...7

2.8 Muuttujien näkyvyysalue ...8

2.9 Määritellyt vakiot...9

3 Syöttö- ja tulostusvirrat...9

3.1 Tulostusvirta cout...9

3.2 Syöttövirta cin...10

4 Operaattorit...11

4.1 Sijoitusoperaattori...11

4.2 Aritmeettiset operaattorit (+, -, *, / ja %)...11

4.3 Yhdistetyt aritmeettiset ja sijoitusoperaattorit...12

4.4 Lisäys ja vähennys yhdellä (++ ja --)...12

4.5 Vertailuoperaattorit (==, !=, <, >, <=, >=)...13

4.6 Loogiset operaattorit (&&, || ja !)...14

4.7 Ehdollinen operaattori (?)...14

4.8 Bittioperaattorit (&, |, ~, >>, <<) ...15

4.9 Tyypinmuunnosoperaattori ( ( ) )...15

4.10 Muuttujan koko (sizeof())...16

4.11 Operaattorien suoritusjärjestys eli presedenssi...16

5 Kontrollirakenteet...17

5.1 If - else if - else ...17

5.2 Silmukat...19

5.2.1 While...19

5.2.2 Do-while...19

5.2.3 For...20

5.3 Hyppylauseet...21

(2)

5.3.1 Break...21

5.3.2 Continue...21

5.4 Monivalinta: switch-case...22

6 Funktiot...24

6.1 Arvoparametrillinen funktio...24

6.2 Muuttujaparametrillinen funktio ja osoitin...26

6.3 Viittausparametrillinen funktio (C++)...28

6.4 Funktion ylikuormaus (overloading)...30

7 Taulukko...31

7.1 Perusteita...31

7.2 Taulukko ja osoitin...34

8 Tietue...35

1 C++-ohjelman rakenne

C++-ohjelman rakenne:

#include <iostream>

using namespace std;

int main () {

// ← Tämä on kommenttimerkki.

//Tänne kirjoitetaan ohjelma.

return 0;

}

• Ensimmäisellä rivillä otetaan käyttöön C++:n syöttö- ja tulostuskirjasto iostream*. Huomaa, että C-kielessä käytettyä .h-tarkenninta ei käytetä.

• Toisella rivillä määritellään, että käytetään std-nimiavaruutta (tästä myöhemmin lisää).

• Pääohjelma alkaa aina rivillä int main(). C++:ssa ei tarvitse käyttää void-tietotyyppiä jos

(3)

funktio ei ota parametreja, mutta halutessa voidin voi sulkeisiin kirjoittaa, se ei ole virhe.

Pääohjelman on palautettava arvo (tässä int), eli C++:ssa ei ole sallittua, että paluuarvon tyyppi on void**.

• Varsinainen ohjelmakoodi kirjoitetaan lohkosulkujen { } sisään.

• Pääohjelman on palautettava arvo. Yleinen käytäntö on, että jos ohjelman suoritus onnistui virheittä, palautetaan 0.

• C++:n oma kommenttimerkki on //. Myös C-kielen /* */ kommentti toimii. Edellinen on käyttökelpoinen jos kommentoidaan vain yksi rivi. Pidemmän pätkän kommentoinnissa jälkimmäinen on händimpi.

2 Muuttujat ja tietotyypit

2.1 Mikä on muuttuja ?

Tietokone säilyttää väliaikaista tietoa RAM-muistissa eli keskusmuistissa. Ohjelman suorituksen aikana tietyt muistialueet ovat ohjelman käytössä niin, että sinne voidaan tallentaa tietoa. Muuttuja on yhden tai useamman muistipaikan nimi. Itse muistipaikan fyysinen sijainti vaihtuu joka kerran kun ohjelmaa ajetaan, mutta sen nimi säilyy. Ohjelmoijan ei siis tarvitse välittää siitä, missä fyysisessä muistipaikassa tieto sijaitsee.

Esimerkiksi lauseella:

char c;

Varataan muistista tietotyyppiä char oleva muuttuja ja annetaan sille nimeksi c. Char-tietotyypin koko on aina yksi tavu (byte) ja se sisältää 8 bittiä*. Muiden tietotyyppien koot saattavat vaihdella

** void main(void) on virheellinen määritys. Se on huono ohjelmointitapa myös C-kielessä vaikka monet oppikirjatkin sitä käyttävät.

* Tarkalleen ottaen bittien määrä tavussa vaihtelee sovelluksesta riippuen. Nykyaikaisessa tietokonetekniikassa tavu on

(4)

prosessorista ja käyttöjärjestelmästä riippuen.

8 bitillä voi esittää 28 = 256 eri lukua. Jos luvun etumerkki otetaan huomioon (signed int) meillä on käytössä luvut -128 – +127 ja jos etumerkkiä ei oteta huomioon (unsigned int) luvut 0 - +255.

Tietotyyppi char on siinä mielessä eritysasemassa, että sitä käytetään myös merkkien esittämiseen (vaikka se on siis kokonaislukutyyppi). Se, mikä merkki vastaa mitäkin lukua, määritellään ASCII- kooditaulukon avulla **. Esimerkiksi desimaalilukua 64 vastaa kirjain A, lukua 65 kirjain B jne.

Muistipaikkaan voidaan siis tallentaa tietoa sen nimen perusteella:

c=1;

Sijoitetaan muuttujaan (muistipaikkaan) c luku 1.

c='A';

Sijoitetaan muuttujaan c merkki 'A'. Kertausta C-kielestä: Yksittäiset merkit tulevat aina yksinkertaisten hipsujen ' ' sisään. Merkkijonot tulevat lainausmerkkien “ “ sisään..

2.2 C++:n tietotyypit

Oheiseen taulukkoon on koottu C++:n tietotyyppien nimet, koot tavuina ja lukualueet.

Name Description Size* Range*

char Character or small integer. 1byte signed: -128 to 127

unsigned: 0 to 255 short int

(short) Short Integer. 2bytes signed: -32768 to 32767

unsigned: 0 to 65535

int Integer. 4bytes

signed: -2147483648 to 2147483647

unsigned: 0 to 4294967295 long int

(long) Long integer. 4bytes signed: -2147483648 to

2147483647 kuitenkin aina 8 bittiä.

(5)

unsigned: 0 to 4294967295 bool Boolean value. It can take one of two values: true or

false. 1byte true or false

float Floating point number. 4bytes +/- 3.4e +/- 38 (~7 digits) double Double precision floating point number. 8bytes +/- 1.7e +/- 308 (~15 digits) long double Long double precision floating point number. 8bytes +/- 1.7e +/- 308 (~15 digits) wchar_t Wide character. 2 or 4 bytes 1 wide character

Tietotyypin int koko riippuu järjestelmän sananpituudesta (word length) ja muut tyypit suhteutetaan siihen. Siten 32-bittisissä järjestelmissä int on 4 tavua (4*8=32) ja 64-bittisissä 8 tavua (8*8=64).

2.3 Muuttujan nimeäminen, varatut sanat

Muuttujan nimi saa sisältää vain kirjaimia (skandimerkkejä ei voi käyttää), numeroita 0-9 tai alaviivan _. Nimi ei voi alkaa numerolla ja alaviivan käyttöä ensimmäisenä merkkinä on syytä välttää. C++ on

“case-sensitiivinen” eli isot ja pienet kirjaimet tarkoittavat eri asiaa.

Muuttujia nimetessä ei voi käyttää seuraavia sanoja, jotka ovat C++-kielen varatut sanat (reserved words):

asm, auto, bool, break, case, catch, char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private,

protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using,

virtual, void, volatile, wchar_t, while

(6)

2.4 Muuttujan määrittely

C++:ssa muuttuja on aina määriteltävä (declaration) ennen kuin sitä voi käyttää.

Esim: int a;

float mynumber;

Yhdellä rivillä voidaan määritellä monta samantyyppistä muuttujaa:

int a, b, c;

Muuttuja voidaan alustaa (initialize) eli sille voidaan antaa alkuarvo määrittelyn yhteydessä:

int a = 0, b = 1, c = 2;

int a = b = c = 0;

Ellei muuttujalle anneta arvoa, on muuttujan arvo jokin satunnainen luku, joka sattuu sillä hetkellä olemaan siinä muistipaikassa johon muuttuja kiinnitetään. Muuttujat eivät oletusarvoisesti alustu nollaksi tai mihinkään muuhunkaan arvoon.

Uusi asia: C++:ssa alustus voidaan tehdä myös ns. konstruktorin eli muodostimen avulla. Siten int a(0);

on sama asia kuin:

int a=0;

2.5 Sijoituslauseesta

Muuttujan alustuksen yhteydessä oli esillä merkki =. On syytä muistaa, että merkki = ei C/C++:ssa ole yhtäsuuruusmerkki vaan sijoitusoperaattori. Kahden muuttujan yhtäsuuruutta testataan operaattorilla ==. Näistä lisää myöhemmin. Sijoitusoperaattori toimii oikealta vasemmalle.

Operaattorin oikealla puolella olevan lausekkeen arvo sijoitetaan vasemmalla puolella olevan

(7)

Esim: int a=0; //Sijoitetaan a:n arvoksi 0

a=a+1; //Kasvatetaan a:ta yhdellä. Sijoitetaan uusi arvo a:n arvoksi (a:n arvo on nyt 1).

2.6 C++:n merkkijono string

Merkkijono on merkkien muodostama taulukko, joka koostuu useammasta merkistä. C-kielessä merkkijonon koko oli määriteltävä kiinteäksi:

char merkit[20];

char nimi[ ] = “Robin Hood”;

C++:ssa on käytössä merkkijonotyyppi string, joka käyttäytyy kuten mikä tahansa tietotyyppi (vaikka ei varsinainen perustietotyyppi olekaan).

string merkit;

merkit=”Robin Hood”;

string nimi=”Little John”;

string name(“Monk Tuck”);

String-tyyppisen merkkijonon kokoa ei tarvitse määritellä. Se kasvaa ja pienenee tarpeen mukaan riippuen siitä, kuinka monta merkkiä tarvitaan. Sen kanssa voi käyttää “normaaleja” sijoitus- ja vertailuoperaattoreita. C-kielen funktioita strcmp, strcpy jne ei enää tarvitse käyttää. Ne voi unohtaa.

Merkkijonoihin palataan myöhemmin.

2.7 Totuusarvo-tietotyyppi

C++:ssa on erikseen totuusarvo-tietotyyppi bool, joka voi saada arvon true tai false. False vastaa aina kokonaislukuarvoa nolla (0). True:ksi tulkitaan mikä tahansa nollasta eriävä arvo.

(8)

2.8 Muuttujien näkyvyysalue

Perussääntö on, että muuttuja näkyy siinä lohkossa jossa se on määritelty. Lohko rajautuu aaltosulkeisiin. Siten pääohjelmassa määritelty muuttuja ei näy aliohjelmaan ja toisinpäin. Ohjelma voi sisältää siis monta saman nimistä muuttujaa eri ohjelmalohkoissa. Edellä mainittuun sääntöön on kaksi poikkeusta: Globaalit ja staattiset muuttujat. Globaali muuttuja määritellään ennen pääohjelmaa ja se näkyy kaikkiin ohjelmalohkoihin. Paikallinen saman nimisen muuttujan määritys ohittaa globaalin muuttujan.

Automaattinen muuttuja syntyy, kun tullaan siihen ohjelmalohkoon jossa se on määritelty, ja tuhoutuu nimensä mukaisesti automaattisesti, kun ohjelmalohkosta poistutaan. Ohjelmoijan ei tarvitse huolehtia niiden luomisesta tai tuhoamisesta. Staattinen muuttuja syntyy vain kerrran. Se voidaan määritellä missä kohtaa ohjelmaa tahansa ja on olemassa koko ohjelman suorituksen ajan ja säilyttää arvonsa.

#include <iostream>

using namespace std;

//Globaali x int x=2;

int main() {

//Pääohjelman x int x=1;

{

//Lohkosulkujen rajaama vaikutusalue int x=0;

cout << x << endl;

}

(9)

cout << x << endl;

cout << ::x << endl;

return 0;

}

2.9 Määritellyt vakiot

Vakion arvoa ei voi muuttaa ohjelman ajon aikana. Vakio voidaan määritellä joko #define- direktiivillä tai const-määreellä.

#define PII 3.1415

const float PII=3.1415;

Define on ns. esikääntäjän (preprocessor) direktiivi, joka ei ole osa varsinaista ohjelmakoodia.

Siksi sen käyttö voi johtaa arvaamattomiin tilanteisiin. Const-määreen käyttö on suositeltavampaa.

3 Syöttö- ja tulostusvirrat

3.1 Tulostusvirta cout

C-kielessä opittiin, että näytölle tulostus tapahtuu lauseella printf ja tietojen syöttö näppäimistöltä esimerkiksi lauseilla scanf tai gets. Niiden kanssa piti muistaa kaikkia ikäviä formaattikoodeja.

C++:ssa niitä ei tarvita.

C++:ssa tulostus tapahtuu lauseella cout (“character out”).

cout << "Hello World!" << endl;

(10)

Tulostaa näytölle lainausmerkeissä olevan tekstin. endl (END Line) on rivinvaihto. Myös C-kielen

“\n” toimii edelleen. <<-merkkien sielunelämään palataan myöhemmin. Tässä riittää tietää, että niillä erotetaan tulostettavat tekstit ja ohjausmerkit toisistaan. Esimerkiksi

cout << "Hello" << endl << “World!”;

Tulostaa:

Hello World

3.2 Syöttövirta cin

Tietojen syöttö joltain oheislaitteelta keskusmuistiin muuttujiin tapahtuu lauseella cin (“character in”). Huomaa että samalla rivillä voi olla useamman tiedon luku >> merkeillä erotettuna. Muuttujat erotetaan toisistaan enterillä tai välilyönnillä.

float luku;

string mjono;

cin >> mjono >> luku;

cout << luku << " " << mjono << endl;

Kaikkien numeeristen tietotyyppien, yksittäisten merkkien ja välilyöntejä sisältämättömien merkkijonojen luku onnistuu cin:llä. Jos on tarpeen lukea merkkijono, joka sisältää välilyöntejä on käytettävä getline-funktiota.

getline(cin,mjono);

(11)

4 Operaattorit

Muuttujia ja vakioita käsitellään operaattorien avulla.

4.1 Sijoitusoperaattori

Sijoituksessa = merkin oikealla puolella olevan lausekkeen arvo (ns. rvalue) sijoitetaan vasemmalla puolella olevan muuttujan (lvalue) arvoksi. Vasemmalla puolella on aina oltava muuttuja. Oikealla puolella voi olla vakio, muuttuja tai vaikkapa monimutkainen

matemaattinen lauseke.

a = 2;

b = a+1;

D = sqrt(a*a+b*b);

Sijoituslauseita voi yhdistellä hyvinkin mielipuolisesti:

a = 2 + (b = 5);

a = b = c = 0;

4.2 Aritmeettiset operaattorit (+, -, *, / ja %)

Yhteenlasku +, vähennyslasku -, kertolasku * ja jakolasku / sekä jakojäännös (modulo) %. Muut lienevät selviä. Jakojäännös kertoo sen meneekö kahden luvun jakolasku tasan.

A = 11 % 3;

Muuttuja A saa arvon 2.

(12)

4.3 Yhdistetyt aritmeettiset ja sijoitusoperaattorit

+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=

Suoritetaan ensin aritmeettinen tai bittioperaatio ja tulos sijoitetaan muuttujan arvoksi.

summa += luku;

on sama kuin

summa = summa + luku;

eli ns. karttuva summa.

a -= 5;

on sama kuin

a = a – 5;

4.4 Lisäys ja vähennys yhdellä (++ ja --)

C/C++-kielen ominaisuus on että koodista pyritään tekemään mahdollisimman tiivistä. Siksi on mahdollista käyttää unaarisia operaattoreita ++ ja - - jotka kasvattavat ja pienentävät muuttujan arvoa yhdellä. Seuraavat operaatiot tuottavat saman lopputuloksen:

a = a + 1;

a+=1;

a++;

++a;

Kahden viimeisen ilmauksen kanssa saa olla tarkkana, jos ne sisältyvät sijoituslauseeseen. Sillon pitää

(13)

tietää, missä järjestyksessä eri operaatiot suoritetaan*. B=3;

A=++B; // A contains 4, B contains 4 Kasvatetaan ensin B:tä yhdellä. Lopputulos sijoitetaan A:han.

B=3;

A=B++; // A contains 3, B contains 4 Ensin B:n arvo sijoitetaan A:han. B:tä kasvatetaan yhdellä vasta sitten.

Jos on epävarma, niin suoritusjärjestykseen voi vaikuttaa suluilla. Tai sitten voi käyttää jotain muuta tapaa esittää sama asia (mitenköhän … ?).

4.5 Vertailuoperaattorit (==, !=, <, >, <=, >=)

Vertailuoperaattori palauttaa aina totuusarvon true tai false (koodissa joko 1 tai 0).

(7 == 5) // evaluates to false.

(5 > 4) // evaluates to true.

(3 != 2) // evaluates to true.

(6 >= 6) // evaluates to true.

(5 < 5) // evaluates to false.

a=2;b=3;c=6;

(a == 5) // evaluates to false since a is not equal to 5.

(a*b >= c) // evaluates to true since (2*3 >= 6) is true.

(b+4 > a*c) // evaluates to false since (3+4 > 2*6) is false.

((b=2) == a) // evaluates to true.

Ja sitten vielä kerran muistutus aloittelevan ohjelmoijan tavallisimmasta virheestä. = on sijoitus ja ==

vertailu. Näitten kanssa saa olla tarkkana. Vertailuoperaattoreita käytetään tavallisesti ehtolauseen yhteydessä, mutta siihen palataan hetken kuluttua. Vertailun tulosta voi tutkia kuitenkin ilman ehtolausettakin kirjoittamalla esimerkiksi:

cout << ( 7 == 5); //Tulostaa 0 eli epätosi.

* Operaattorien presedenssi eli suoritusjärjestys on tarkkaan määritelty. Palataan siihen hieman myöhemmin.

(14)

4.6 Loogiset operaattorit (&&, || ja !)

&& on JA-operaattori. Tulos on tosi, jos molemmat operandit ovat tosia. || on TAI-operaattori. Tulos on tosi jos toinen operandi on tosi.

( (5 == 5) && (3 > 6) ) // evaluates to false ( true && false ).

( (5 == 5) || (3 > 6) ) // evaluates to true ( true || false ).

! on EI eli negaatio. Se vaihtaa toden epätodeksi ja päinvastoin. Toimii siis kuin reaalimaailman poliitikko.

!(5 == 5) // evaluates to false because the expression at its right (5 == 5) is true.

!(6 <= 4) // evaluates to true because (6 <= 4) would be false.

!true // evaluates to false

!false // evaluates to true.

4.7 Ehdollinen operaattori (?)

Suorittaa toisen kahdesta vaihtoehdosta riippuen siitä kumpi on tosi. Toimii täsmälleen samoin kuin if- lause.

condition ? result1 : result2;

Siis esimerkiksi:

7==5 ? 4 : 3 // returns 3, since 7 is not equal to 5.

7==5+2 ? 4 : 3 // returns 4, since 7 is equal to 5+2.

5>3 ? a : b // returns the value of a, since 5 is greater than 3.

a>b ? a : b // returns whichever is greater, a or b.

(15)

4.8 Bittioperaattorit (&, |, ~, >>, <<)

Operoivat suoraan bitteihin, joista muuttuja koostuu.

operator asm equivalent description

& AND Bitwise AND

| OR Bitwise Inclusive OR

^ XOR Bitwise Exclusive OR

~ NOT Unary complement (bit inversion)

<< SHL Shift Left

>> SHR Shift Right

unsigned int a=1;

cout << (a<<1) << endl;//2 cout << (a<<2) << endl;//4 cout << (a<<3) << endl;//8 cout << (a<<4) << endl;//16

a=256;

cout << (a>>1) << endl;//128 cout << (a>>2) << endl;//64 cout << (a>>3) << endl;//32 cout << (a>>4) << endl;//16

4.9 Tyypinmuunnosoperaattori ( ( ) )

Muuttujan sisältämä arvo voidaan muuttaa toiseksi tietotyypiksi kesken ohjelmaa. Esimerkiksi:

int i;

float f = 3.14;

i = (int) f;

(16)

Sijoitetaan i:hin f:n sisältö muutettuna kokonaisluvuksi. Muunnoksessa desimaalit häviävät ja tulos on 3.

4.10 Muuttujan koko (sizeof())

Palauttaa parametrina syötetyn tietotyypin tai muuttujan koon tavuina.

a = sizeof (char);

Antaa tulokseksi 1, koska char-tietotyypin koko on yksi tavu.

4.11 Operaattorien suoritusjärjestys eli presedenssi

Oheiseen taulukkoon on koottu, missä järjestyksessä eri operaatiot suoritetaan C++:ssa. Korkeammalla tasolla (prioriteetilla) oleva operaatio suoritetaan ennen.

Level Operator Description Grouping

1 :: scope Left-to-right

2

() [] . -> ++ -- dynamic_cast static_cast reinterpret_cast

const_cast typeid postfix Left-to-right

3

++ -- ~ ! sizeof new delete unary (prefix)

Right-to-left

* & indirection and

reference (pointers)

+ - unary sign operator

4 (type) type casting Right-to-left

5 .* ->* pointer-to-member Left-to-right

6 * / % multiplicative Left-to-right

7 + - additive Left-to-right

(17)

8 << >> shift Left-to-right

9 < > <= >= relational Left-to-right

10 == != equality Left-to-right

11 & bitwise AND Left-to-right

12 ^ bitwise XOR Left-to-right

13 | bitwise OR Left-to-right

14 && logical AND Left-to-right

15 || logical OR Left-to-right

16 ?: conditional Right-to-left

17 = *= /= %= += -= >>= <<= &= ^= |= assignment Right-to-left

18 , comma Left-to-right

Grouping-sarake ilmaisee, missä järjestyksessä samalla tasolla olevat operaattorit suoritetaan jos niitä esiintyy samassa lausekkeessa. Suluilla voidaan muuttaa suoritusjärjestystä tästä taulukosta

poikkeavaksi.

a = 5 + (7 % 2) //Tulos: 6 a = (5 + 7) % 2 //Tulos: 0

5 Kontrollirakenteet

Kontrollirakenteiden avulla ohjelman toiminta haarautuu yhteen tai useampaan suoritettavaan osaan.

Tämä on C-kielen kertausta, joten käydään pikaisesti vain oleelliset asiat läpi.

5.1 If - else if - else

Yksinkertaisin versio:

if (ehto) lauseet;

(18)

Lauseet suoritetaan jos ehto on tosi. Muuten ei tehdä mittään. Seuraavaksi valinta kahdesta eli binäärivalinta:

if (ehto) lauseet1;

else

lauseet2;

Jos ehto on tosi, suoritetaan lauseet1, muuten lauseet2. Ja lopuksi monivalinta:

if (ehto1) lauseet1;

else if (ehto2) lauseet2;

else if (ehto_n) lauseet_n;

else

lauseet;

Käydään vaihtoehtoja läpi niin kauan kuin löytyy tosi. Silloin lopetetaan ja tullaan ulos rakenteesta.

Viimeiseen elseen ei liity koskaan ehtoa. Se suoritetaan jos mikään edellisistä ei ollut tosi.

int x;

cout << "Anna kokonaisluku" << endl;

cin >> x;

if (x%2==0)

cout << "Luku on parillinen" << endl;

else

cout << "Luku on pariton" << endl;

(19)

5.2 Silmukat

5.2.1 While

Lauseita suoritetaan niin kauan kuin ehto on tosi.

while (ehto) lauseet;

Tämä ohjelma laskee kakkosen potensseja käyttäen bittitason siirtämistä vasemmalle.

int x=2,i=0;

while (i<10) {

//Bitwise left shift cout << (x<<i) << endl;

i++;

}

Huomioitava, että jos ehto ei ole voimassa kun ehtoa testataan ensimmäistä kertaa, ei silmukassa käydä kertaakaan.

5.2.2 Do-while

do lauseet while(ehto);

Lauseita suoritetaan jälleen niin kauan kuin ehto on tosi. Sama esimerkki kuin edellä:

(20)

int x=2,i=0;

do {

//Bitwise left shift cout << (x<<i) << endl;

i++;

}

while (i<10);

MUISTA PUOLIPISTE LOPUSSA ! Do-while suoritetaan aina vähintään kerran koska ehto testataan vasta lopussa.

5.2.3 For

for (alkuarvo; ehto; muutos) lauseet;

Käytetään yleensä, kun toistokertojen määrä tiedetään. Muuttujalle asetetaan alkuarvo. Testataan ehto.

Jos tosi, suoritetaan lauseet ja muutetaan alkuarvoa. Testataan muuttunut arvo ehtoa vasten ja jatketaan kunnes tulee epätosi. Jälleen sama esimerkki kuin edellä:

int x=2;

for (int i=0;i<10;i++) {

//Bitwise left shift cout << (x<<i) << endl;

}

C++ lisää for-silmukkaan yhden ominaisuuden, joka ei ole perus-C-kielessä mahdollinen.

Silmukkalaskuri voidaan määritellä ja alustaa for-silmukan sisällä (int i=0...), jolloin siitä tulee silmukan paikallinen muuttuja joka on elossa vain silmukan suorituksen ajan. Tästä on se etu, että ohjelmaan ei jää kummittelemaan muuttujia, joiden arvo saattaa olla aivan eri kuin mitä ohjelmoija

(21)

5.3 Hyppylauseet 5.3.1 Break

Break siirtää ohjelman suorituksen pois suoritettavan olevasta ohjelmalohkosta. Käytetään esimerkiksi virheentarkistukseen silmukassa.

int n;

for (n=10; n>0; n--) {

cout << n << ", ";

if (n==3) {

cout << "countdown aborted!";

break;

} }

5.3.2 Continue

Siirtää suorituksen suoritettavan olevan ohjelmalohkon loppuun, mutta ei ulos sieltä.

for (int n=10; n>0; n--) { if (n==5) continue;

cout << n << ", ";

}

Tämä ohjelma tulostaa luvut 10:stä 1:een mutta skippaa vitosen.

(22)

C++-kielessä on myös goto-lause, mutta sitä ei oikeastaan saa käyttää missään joten sitä ei tässäkään opeteta.

5.4 Monivalinta: switch-case

switch (expression) {

case constant1:

group of statements 1;

break;

case constant2:

group of statements 2;

break;

. . .

default:

default group of statements }

Switch-casen avulla voidaan tehdä päätös useamman vakioarvon väliltä, mitä tehdään. Tyypillinen käyttö oli ennenvanhaan tekstipohjaisissa käyttöliittymissä, jossa esimerkiksi jotain kirjainta painamalla ohjelma teki jotain.

(23)

switch (x) { case 1:

cout << "x is 1";

break;

case 2:

cout << "x is 2";

break;

default:

cout << "value of x unknown";

}

Muutama huomautus. Jokaiseen case-haaraan liittyy break. Default suoritetaan jos mikään case ei toteudu. Switch-casen voi aina korvata if-lauseella:

if (x == 1) {

cout << "x is 1";

}

else if (x == 2) { cout << "x is 2";

}

else {

cout << "value of x unknown";

}

(24)

6 Funktiot

Ohjelma jaetaan yleensä erillisiin kokonaisuuksiin, jotka suorittavat tietyn tehtävän.Näitä ohjelman osia kutsutaan funktioiksi eli aliohjelmiksi. Aliohjelma jakautuu kolmeen osaan:

Esittely eli prototyyppi. Se tehdään ennen pääohjelmaa. Esittelyssä funktiolle annetaan nimi sekä parametrien että paluuarvon tyypit. Suuremmissa ohjelmissa prototyypit kirjoitetaan erilliseen header-tiedostoon.

Runko-osa eli varsinainen aliohjelmakoodi. Jos runko-osa kirjoitetaan ennen pääohjelmaa samaan tiedostoon, ei erillistä esittelyä tarvita.

• Funktion kutsu. Funktiota, aivan kuin ihmistä, kutsutaan sen nimellä.

Funktiolla ei tarvitse välttämättä olla paluuarvoa eikä parametreja. Silloin parametrilista voidaan jättää tyhjäksi. Void-avainsanaa ei välttämättä tarvitse käyttää C++:ssa.

6.1 Arvoparametrillinen funktio

Funktiolle annetut parametrit ovat alkuperäisten muuttujien kopioita. Alkuperäiset muuttujien arvot eivät muutu. Esimerkissä on addition( ) -niminen funktio, joka ottaa parametreina kaksi kokonaislukua a ja b ja palauttaa yhden kokonaisluvun r.

(25)

// function example

#include <iostream>

using namespace std;

int addition (int a, int b) {

int r;

r=a+b;

return (r);

}

int main () {

int z;

z = addition (5,3);

cout << "The result is " << z;

return 0;

}

Tarkemmin ottaen esimerkin arvot 5 ja 3 kopioidaan muuttujien a ja b arvoiksi.

Funktio palauttaa arvon muuttujaan z return-lauseella.

Tässä esimerkki funktiosta, joka ei ota parametreja eikä palauta arvoa:

(26)

#include <iostream>

using namespace std;

void printmessage () {

cout << "I'm a function!";

}

int main () {

printmessage ();

return 0;

}

6.2 Muuttujaparametrillinen funktio ja osoitin

Osoitin on muuttuja, joka sisältää jonkin toisen muuttujan keskusmuistiosoitteen. Osoittimia käsitellään koodissa * ja &-operaattoreilla.

* on sisältöoperaattori

& on viittaus- eli osoiteoperaattori.

Muuttujan määrittely:

tyyppi *osoitin;

Osoittimelle annetaan arvo &-operaattorin avulla:

(27)

int *p;

int c=0;

p=&c;

Viimeinen rivi voidaan suomentaa siten, että “osoitinmuuttujaan p sijoitetaan (tavallisen) muuttujan c keskusmuistiosoite”. Osoitinmuuttajan sisältö ja sen osoittaman muistipaikan (tässä muuttuja c) sisältö (tässä 0) voidaan tulostaa seuraavasti:

cout << "Osoite " << p << " ja sisältö " << *p << endl;

Osoitin, joka ei osoita mihinkään on ns. nollaosoitin (NULL pointer).

Osoittimia käytetään erityisen paljon funktioiden kanssa, jolloin funktiolle välitetään alkuperäisen muuttujan arvon sijasta muuttujan keskusmuistiosoite. Silloin funktio ei operoi alkuperäisen muuttujan kopioon vaan suoraan itse muuttujaan. Näin on mahdollista muuttaa muuttujien arvoja funktioissa.

Esimerkkiohjelmassa kasvatetaan muuttujan arvoa yhdellä.

void addOne(int *x) {

(*x)++;

}

int main() {

int c=0;

addOne(&c);

cout << c;

return 0;

}

HUOM! Elä sotke näitä asioita. Osoittimen alustus määrittelyn yhteydessä

(28)

int c=25;

int *p = &c; //OK on sama asia kuin

int c;

int *p;

p=&c; //OK, mutta

*p=&c; //VIRHE !

6.3 Viittausparametrillinen funktio (C++)

C++:ssa on uusi tapa viitata muistiosoitteisiin, ns. Viittausparametri &.

tyyppi &viittaus = muuttuja;

Viittaus voidaan ajatella olevan alkuperäisen muuttujan aliasnimi. Viittausmuuttujaa käytettäessä käytetäänkin alkuperäistä muuttujaa johon viitataan, ainoastaan muuttujan nimi on eri. Oleelliset erot osoittimeen ovat, että

• viittausmuuttujan on aina viitattava johonkin muuttujaan (NULL ei sallittu) ja

• viittausta ei voi vaihtaa osoittamaan toiseen muuttujaan ohjelman aikana.

int ted=25; //Tavallinen muuttuja

int &andy=ted; //andy on muuttujan ted alias andy++; //muutetaan todellisuudessa ted cout << ted; //Tulostuu 26

(29)

Viittausta käytetään pääasiasssa funktioiden parametrivälityksessä. Tässä sama esimerkki kuin osoittimien kanssa:

void addOne(int &x) {

x++;

}

int main() {

int c=0;

addOne(c);

cout << c;

return 0;

}

Nähdään, että viittausparametrin pääasiallinen etu on koodin yksinkertaistuminen. Ei tarvita kuin yksi

&-merkki parametrilistassa. Kannattaa huomata, että funktiokutsun perusteella ei voi nähdä, onko kyseessä arvoparametrillinen vai funktioparametrillinen funktio.

(30)

6.4 Funktion ylikuormaus (overloading)

Saman nimisestä funktiosta voi olla useita eri versioita, jos ne eroavat toisistaan parametrien tyyppien tai lukumäärän suhteen. Paluuarvon erilaisuus ei riitä jos parametrilista on sama.

int summa(int x,int y);

float summa(float x, float y); //OK, eroavat parametrien tyyppien osalta

float summa(int x,int y); //VIRHE !

int summa(int x); //OK, eri määrä parametreja

Esimerkiksi kaksi edellistä esimerkkiä voidaan yhdistää samaan koodiin:

void addOne(int &x) {

x++;

}

void addOne(int *x) {

(*x)++;

}

int main() {

int c=0;

addOne(c); //Viittausparam. funktion kutsu addOne(&c); //Muuttujaparam. funktion kutsu cout << c; //Paljos c on nyt ?

return 0;

}

(31)

7 Taulukko

7.1 Perusteita

Tässä on lyhyt kertaus C-kielen taulukoista. C++ sisältää huomattavasti parempia menetelmiä taulukoiden käsittelyyn. Niihin palataan hieman tuonnempana.

Taulukko koostuu peräkkäisistä muistipaikoista, jotka sisältävät samantyyppistä tietoa. Taulukon alkioihin voidaan viitata indeksoimalla. C/C++:ssa taulukon indeksointi alkaa nollasta.

int billy[5]; //5 alkion mittainen kokonaislukutaulukko nimeltä billy

char merkit[80];//80 alkion mittainen merkkijonotaulukko nimeltä merkit.

Char-tyyppisen taulukon jokainen alkio vie aina yhden tavun (8 bittiä) verran muistia.

Kokonaislukutyyppisen taulukon alkio vie yhden kokonaisluvun (4 tavua eli 32 bittiä) verran tilaa muistista.

• Taulukko tunnistetaan hakasuluista [ ]. Määrittelyn yhteydessä sulkujen sisään annetaan taulukon koko.

• Taulukon koko on kiinteä. Kokoa ei siis voi muuttaa suorituksen aikana*.

* Tämä ei tarkalleen pidä paikkaansa. Myös C-kielessä on mahdollista varata taulukko dynaamisella muistinvarauksella, mutta sen käyttö on hankalaa ja virheille altista.

(32)

Taulukon alkioihin voidaan viitata missä järjestyksessä tahansa. Esimerkiksi sijoituslauseella billy[0]=9;

sijoitetaan luku 9 taulukon ensimmäiseksi alkioiksi (indeksi 0). Taulukon alkio voidaan tulostaa normaalin muuttujan tapaan:

cout << billy[0] << endl;

Tulostaa taulukon ensimmäisen alkion sisällön (eli 9).

Taulukon indeksointi "käsin" on aika harvinaista. Yleensä taulukko käydään läpi kerralla for-silmukan avulla.

Tässä esimerkissä alustetaan luvut-niminen kokonaislukutaulukko. Taulukon kokoa ei tarvitse määritellä jos alkiot syötetään alustuksen yhteydessä (tässä alkioita on 5). Hyvin tavallinen tapa taulukon alkioiden tulostamiseen on for-silmukka.

int billy [] = { 16, 2, 77, 40, 12071 };

for (int i=0;i<5;i++)

cout << billy[i]<<endl;

C-kielessä ei ole merkkijono-tietotyyppiä. Merkkijonot ovat itse asiassa merkkitaulukoita, jossa jokainen alkio sisältää yhden ASCII-merkin. Merkkijono päättyy aina loppunollaan \0. Siten merkkijonon koko on oltava yhtä suurempi kuin sinne tallennettavien merkkien määrä.

Merkkijonon käsittely:

• strlen = merkkijonon pituus

(33)

• strcmp = kahden merkkijonon vertailu

• jne...

char m1[] = "Aku Ankka",m2[10];

cout << "Merkkijonon pituus " << strlen(m1) << endl;

strcpy(m2,m1);

cout << "Toinen merkkijono on " << m2 << endl;

if (strcmp(m1,m2)==0))

cout << "Merkkijonot ovat samat" << endl;

else

cout << "Merkkijonot eivät ole samat" << endl;

Taulukon nimi on osoitin taulukon ensimmäiseen alkioon. Seuraavassa esimerkissä esitellään tulostusaliohjelma printarray( ), joka ottaa syötteekseen arg-nimisen kokonaislukutaulukon sekä taulukon koon kokonaislukuna (length). Pääohjelmassa aliohjelmaa kutsutaan kahdella eri taulukolla firstarray ja secondarray.

#include <iostream>

using namespace std;

void printarray (int arg[], int length) { for (int n=0; n<length; n++)

cout << arg[n] << " ";

cout << "\n";

}

(34)

int main () {

int firstarray[] = {5, 10, 15};

int secondarray[] = {2, 4, 6, 8, 10};

printarray (firstarray,3);

printarray (secondarray,5);

return 0;

}

Muutama muistutus:

• Funktiokutsussa taulukosta annetaan vain sen nimi (joka on osoitin taulukon alkuun), ei sulkeita minkäänlaisia !

• Esittelyssä ja rungossa int arg[]on sama asia kuin int *arg

7.2 Taulukko ja osoitin

Taulukon alkioihin voidaan viitata osoittimen avulla.

int c[]={9,0,2,5,0};

int *p=c; //HUOM: Ei int *p=&c, miksi ?

for (int i=0;i<5;i++,p++) {

cout << *p;

}

Osoitin siirretään osoittamaan seuraavaan alkioon lauseella p++. Vastaavasti edelliseen alkioon

(35)

Samantyyppinen esimerkki merkkijonoilla. Nyt voidaan hyödyntää sitä tietoa, että merkkijono päättyy aina loppunollaan.

char c[]={"Hello"};

char *p=c;

while ((*p)) {

cout << *p;

p++;

}

Eli niin kauan kuin p:n osoittaman muistipaikan sisältö on jotain muuta kuin \0 (siis looginen tosi), tulostetaan muistipaikan sisältö ja siirrytään seuraavaan. Ehkä havainnollisempi versio ehdosta olisi

while ((*p) != '\0')

8 Tietue

Tässä kerrataan C-kielen tietue. Tietue sisältää monta yhteen kuuluvaa tietoa koottuna yhdeksi muuttujaksi. Tietueen kanssa pitää muistaa, että siinä luodaan uusi tietotyyppi (näissä esimerkeissä puhelinluettelo), joka käyttäytyy ihan samalla lailla kuin varsinaiset tietotyypit (int, char, jne).

Tietotyyppiin liitetään joku muuttuja, tässä tapauksessa sitä kutsutaan tietuemuuttujaksi (esimerkissä HYV9SN). Tietueen kenttiin viitataan pisteoperaattorilla (.).

Katsotaan pari esimerkkiä.

struct puhelinluettelo {

(36)

char nimi[80];

char pnro[15];

};

int main() {

struct puhelinluettelo HYV9SN;

strcpy(HYV9SN.nimi,"Aku Ankka");

strcpy(HYV9SN.pnro,"050 555 6666");

cout << HYV9SN.nimi << " " << HYV9SN.pnro << endl;

return 0;

}

Edellisessä esimerkissä tietuemuuttujaan mahtuu vain yksi opiskelija. Hyödyllisempi on tietuetaulukko.

Muutetaan pääohjelmaa hieman.

const int N=3; //Vakio, montako tietuetta ? struct puhelinluettelo

{

char nimi[80];

char pnro[15];

};

int main() {

struct puhelinluettelo HYV9SN[N];

strcpy(HYV9SN[0].nimi,"Aku Ankka");

strcpy(HYV9SN[0].pnro,"050 131 1313");

strcpy(HYV9SN[1].nimi,"Roope Ankka");

strcpy(HYV9SN[1].pnro,"050 555 6666");

(37)

strcpy(HYV9SN[2].nimi,"Mikki Hiiri");

strcpy(HYV9SN[2].pnro,"050 555 6667");

for (int i=0;i<N;i++)

cout << HYV9SN[i].nimi << " " << HYV9SN[i].pnro << endl;

return 0;

}

Lopuksi vielä funktioilla toteutettu versio:

const int N=3;

struct puhelinluettelo {

char nimi[80];

char pnro[15];

};

void syota_tiedot(struct puhelinluettelo HYV9SN[]) {

strcpy(HYV9SN[0].nimi,"Aku Ankka");

strcpy(HYV9SN[0].pnro,"050 131 1313");

strcpy(HYV9SN[1].nimi,"Roope Ankka");

strcpy(HYV9SN[1].pnro,"050 555 6666");

strcpy(HYV9SN[2].nimi,"Mikki Hiiri");

strcpy(HYV9SN[2].pnro,"050 555 6667");

}

void tulosta_tiedot(struct puhelinluettelo HYV9SN[]) {

for (int i=0;i<N;i++)

(38)

cout << HYV9SN[i].nimi << " " << HYV9SN[i].pnro <<

endl;

}

int main() {

struct puhelinluettelo HYV9SN[3];

syota_tiedot(HYV9SN);

tulosta_tiedot(HYV9SN);

return 0;

}

Tietueeseen voidaan määritellä osoitin, ns. tietueosoitin, jota merkitään nuolioperaattorilla →.

Tässä esimerkissä voitaisiin määritellä osoitin tietuetaulukkoon (taulukon alkuun) seuraavasti:

struct puhelinluettelo *p=HYV9SN;

jolloin taulukon kenttiin voidaan viitata nuolella:

cout << p->nimi << p->pnro;

Tulostaa Akun tiedot. Seuraavaan tietueeseen voidaan siirtyä osoittimen inkrementoinnilla p++;

jolloin siirrytään tulostamaan Roopen tiedot.

Viittaukset