Olio-ohjelmoinnin perusteet luento 3: Muuttujista ja funktioista Sami Jantunen LTY/Tietotekniikan osasto.

Slides:



Advertisements
Samankaltaiset esitykset
Tuloksellinen Java-ohjelmointi Luku 3 Luokkien käyttäminen
Advertisements

15. Loogiset operaatiot.
@ Leena Lahtinen Helia TIETO JA TIETOKONEOHJELMA  TIETOKONEOHJELMA KÄSITTELEE TIETOJA  TIETOJA VOIDAAN KÄSITELLÄ OHJELMASSA VAIN SALLITUILLA.
© Jukka Harju, Viittausmuuttujat. © Jukka Harju, Viittaukset •Viittausmuuttuja sisältää tiedon siitä missä muistipaikassa olio.
© Hannu Laine 1 Tietorakenteet ja algoritmit Funktio-osoittimet Funktio-osoittimen ja taulukko-osoittimen vertailu Funktio-osoittimen käyttötapoja.
JavaScript (c) Irja & Reino Aarinen, 2007
Ict1td002: Ohjelmointitaito Kertaus Osio 2 - luokat - ilmentymät - viittaus- ja arvomuuttuja - ilmentymien taulukointi HAAGA-HELIA IltaTiko.
Taulukot: Array Taulukko Javassa pitää aina perustaa (new)
Ohjelmointitaito (ict1td002, 12 op) Syksy 2008
Näytölle tulostaminen. 7.2 Sisällys System.out.println - ja System.out.print -operaatiot. Tulostus erikoismerkeillä. Edistyneempää tulosteiden.
C-ohjelmointi, kevät 2006 Taulukot Binääritiedostot Luento
Java-ohjelmointi Opas ammattimaiseen osaamiseen Luku 4 Toistolauseet
@ Leena Lahtinen OHJELMAN OSITTAMINEN LUOKKA ATTRIBUUTIT METODIT.
Olio-ohjelmoinnin perusteet luento 3
OLIO-OHJELMOINTI PERUSTEET PERUSTIETOTYYPIT
Poikkeuskäsittely- lohkot tMyn1 Poikkeuskäsittelylohkot try-catch Poikkeustilanteiden käsittelymekanismi toteutetaan varatuilla sanoilla try, throw ja.
TyyppimuunnoksettMyn1 Tyyppimuunnokset Joskus kääntäjän on tehtävä itse päätöksiä, jos ohjelmoija ei ole ajatellut yksityiskohtia: int arvo1=10; long arvo2=25;
Vakio-osoitin ja osoitin vakioon tMyn1 Vakio-osoitin ja osoitin vakioon Tavallinen osoitin voi vaihtaa osoitettavaa keskusmuistialuetta. Tämä voidaan tehdä.
Poikkeustenkäsittely  Mitä poikkeustenkäsittely tarkoittaa?  Poikkeuksen käsitteleminen  Poikkeusluokkien hierarkia  Poikkeuksen heittäminen 1.
TAULUKKO YKSIULOTTEINEN TAULUKKO. TAULUKKO  Taulukon tarkoitus Ohjelmassa tarvitaan paljon samantyyppisiä samaan kohdealueeseen kuuluvia muuttujia Näitä.
TIETO JA TIETOKONEOHJELMA TIETOKONEOHJELMA KÄSITTELEE TIETOJA TIETOJA VOIDAAN KÄSITELLÄ OHJELMASSA VAIN SALLITUILLA MENETELMILLÄ.
Sami Jantunen LTY/Tietotekniikan osasto
Dynaamiset oliottMyn1 Dynaamiset oliot Dynaamisen olion tunnuksen esittely ja olion määrittely voivat tapahtua yhtäaikaisesti tai eri aikaan. Dynaamisen.
Olioon kohdistuvia perustoimintoja tMyn1 Olioon kohdistuvia perustoimintoja Kopiointimuodostin (copy constructor) alustaa olion tietojäsenet saman luokan.
13. Hyvä ohjelmointitapa (osa 1)
Virtuaaliset jäsenfunktiot tMyn1 Virtuaaliset jäsenfunktiot Virtuaalinen jäsenfunktio on esiteltävä monimuotoisessa kantaluokassa. Virtuaalisen jäsenfunktion.
© Jukka Harju, Jukka Juslin
7. Oliot ja viitteet.
Luokan määrittely class-määreellä tMyn1 Luokan määrittely class-määreellä Luokan määrittely tarkoittaa luokan tietojäsenten esittelyä ja jäsenfunktioiden.
ict1td002 - Copyright Raine Kauppinen 1 Alkuarvot ja tyyppimuunnokset (1/5)  Aiemmin olemme jo antaneet muuttujille alkuarvoja, esimerkiksi: int.
Metodit – Arvotyyppi Ellei metodi palauta arvoa, sen arvotyyppi on void Tällöin ”return;”-lauseke ei ole metodissa pakollinen, vaikka sen käyttö on sallittua.
Muuttujat ja vakiottMyn1 Muuttujat ja vakiot PHP-kielen syntaksi on lainattu suurimmaksi osaksi C- kielestä. PHP on erityisesti HTML-dokumenttien sisään.
4. Attribuutit 4.1. Sisällys Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2.
5. Kapselointi Yleistä Kapseloinnilla (encapsulation) tarkoitetaan luokan tietojen ja toimintojen pakkaamista yhdeksi suojatuksi kokonaisuudeksi.
10. Abstrakti luokka Johdanto Abstrakti luokka (abstract class) poikkeaa konkreettisesta luokasta (ei-abstrakti luokka) siten, että siitä ei.
@ Leena Lahtinen OHJELMAN OSITTAMINEN LUOKKA ATTRIBUUTIT METODIT.
Olioon kohdistuvia perustoimintoja tMyn1 Olioon kohdistuvia perustoimintoja Kopiointimuodostin (copy constructor) alustaa olion tietojäsenet saman luokan.
Poikkeukset Yleistä Virheeseen varautuminen tarkoittaa sitä, että ohjelmoija huomioi koodia kirjoittaessaan ajonaikaisen virheen mahdollisuuden.
Ohjelmointitaito (ict1td002, 12 op) Kevät 2008 Raine Kauppinen
Johdatus ohjelmointiin – C kielen peruselementit Tutkijayliopettaja Manne Hannula Opetusharjoittelu (ohjaava opettaja Jukka Jauhiainen)
Johdetun luokan olion esittely... tMyn1 Johdetun luokan olion esittely ja määrittely Esittelyluokka tarkoittaa olion tunnuksen luokkaa. Määrittelyluokka.
2. Lisää Java-ohjelmoinnin alkeita
Antti-Jussi Lakanen Nuorten peliohjelmointi 2009 / Jyväskylän yliopisto.
Kontrollirakenteet laajemmin
Javascript 2: Ohjelmointikielen ominaisuudet Jaana Holvikivi Metropolia.
Javan oliovirrat eli oliotiedostojen käsittely. Olio- eli objektitiedostojen käsittely Käsittely täysin samanlaista kuin muiden tiedostojen 1.Otetaan.
1 © Jukka Juslin Luokat, attribuutit ja metodit Yleistietoa: seuraavalla koulutusviikolla tarkempi käsittely.
14. Poikkeukset Sisällys Johdanto poikkeuksiin. Poikkeusten käsittely: − Poikkeusten käsittely paikallisesti. − Poikkeusten heittäminen. Exception.
15. Ohjelmoinnin tekniikkaa
Osoittimen määrittely ja alustus tMyn1 Osoittimen määrittely ja alustus Osoitin (pointer) on muuttuja, joka voi sisältää keskusmuistiosoitteen. Osoitinmuuttujan.
Valintarakenne valintarakenne alkaa aina kysymyksellä eli ehdolla ehto tarkoittaa, että muuttujan sisältöä verrataan toisen muuttujan sisältöön tai vakioon.
Ohjausrakenteet Määräävät ohjelmakoodin suoritusjärjestyksen Ehtolause if – else on muotoa if (lauseke) lause1 else lause2 Jos lauseke on tosi, niin suoritetaan.
Olio-ohjelmoinnin perusteet luento 3: Muuttujista ja funktioista Sami Jantunen LTY/Tietotekniikan osasto.
Tiedostot. 8.2 Sisältö Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen.
String-vertailusta ja Scannerin käytöstä (1/2)
6. Muuttujat ja Java.
6. Tiedostot.
Funktio-ohjelmointi ja Java
Poikkeustenkäsittelylohkot try-catch
13. Loogiset operaatiot.
3. Luokat, oliot ja metodit Java-kielessä (Lausekielinen ohjelmointi I ja II –kursseilla opitun kertausta.)
7. Näytölle tulostaminen
Toisto Toistolausekkeet for, while(ehto){…} ja do {…} while(ehto)
9. Aritmeettiset operaatiot
14. Hyvä ohjelmointitapa.
11. Javan valintarakenteet
7. Näytölle tulostaminen
13. Loogiset operaatiot.
4. Luokan testaus ja käyttö olion kautta
eli oliotiedostojen käsittely
Esityksen transkriptio:

Olio-ohjelmoinnin perusteet luento 3: Muuttujista ja funktioista Sami Jantunen LTY/Tietotekniikan osasto

VAROITUS!!!!!!  Tällä luennolla käsitellään perusasioita, joilla ei ole sinänsä paljon tekemistä oliopohjaisuuden kanssa!  Esimerkit ovat esitetty ei-oliopohjaisella tavalla!  Tarkoitus on vain havainnoillistaa perusasioita  Toivottavasti osaat soveltaa näitä jatkossa, kun puhumme lisää luokista!

Sisältö  Muuttujat  Muuttujien määrittely ja tietotyypit  Osoittimet (pointer variables)  Viittaukset (reference variables)  Funktiot  määrittely ja tiedon välitys  muuttujien näkyvyysalueet  oletusparametrit (default parameters)  uudelleenmäärittely (overloading)  avoimet funktiot (inline)  rekursio

Muuttujista…  Tietokoneohjelmat manipuloivat tietoa  Meillä on siis tarve tallettaa tietoa  Muuttujat:  Kuvaavat tiettyä muistin muistipaikkaa  Sisältävät tietyn tiedon  Kun määrittelet muuttujan:  Varaat tilaa muistista  Annat muuttujalle nimen  Teet tämän kerran kutakin muuttujaa kohden

Kuinka luodaan muuttuja  Formaatti: ;  Muuttujan nimeksi voit valita melkein mitä vaan  Esimerkkejä: byte age; float gpa; String name; char letterGrade;  Nyt kun muuttujat on määritelty  Ei tarvitse määritellä niitä uudestaan  Voit käyttää muuttujan nimeä jatkossa tiedon lukemisessa ja kirjoittamisessa agegpa nameletterGrade

C++ varatut sanat  Näitä sanoja et kuitenkaan voi käyttää sellaisenaan muuttujien nimissä:  auto, bool, break, case, catch, char, class, const, continue, default, do, double, else, enum, extern, float, for, friend, goto, if, inline, int, long, namespace, new, operator, private, protected, public, register, return, short, signed, sizeof, static, struct, switch, template, this, throw, try, typedef, union, unsigned, void, volatile, while

Sallittuja muuttujien nimiä  Ei saa olla varattu sana  Ei saa alkaa numerolla  Ei saa sisältää symboleja kuten  Kuten !, ^, &, /, ), tai välilyönti  Poikkeukset: alaviiva _, ja dollarimerkki $  Esimerkkejä: byte $theValue; // legal char test_value;// legal double double;// not legal int rum&coke;// not legal bool true or false; // not legal for two reasons!

Muuttujien alustamisesta  Tarkoittaa alku-arvon antamista muuttujalle  Arvo annetaan = -operaattoria käyttäen  Kopioi oikealla olevan tiedon vasemmalla määriteltyyn muuttujaan. Muuttujan tyyppi ja tiedon formaatti pitää olla yhteensopiva  Alustettava tieto voi olla vakio tai toinen muuttuja!  Esimerkkejä: int age; age = 15; char letterGrade = ‘B’; char yourGrade = letterGrade;

Tietotyypeistä  Tietotyyppi kertoo mikälaista tietoa muuttuja voi pitää sisällään  Jotkin tietotyypit ovat “sisäänrakennettuja” ohjelmointikieleen  Voimme myös määritellä tietotyyppejä itse (puhutaan tästä lisää myöhemmin)  Erilaisia tietotyypin muotoja:  Yksinkertaiset tietotyypit  Monimutkaiset tietotyypit (Valmistettu yksinkertaisista tietotyypeistä)

Yksinkertaiset tietotyypit  Sisäänrakennettuja  Numerot:  short (melko pienet numerot)  int (suuret numerot)  long (TOSI suuret numero)

Yksinkertaiset tietotyypit  Desimaaliluvut:  float (Ei niin tarkka kuin double )  double (Aika tarkka)  Tarkkuudella tarkoitetaan kuinka monta lukua tulee desimaalin jälkeen  Muita:  char (pitää sisällään merkkejä kuten ‘a’, ‘A’, ‘1’, ‘ ‘)  bool (pitää sisällään totuusarvon true tai false)

No kuinka iso se on?: sizeof( )  sizeof( ) kertoo kuinka paljon tietotyyppi vie tavuja  Esimerkki: int myInt; cout << sizeof (myInt) << endl;

Etumerkki vai ei?  C++ -kielessä voi määritellä merkki- ja kokonaislukumuuttujat etumerkittömäksi.  Etumerkillisille ja etumerkittömille kokonaisluvuille varataan yhtä paljon muistitilaa  Luvut ovat oletusarvoisesti etumerkillisiä  Etumerkittömän edut:  Etumerkittömät tietotyypit voivat siis sisältää suuremman joukon positiivisia lukuja

Perustietotyypeistä  Se kuinka monta tavua kukin tietotyyppi vie tilaa on riippuvainen kääntäjästä ja käyttöjärjestelmästä!  Tässä kuitenkin esimerkkejä: TyyppiKoko (Tavua)Arvoalue unsigned int20 …65535 int … unsigned long40 … long … char10 … 255

Miksi koolla on väliä  Eri tietotyypit vie eri määrän tavuja muistista  Et voi laittaa suuritilaisemman muuttujan sisältöä pienenpään muistitilaan: short s = 5;long l = 5; long l = s;short s = l; long short long short long short

Tyyppimuunnos (Type Casting)  Tapahtuu kun pistät jotain enemmän tilaa vievää tietoa pienempään muistipaikkaan  Tiedon tarkkuustaso saattaa heikentyä  Formaatti: = ( ) ;  Esimerkki: long myLong = 17; short myShort = (short)myLong; // We are squeezing myLong into myShort!

short vai long?  Jos on pienikin mahdollisuus, että muuttujaan tulee suurempi arvo kun tietotyyppiin mahtuu, niin valitse isompi tietotyyppi.

Etumerkittömien kokonaislukujen ylivuoto Sama ilmiö kun auton matkamittarissa:  Kun on maksimi saavutettu, niin aloitetaan uudestaan nollasta  Esim: unsigned int myInt = 65535; cout<< myInt << endl; myInt++; cout<< myInt << endl; myInt++; cout<<myInt<<endl; Mitä tapahtuu?? Tuloste:

Etumerkillisten kokonaislukujen ylivuoto  Suurinta positiivista arvoa seuraa negatiivisin mahdollinen arvo  Esim: int myInt = 32767; cout<< myInt << endl; myInt++; cout<< myInt << endl; myInt++; cout<<myInt<<endl; Mitä tapahtuu?? Tuloste:

unsigned short int luku1; unsigned short int luku2; unsigned short int luku3;  Liian työlästä?  Altis kirjoitusvirheille  Ratkaisuehdotuksia:  unsigned short int luku1, luku2, luku3;  Peitenimi (Typedef)

Peitenimi (Typedef) #include typedef unsigned short int USHORT; void main() { USHORT Leveys = 5; USHORT Korkeus;...

Yhteenveto  Muuttujat ovat nimettyjä soluja tietokoneen muistissa  On olemassa erilaisia tietotyyppejä säilyttämään erilaista tietoa  Eri tietotyypit vievät eri määrän tilaa  Kaikki muuttujat määritellään samanlaisen formaatin mukaisesti

Vakioista Miksi vakioita? -Esimerkki  Oletetaan, että koulussa yhdelle luokalle hyväksytään 15 oppilasta  Oletetaan myös, että koulun oppilasmäärä saadaan kerrottuna luokkien lukumäärä luokan koon kanssa: int luokkienLukumaara = 20; int oppilasmaara = 15 * luokkienLukumaara;  Mikä vikana?

Miksi vakioita?  Emme halua kovakoodata arvoja  Työlästä muuttaa  Emme myöskään halua laittaa pysyviä arvoja muuttujiksi  Joku saattaa vahingossa muuttaa niiden arvoja

#define  Hieman vanhentunut tapa määritellä vakio  Esim: #define oppilaitaLuokassa 15  Ei ota mitään kantaa tietotyyppiin  Esikäsittelijä pelkästään korvaa tekstin toisella  Kääntäjä siis näkee oppilaitaLuokassa-tekstin sijasta luvun 15

Const  Suositeltavampi tapa #define sijasta: const unsigned short int oppilaitaLuokassa = 15;  Kääntäjä tietää minkä tyyppinen vakio on.  osaa valvoa, että vakiota käytetään oikein  Vakiota ei voi muuttaa ohjelman suorituksen aikana. Jos vakio halutaan muuttaa, tulee ohjelma kääntää uudestaan.

Luetellut vakiot  Muuttujatyyppi, johon voi sijoittaa vain etukäteen määriteltyjä arvoja.  Luetellun vakion määrittely: enum VARI {PUNAINEN, SININEN, VIHREA, VALKOINEN, MUSTA};  Määrittelee sanan VARI  Määrittelee vakiot PUNAINEN (arvo 0), SININEN (arvo 1),…  Kullekin vakiolle on mahdollista määritellä arvo erikseen: enum VARI {PUNAINEN=100, SININEN, VIHREA=500, VALKOINEN=501, MUSTA=700};  Lause tuottaa vakiot PUNAINEN=100, SININEN=101, VIHREA=500, VALKOINEN=501 ja MUSTA=700  Luetellut vakiot ovat käteviä kun käsitellään rajallista alijoukkoa (värejä, viikonpäiviä, ym…)  Ohjelmakoodin luettavuus paranee

Luetellut vakiot käyttöesimerkki #include void main() { enum Paivat {Sunnuntai, Maanantai, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai }; Paivat vapaaPaiva; cout << “Minkä päivän haluat pitää vapaata (0-6)? “; cin >> vapaaPaiva; if (vapaaPaiva == Sunnuntai || vapaaPaiva == Lauantai) cout << “Viikonloppu on vapaata muutenkin!” << endl; else cout << “OK. pannaan asia muistiin” << endl; }

Lisäys- ja vähennysoperaattorit  ++ korottaa muuttujan arvoa yhdelläint counter = 5; counter++;counter = counter +1;  += korottaa muuttujan arvoa annetulla määrälläint counter = 5; counter += 3;counter =counter + 3;  Sama kuin Huomaa: Myös --, -=, %=, /= versiot

Lisäys- ja vähennysoperaattorit  Voidaan toteuttaa joko etuliitteenä (esim. ++counter; ) tai jälkiliitteenä (esim. counter++; )  Lopputulos sama paitsi jos muuttujaa käytetään samassa tilanteessa vielä arvon muutoksen lisäksi johonkin muuhun

Etu- ja jälkiliitelisäys esimerkki … void main() { int minunIka=40; int sinunIka=40; cout << “minun ikä on:” << minunIka++ << endl; cout << “sinun ikä on:” << ++sinunIka << endl; … } Mitä tapahtuu?? Tuloste: minun ikä on:40 Sinun ikä on:41

Osoittimista Oletteko nähneet tällaista?  Ohjelmoijan painajainen!  Johtuu osoittimen väärinkäytöstä

Tarkastellaan hieman muistia! Muistin osoite sinisellä, Arvot mustalla, Muuttujan nimi punaisella

Määritetään int-muuttuja int myInt; myInt

Mitä tuli tehtyä?  Määrittelemällä int- muuttujan varasimme juuri ja juuri tarpeeksi muistitilaa int- luvulle  Ei hajuakaan missä päin muistia muuttujamme sijaitsee  Tietokone valitsee muistiosoitteen “satunnaisesti”  Mikä arvo on varaamassamme muistipaikassa?  Voimmeko tulostaa muistipaikan arvon?  Tulostaisimme –4717! (roskaa)

Kopioidaan 42 muuttujan osoittamaan muistipaikkaan myInt = 42; myInt

Osoittimet (Pointers)  Antaa mahdollisuuden päästä käsiksi muistipaikkaan, missä tieto sijaitsee  Osoitin määritellään seuraavanlaisella formaatilla: * ;  Example: int *ptr;

Määritetään int osoitin int *ptr; ptr myInt

Mitä nyt tuli tehtyä?  Loimme uuden muuttujan joka tulee osoittamaan int tietoon  Huomaa, että osoitin ei vielä osoita myInt sisältämään tietoon  Mitä jos yritämme tulostaa osoittimen sisällön?

cout << ptr; (ptr:n arvoksi tulostuu 98131) ptr myInt

Ongelma  Kuinka voimme saada myInt osoitteen, jotta ptr voi osoittaa sinne?  Muista, että voimme vielä käyttää myInt:ä suoraankin int someInt = myInt;  Tarvitsisimme todella keinon tallettaa myInt-muuttujan osoite  Meidän ei tarvitse tallettaa myInt muuttujan arvoa osoittimeen (vain osoite)

& operaattori  & operaattorin avulla päästään käsiksi muuttujan muistiosoitteeseen  Mitä seuraavanlainen komentorivi tulostaisi näytölle? cout << &myInt << endl;

Mitä tapahtuisi? cout << &myInt; ptr myInt

Laitetaan osoitin osoittamaan…  Nyt pitäisi laittaa “ptr” osoittamaan myInt -muuttujan sisältämään tietoon ptr = &myInt; ptr on osoitin, joten se olettaa että sen arvoksi annetaan osoite & -operaattorilla saamme myInt muuttujan osoitteen ja kopioimme osoitetiedon ptr-osoittimen arvoksi

Ennen ptr myInt

Jälkeen ptr = &myInt; ptr myInt

Mitäs tämä tekisi? ptr = myInt; ptr myInt

Hupsista! ptr = myInt; ptr myInt

Osoittimen sisältö  Kuinka osoittimen sisältö saadan luettua?  Käytetään *-operaattoria  Esimerkki: cout << *ptr << endl; //Tulostaa ptr-osoittimen //osoittaman muistipaikan sisällön!

Seurataan osoitinta ja tulostetaan cout << *ptr << endl; ptr myInt

Toinen esimerkki Muistin osoite sinisellä, Arvot mustalla, Muuttujan nimi punaisella

Määritetään osoitin int *ptr; ptr

Mitä tapahtuu? cout << *ptr << endl; ptr

Hupsista!

 Parametrin välittäminen funktioon lähettää kopion alkuperäisestä muuttujan arvosta. Funktio ei siis pysty manipuloimaan pääohjelmassa olevan muuttujan arvoa! void cannotChange (int x) { x = 6; cout << x << endl; } void main ( ) { int myInt = 17; cannotChange (myInt); cout << myInt << endl; } Miksi käyttäisin osoittimia?

void cannotChange (int x) { x = 6; cout << x << endl; } void main ( ) { int myInt = 17; cannotChange (myInt); cout << myInt << endl; } Märitetään myInt myInt

Kutsutaan funktiota myInt void cannotChange (int x) { x = 6; cout << x << endl; } void main ( ) { int myInt = 17; cannotChange (myInt); cout << myInt << endl; }

Kopiointi tapahtuu tässä! myInt x void cannotChange (int x) { x = 6; cout << x << endl; } void main ( ) { int myInt = 17; cannotChange (myInt); cout << myInt << endl; }

Ja muutos kohdistuu vain paikalliseen kopioon myInt x void cannotChange (int x) { x = 6; cout << x << endl; } void main ( ) { int myInt = 17; cannotChange (myInt); cout << myInt << endl; }

Tulostetaan kopion arvo (6) myInt x void cannotChange (int x) { x = 6; cout << x << endl; } void main ( ) { int myInt = 17; cannotChange (myInt); cout << myInt << endl; }

Palataan pääfunktioon (tulostetaan 17) (x on tuhottu, tilalle jäi vain roskaa…) myInt void cannotChange (int x) { x = 6; cout << x << endl; } void main ( ) { int myInt = 17; cannotChange (myInt); cout << myInt << endl; }

void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; } Ja sitten sama osoittimilla

Luodaan myInt myInt void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Luodaan ptr osoittamaan myInt:n muistipaikkaan myInt ptr void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Lähetetään ptr:n kopio funktioon myInt ptr void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Lähetetään ptr:n kopio funktioon myInt ptr x void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Muutetaan x:n osoittamaa muistipaikkaa myInt ptr x void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Muutetaan x:n osoittamaa muistipaikkaa myInt ptr x void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Tulostetaan x:n osoittaman muistipaikan sisältö (6) myInt ptr x void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Huomaa pääohjelmassa, että muuttujan arvo on muuttunut (myöskin 6) myInt ptr x void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Mielenkiintoinen juttu Seuraavat lausekkeet tulostavat saman asian! cout << *ptr << endl; cout << myInt << endl Samoin nämä! cout << ptr << endl; cout << &myInt << endl; MIKSI? void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Vakio-osoittimet  Varattu sana const voidaan kirjoittaa osoitinmuuttujan määrittelyyn ennen tietotyyppiä, tietotyypin jälkeen tai molempiin paikkoihin.  Esim:  const int * pYksi;  int * const pKaksi;  const int * const pKolme;

Vakio-osoittimet esimerkit  pYksi osoittaa int- tyyppiseen vakioon. Osoittimen osoittamaa tietoa ei voi muuttaa mutta osoittimen arvoa voi muuttaa  const int * pYksi;  pKaksi on osoitinvakio, joka osoittaa int-tyyppiseen tietoon. Osoittimen osoittamaa int- tietoa voi muuttaa mutta osoittimen arvoa ei voi muuttaa  int * const pKaksi;  pKolme on osoitinvakio int –tyyppiseen vakioon. Psoittimen osoittamaa tietoa ei voi muuttaa eikä myöskään osoittimen arvoa voi muuttaa  const int * const pKolme;

Osoittimet yhteenveto  Sinun tulee ymmärtää miten muisti toimii, jotta ymmärtäisit osoittimien toiminnan  &-operaattori on osoittimiin liittyvien salaisuuksien äiti   Osoittimien sisällön saat * -operaattorilla  Voit manipuloida funktioissa pääohjelman muuttujien arvoja välittämällä funktiokutsussa osoittimia.

Viittausmuuttujat (Reference variables)  Osoittimia tarvitaan, mutta ne ovat usein pahojen ohjelmointivirheiden lähde.  Viittausmuuttujat:  osoittaa osoittimen tapaan olemassa olevaan tietoon.  on osoittimia turvallisempi. Kääntäjä tekee viittausmuuttujalle enemmän tarkistuksia  on osoittimia selkeämpi käyttää  Viittausmuuttuja on kuin “peitenimi” tai “synonyymi” olemassa olevalle tiedolle

Viittausmuuttujat Käyttöohje  Muodostetaan &-operaattorilla seuraavan formaatin mukaisesti: & = viitattavaTieto; ESIM: int &jokuViittaus = jokuInt;  Viittaus on AINA alustettava johonkin tietoon ennen käyttöä!  Viittausta ei voi muuttaa viittaamaan toiseen kohteeseen!

Viittausmuuttuja käyttöesimerkki Mitä tapahtuu?? void main () { int intYksi; int &jokuViittaus = intYksi; intYksi = 5; cout << ”intYksi: ” << intYksi << endl; cout << ”jokuViittaus: ” << jokuViittaus << endl; jokuViittaus = 7; cout << ”intYksi: ” << intYksi << endl; cout << ”jokuViittaus: ” << jokuViittaus << endl; } Tulostus: intYksi: 5 jokuViittaus: 5 intYksi: 7 jokuViittaus: 7

Tiedon välitys funktion parametreissä  Funktioita koskee kaksi rajoitusta  parametrit ovat kopioita alkuperäisistä tiedoista (muistathan osoitin-esimerkin)  funktio voi palauttaa vain yhden paluuarvon  Rajoitukset voi kiertää joko osoittimella tai viittauksella

Palataan osoitinesimerkin pariin Vaikeaselkoinen (*-operaattorin jatkuva käyttö) void canChange (int* x) { *x = 6; cout << *x << endl; } void main ( ) { int myInt = 17; int* ptr = &myInt; canChange (ptr); cout << myInt << endl; }

Ja sitten sama viittauksia käyttäen void canChange (int &x) { x = 6; cout << x << endl; } void main( ) { int myInt = 17; canChange (myInt); cout << myInt << endl; } Selkeämpää vai mitä????

Useampi paluuarvo funktiolle? Viittaustoteutus int kertoja (int luku, int &nelio, int &kuutio ) { nelio = luku*luku; kuutio = luku*luku*luku; return 1; //onnistui } void main( ) { int luku, nelio, kuutio, tulos; tulos = kertoja(luku, nelio, kuutio); } Miten tämä toteutettaisiin osoittimilla????

Sama osoitintoteutuksena int kertoja (int luku, int *nelio, int *kuutio ) { *nelio = luku*luku; *kuutio = luku*luku*luku; return 1; //onnistui } void main( ) { int luku, nelio, kuutio, tulos; tulos = kertoja(luku, &nelio, &kuutio); }

Parametrien välittäminen kopioina vs. viittauksena -Tehokkuusnäkökulma  Parametrien välittämisestä kopioina seuraa taustalla seuraavia tehtäviä:  kutsutaan välitettävän tyypin kopiorakentajaa  sijoitetaan kopio muistiin  kutsutaan välitettävän tyypin purkajaa  kutsutaan paluutyypin kopiorakentajaa  kutsutaan paluutyypin purkajaa  Jos välitettävät parametrit ovat suurikokoisia olioita, kopiointi syö muistia ja suorituskykyä   suositaan osoittimia ja viittauksia? (Entäpä turvallisuus ja olion eheys?)

Vakioviittaus  Voidaan tehokkaasti välittää funktion parametreina olioita ja olla samalla varma siitä, että oliota ei muuteta

Milloin käytetään viittauksia? Milloin osoittimia?  Suosi viittauksia:  ulkoasultaan selkeämpiä  turvallisempia  Viittausta ei voi muuttaa! Käytä osoitinta jos:  on tarve osoittaa ensin yhteen tietoon ja sitten toiseen  on tarve väliillä osoittaa tietoon, mutta välillä ei

Missä mennään?  Muuttujat  Muuttujien määrittely ja tietotyypit  Osoittimet (pointer variables)  Viittaukset (reference variables)  Funktiot  määrittely ja tiedon välitys  muuttujien näkyvyysalueet  oletusparametrit (default parameters)  uudelleenmäärittely (overloading)  avoimet funktiot (inline)  rekursio

Termiologiaa  Funktio on looginen ryhmä komentoja  Uudelleenkäytettävää koodia  Kirjoita kerran  Kutsu niin monta kertaa kuin haluat  Edut  Uudelleenkäytettävää  Helpottaa abstraktiota  Vähentää monimutkaisuutta  Vähentää koodin pituutta

Miksi funktioita? (näetkö mitään toistuvaa?) double average; int userNum1, userNum2; cout << “Please enter the 2 numbers” << endl; cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … // a lot of other code cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2;

Miksi funktioita? (näetkö mitään toistuvaa?) Samaa koodia double average; int userNum1, userNum2; cout << “Please enter the 2 numbers” << endl; cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … // a lot of other code cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2;

Siirretään toistuva koodi omaksi funktioksi cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; Tee tästä oma funktio double average; int userNum1, userNum2; cout << “Please enter the 2 numbers” << endl; cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … // a lot of other code cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2;

Ja nimetään sitten funktio cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; double calculateAverage( ) double average; int userNum1, userNum2; cout << “Please enter the 2 numbers” << endl; cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … // a lot of other code cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; … cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2;

Ja kutsutaan funktiota (sen sijaan että duplikoisimme komentoja) double average; int userNum1, userNum2; cout << “Please enter the 2 numbers” << endl; average = calculateAverage(); … // a lot of other code average = calculateAverage(); … average = calculateAverage(); cin >> userNum1; cin >> userNum2; average = (userNum1 + userNum2) / 2; average = calculateAverage();

Mitä taas tuli tehtyä?  Kirjoitimme koodin kerran, mutta käytimme sitä useasti  Lyhensimme rivien määrää koodissamme  Yksinkertaistimme koodia  Tämä on proseduraalista abstraktiota (muistathan ensimmäisen luennon?)

Muuttujien näkyvyysalue (Scope)  Näkyvyysalue- kuka näkee ja mitä  Funktion sisällä määritetyt muuttujat näkyvät vain funktion sisäpuolella!  Pitää olla keino lähettää informaatiota funktiolle  Pitää olla keino saada tietoa funktiosta  Esimerkki: function1 ei näe myInt:iä function1function2 char myChar; int myInt;

Globaalit muuttujat  Funktioiden ulkopuolella määritellyt muuttujat (globaalit muuttujat) näkyvät kaikissa funktioissa (myös main:ssa)  Paikallinen muuttuja, joka on saman niminen kuin globaali muuttuja ei vaikuta globaalin muuttujan arvoon  itse asiassa paikallinen muuttuja “piilottaa” saman nimisen globaalin muuttujan #include //globaaleja muuttujia int x =5, y =7; void main() { cout << “Y on ” << y << endl; omaFunktio(); cout << “Y on ” << y << endl; } void omaFunktio() { y = 10; }

Varoituksen sana globaaleista muuttujista  Globaalien muuttujien käyttö on vaarallista!  Kukaan ei pidä kirjaa niiden käytöstä  Yksi käyttää yhdellä tavalla, toinen toisella  altis virheille, mitä on vaikea paikallistaa  Globaalien muuttujien käyttöön ei yleensä ole tarvetta  Malta vielä hetki. Seuraavilla luennoilla tulee lisää (=oliopohjaisia) ratkaisuja muuttujien näkyvyysongelmaan

Funktion malli unsigned short int LaskeAla (int pituus, int leveys) Paluuarvon tyyppiFunktion nimiParametrien nimet Parametrien tyypit

Paluutyyppi  Funktiolla on mahdollisuus palauttaa kutsuvaan koodiin tietoa  Jos funktio ei palauta mitään, sen paluutyyppi on void  Jos funktio palauttaa tietoa, sen paluutyyppi on samaa tyyppiä kun palautettavan tiedon tyyppi  Esimerkkejä paluutyypeistä:  int  char  bool

Tehtävä: Valitse paluutyypit  Funktion nimi average getLetterGrade areYouAsleep getGPA printMenu getStudentName  Paluutyyppi double or float char boolean double or float void String

Funktion nimestä  Samoja sääntöjä kuin muuttujienkin nimeämisessä. Voi olla melkein mitä tahansa paitsi:  varattu sana  Ei voi alkaa numerolla  ei voi sisältää symboloja paitsi _ ja $  Funktion nimi tulisi alkaa pienellä kirjaimella  Jos funktion nimessä on useita sanoja aloita ne (ensimmäistä lukuunottamatta) isolla kirjaimella. Esimerkki:  thisIsAnExample  Tyypillisesti yrityksillä on omat tyylioppaat, joissa on määritelty nimeyskäytännöt tarkemmin!

Esimerkki #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); } x y // Note: the average function is currently inactive

Esimerkki (määritä muuttujat) num1 num2num3 ? ?? #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); } x y // Note: the average function is currently inactive

Esimerkki (määritä muuttujat) num1 num2num3 result1result2 ? ?? ?? #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); } x y // Note: the average function is currently inactive

Esimerkki num1 num2num3 result1result ?? #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); } x y // Note: the average function is currently inactive

Example (call the function) num1 num2num3 result1result ?? HERÄTYS! #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); } x y

Example (data passing) num1 num2num3 result1result ?? #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); } 57 x y

Esimerkki (pääohjelma vaipuu uneen) xy num1 num2num3 result1result ?? 57 // Funktio on nyt aktiivinen #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); }

Esimerkki (funktio hoitaa hommaansa) xy num1 num2num3 result1result ?? 57 // is 12; 12 / 2 == 6 #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); }

Esimerkki (Funktio on valmis ja palauttaa tuloksen) xy num1 num2num3 result1result ?? 57 // is 12; 12 / 2 == 6 6 #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); }

Esimerkki (pääohjelma herää; funktio nukkuu) x y num1 num2num3 result1result ? funktio nukkuu #include void main ( ) { int num1, num2, num3; double result1, result2; num1 = 5; num2 = 7; num3 = 4; result1 = average (num1, num2); result2 = average (num3, num1); } double average (int x, int y) { return ( (x+y) / 2); }

Sääntöjä funktioista  Et voi määritellä uutta funktiota toisen funktion sisältä  Funktiot ovat yleensä luokan sisällä (tästä puhutaan seuraavalla luennolla)  Sijoita funktioiden toteutus kutsuvan koodin yläpuolelle  Muussa tapauksessa esittele funktio ennen käyttöä funktion prototyypillä  Funktiot eivät näe toistensa muuttujia

Funktion prototyyppi (jos varsinainen toteutus on vasta myöhemmin) #include void printNum (int myNum); void main ( ) { int num1, num2, num3; num1 = 5; num2 = 7; num3 = 4; printNum (num1); } void printNum (int myNum) { // Remember, printNum can’t see num1, num2 or num3! cout << myNum << endl; } Here’s the prototype

Työlään tuntuinen funktiokutsu? -Esimerkki void main() { //Tama ohjelma piirtaa tikkataulun piirraYmpyra(10,150,200); piirraYmpyra(20,150,200); piirraYmpyra(30,150,200);... } void piirraYmpyra(int sade, int x, int y) {...; } Ärsyttääkö mikään???

Oletusparametrien käyttö funktiossa (default parameters) void main() { //Tama ohjelma piirtaa tikkataulun piirraYmpyra(10); piirraYmpyra(20); piirraYmpyra(30);... } void piirraYmpyra(int sade, int x = 150, int y = 200) {...; }

Oletusparametrit sääntöjä  Funktion parametreille voi antaa oletusarvot  Oletusarvot annetaan funktion toteutuksen esittelyssä.  Funktion määrittely on edelleen samanlainen void piirraYmpyra (int sade, int x, int y); void piirraYmpyra(int sade, int x = 150, int y = 200) {  Funktiota kutsuttaessa parametrin arvon voi jättää kirjoittamatta jos parametrille on määritelty oletusarvo  Funktio käyttää tällöin oletusarvoa  Jos parametrillä ei ole oletusarvoa, niin sitä edeltävillekkään parametreille ei voi antaa oletusarvoa   määritä pakolliset parametrit ensin ja oletusarvoiset parametrit viimeiseksi

Funktioiden uudelleenmäärittely (overloading) void main() { string omaString; int omaInt; tulosta(omaString); tulosta(omaInt); } void tulosta( string x) { cout << “tulostetaan string: “ << x << endl; } void tulosta( int x) { cout << “tulostetaan int: “ << x << endl; }

Funktioiden uudelleenmäärittely (overloading)  Saman nimisestä funktiosta voi tehdä eri versioita  Versiot eroavat toisistaan parametrien määrän tai tyyppien suhteen  Paluuarvot voivat olla samaa tai eri tyyppiä  Jos ainoana erona on paluutyyppi, saadaan käännösvirhe  Kääntäjä osaa valita oikean funktion kutsussa käytettyjen parametrien perusteella.  Käyttöesimerkki: keskiarvon laskeminen käyttäen erityyppisiä parametreja (sen sijaan että toteuttaisimme IntKeskiarvo(), DoubleKeskiarvo(),…

Avoimet funktiot (Inline function)  Funktioon hyppäämiseen ja sieltä palaamiseen kuluu vähän aikaa  Jos funktio on hyvin pieni (2-3) riviä funktio ei ole kovin “kustannustehokas”  Jos funktion esittelyyn liittää varatun sanan inline, kääntäjä kopioi funktion koko sisällön niihin kohtiin missä funktiota kutsutaan  Avoimen funktion kääntöpuoli: koska funktio kopioidaan jokaiseen kutsukohtaan, ohjelmatiedoston koko kasvaa.

Avoin Funktio (inline function) Esimerkki inline int Tuplaa(int) void main() { int luku; cout << “syötä luku: “<< endl; cin >> luku; luku=Tuplaa(luku)...; osta(omaInt); } inline int Tuplaa( int x ) { return 2*x; }

Rekursiiviset Funktiot  Funktio voi kutsua itseään (rekursio)  Käytetään yleensä tilanteissa, missä funktion saamia tietoja käsitellään samalla tavalla kuin funktion tuottamaa tulostakin.  Pidä huolta, että rekursio loppuu jossain pisteessä!

Yhteenveto- Funktiot  Funktio on looginen ryhmä komentoja  Uudelleenkäytettävää koodia  Kirjoita kerran  Kutsu niin monta kertaa kuin haluat  Edut  Uudelleenkäytettävää  Helpottaa abstraktiota  Vähentää monimutkaisuutta  Vähentää koodin pituutta

Yhteenveto- Funktiot  Fuktiot noudattavat seuraavanlaista mallia:  Funktioille voi määritellä oletusparametereja. Kaikkia parametreja ei näin tarvitse täyttää funktiota kutsuttaessa unsigned short int LaskeAla (int pituus, int leveys) Paluuarvon tyyppiFunktion nimiParametrien nimet Parametrien tyypit

Yhteenveto- Funktiot  Saman nimisestä funktiosta voi tehdä eri versioita (overloading)  Funktioille voi määritellä oletusparametereja. Kaikkia parametreja ei näin tarvitse täyttää funktiota kutsuttaessa  Ohjelmasta saadaan tehokkaampi määrittelemällä lyhyet funktiot ”inline”-funktioiksi  Funktio voi kutsua itseään (rekursiivinen funktio)