Funktioesittelyt (declarations) Jos funktiota käytetään ennen sen määrittelyä (definition), se pitää esitellä (declare) - muuten sen tyypiksi oletetaan.

Slides:



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

15. Loogiset operaatiot.
Olio-ohjelmoinnin perusteet luento 3: Muuttujista ja funktioista Sami Jantunen LTY/Tietotekniikan osasto.
© 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
Tietorakenteet ja algoritmit
Taulukoiden määrittely, käsittely ja kopiointi Vaihtoehdot taulukoille
Copyright  Hannu Laine Osoittimet ja taulukot Hannu Laine.
C-kieli ja dynaaminen muistin varaus
22. Taulukot.
Rakenteinen ohjelmointi
C-ohjelmointi, kevät 2006 Taulukot Binääritiedostot Luento
Java-ohjelmointi Opas ammattimaiseen osaamiseen Luku 4 Toistolauseet
OHJELMAN OSITTAMINEN LUOKKA ATTRIBUUTIT METODIT. LUOKKA JAVA ohjelma koostuu luokista LUOKKA sisältää metodeja molemmat sisältävät attribuutteja eli muuttujia.
@ Leena Lahtinen OHJELMAN OSITTAMINEN LUOKKA ATTRIBUUTIT METODIT.
OLIO-OHJELMOINTI PERUSTEET PERUSTIETOTYYPIT
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;
16. Lohkot Sisällys Tutustutaan lohkoihin. Muuttujien ja vakioiden näkyvyys sekä elinikä erityisesti operaation lohkossa. Nimikonfliktit. Muuttujat.
Ohjelmoinnin tekniikkaa Sisällys for -lause lyhemmin. Vaihtoehtoisia merkintöjä aritmeettisille lauseille. Useiden muuttujien esittely.
TAULUKKO YKSIULOTTEINEN TAULUKKO. TAULUKKO  Taulukon tarkoitus Ohjelmassa tarvitaan paljon samantyyppisiä samaan kohdealueeseen kuuluvia muuttujia Näitä.
Sami Jantunen LTY/Tietotekniikan osasto
13. Hyvä ohjelmointitapa (osa 1)
© Jukka Harju, Jukka Juslin
Funktion esittely eli prototyyppi tMyn1 Funktion esittely eli prototyyppi Funktion esittely (function declaration) kertoo funktion nimen, parametrien tyypit.
1 Kertaus koetta varten oleellisista asioista Jukka Juslin.
7. Oliot ja viitteet.
ict1td002 - Copyright Raine Kauppinen 1 Alkuarvot ja tyyppimuunnokset (1/5)  Aiemmin olemme jo antaneet muuttujille alkuarvoja, esimerkiksi: int.
String-vertailusta ja Scannerin käytöstä (1/2)
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.
11. Javan toistorakenteet
19. Olio-ohjelmointia Javalla
4. Attribuutit 4.1. Sisällys Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2.
@ Leena Lahtinen OHJELMAN OSITTAMINEN LUOKKA ATTRIBUUTIT METODIT.
Hyvä ohjelmointitapa (osa 2) Yleistä Lisää hyviä ohjelmointikäytäntöjä: − Jaa pitkä koodi osiin. − Käytä attribuutteja säästeliäästi.
22. Taulukot.
Poikkeukset Yleistä Virheeseen varautuminen tarkoittaa sitä, että ohjelmoija huomioi koodia kirjoittaessaan ajonaikaisen virheen mahdollisuuden.
FunktiottMyn1 Funktiot Funktiot voidaan jakaa –Kirjastofunktioihin, jotka ovat valmiina kaikkien käytössä. Erikoisempien kirjastofunktioiden käyttöönotto.
Antti-Jussi Lakanen Nuorten peliohjelmointi 2009 / Jyväskylän yliopisto.
Tiedon vieminen funktiolle tMyn1 Tiedon vieminen funktiolle, parametrit Argumentin vieminen funktiolle voidaan toteuttaa kahdella menetelmällä: –Pass-by-Value.
1 © Jukka Juslin Luokat, attribuutit ja metodit Yleistietoa: seuraavalla koulutusviikolla tarkempi käsittely.
Ohjelmointi 1. toinen luento1 Taulukot n Kiinteät taulukot: alkioiden määrä tiedetään Dim intCount(12) As Integer 0 indeksit saavat arvoja 0-12 (Option.
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.
Ohjausrakenteet Määräävät ohjelmakoodin suoritusjärjestyksen Ehtolause if – else on muotoa if (lauseke) lause1 else lause2 Jos lauseke on tosi, niin suoritetaan.
Muuttujan osoite int a=1; 0xbfffea64 /* tulostetaan a:n osoite*/ printf(“%p\n”, &a); 0xbfffea68 /* tulostetaan a:n osoite + 1*/ printf(“%p\n”, &a+1); /*
MapInfon tiedostot TAB – Tiedosto, jonka avulla tietokanta avataan MapInfossa. Tiedostossa tietoja kentistä ja koordinaattijärjestelmästä. DAT, XLS. TXT.
String-vertailusta ja Scannerin käytöstä (1/2)
1. Omat operaatiot.
7. Oliot ja viitteet.
2. Taulukot.
Scala Collections.
7. Hyvä ohjelmointitapa..
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)
16. Ohjelmoinnin tekniikkaa
14. Hyvä ohjelmointitapa.
2. Taulukot.
7. Oliot ja viitteet.
7. Hyvä ohjelmointitapa..
5. Aliohjelmien toteutus
7. Näytölle tulostaminen
13. Loogiset operaatiot.
3. Attribuutit.
4. Luokan testaus ja käyttö olion kautta
Jakso 4 Aliohjelmien toteutus
16. Ohjelmoinnin tekniikkaa
Esityksen transkriptio:

Funktioesittelyt (declarations) Jos funktiota käytetään ennen sen määrittelyä (definition), se pitää esitellä (declare) - muuten sen tyypiksi oletetaan int ja argumenteille tehdään oletusmuunnokset (C99:ssä funktion käyttö ennen määrittelyä tai esittelyä on virhe). Funktion esittely on samannäköinen kuin määrittelyn alku, funktion runko (koodi) vain puuttuu: return-tyyppi funktionimi(parametrilista);

/* Esittely (prototyyppi) */ double keskiarvo (double x, double y); /* Määrittely */ double keskiarvo (double x, double y) { return (x+y)/2; } Parametrien nimet voi esittelyssä jättää pois: double keskiarvo(double, double); // ei suositella

K&R -tyyli double keskiarvo(); /* Esittely */ double keskiarvo (x, y) /* Määrittely */ { double x, y; return (x+y)/2; } isum(a, b) /* oletustyyppi int { int a,b; return a+b; } Argumenttien tyyppejä tai määrää ei tarkisteta! Tätä ei pidä käyttää uudessa koodissa.

Parametrit ja argumentit Parametri: funktion määrittelyssä ja esittelyssä näkyvä nimi Argumentti: funktiokutsussa funktiolle välitettävä arvo (konventio, muitakin käytäntöjä näkee) C:ssä kaikki parametrit ovat arvoparametreja, argumentit ovat arvoja (passed by value) eivätkä niihin tehdyt muutokset palaudu kutsuvalle koodille.

int potenssi (int x, int n) { int result = 1; while (n-- > 0) result *= x; return result; } n on funktiolle lokaali kopio, sen muuttaminen ei vaikuta kutsuvaan koodiin.

Taulukkoparametrit int tsumma(int a[], int n) { int i, summa; for (i=0; i<n; i++) summa += a[i]; return summa; } Taulukon koko pitää välittää parametrina - funktio ei voi sitä päätellä. Erityisesti sizeof ei toimi taulukkoparametrin kanssa “luonnollisella” tavalla.

Funktiolle voi välittää taulukon koon liian pienenä, jos haluaa käsitellä vain osaa taulukosta: int a[100]; int tsum(int a[], int n) { int r=0; for (i=0; i<n; i++) r += a[i]; return r; } s10 = tsum(a, 10); // 10:n ens. alkion summa

Funktio voi muuttaa taulukkoparametrin *alkioita*: void tau_plusplus(int a[], int n) { int i; for (i=0; i<n; i++) a[i]++; return; }

Moniulotteisen taulukkoparametrin koko pitää määritellä ensimmäistä ulottuvuutta lukuunottamatta: int t2sum (int a[][10], int n) { int i,j,r; for (i=0; i<n; i++) for (j=0; j<10; j++) r+=a[i][j]; return r; }

C99:ssä taulukkoparametri voi olla muuttuvankokoinen: int tsum (int n, int a[n]) // huom. n ensin! // jos esittelyssä halutaan jättää nimet pois: int tsum (int, int a[*]); int tsum (int, int []); Taulukon kokoa ei kuitenkaan tarkisteta automaattisesti! Muuttuvakokoiset taulukot ovat hyödyllisimpiä moniulotteisten kanssa: int tf(int n, int m, int a[n][m], int b[m+n])

C99:ssä voi taulukkoparametrin *minimikoon* määrätä avainsanalla static: int tsum (int a[static 3], int n) Tämä on vain optimointivihje kääntäjälle, ohjelman toimintaan se ei muuten vaikuta. Moniulotteisen taulukon tapauksessa vain ensimmäiselle saa antaa static-määreen.

C99:ssä voi funktiokutsuissa käyttää vakiotaulukoita: t = tsum ((int[]){ 1, 2, 3}, 3); t = tsum ((int[]){ a, b*2, c+d, 5 }, 4);

return-lause Funktion suoritus päättyy return-lauseeseen tai void- tyyppisen myös viimeiseen }-merkkiin. return-lauseen argumentti saa olla mielivaltainen lauseke, se muunnetaan funktion tyyppiä vastaavaksi (kuten sijoituksessa). void-funktiossa return ei ole tarpeen mutta laillinen, ilman argumenttia. Muissa se on käytännössä (muttei muodollisesti) pakollinen: sen puuttuessa funktion arvoa ei saa käyttää.

Ohjelman lopetus main() on funktio, jonka loppu on samalla ohjelman loppu. Se voi päättyä joko return -lauseeseen tai exit() - funktiokutsuun: return n; exit(n); ovat ekvivalentteja main() -funktiossa; muissa funktioissa exit() lopettaa (pää!)ohjelman, return vain ao. funktion.

Yleensä pääohjelman pitäisi palauttaa statuskoodi. Yleisin konventio: nolla onnistuneesta suorituksesta, jotain nollasta eroavaa muuten. Luettavuuden ja siirrettävyyden parantamiseksi voi käyttää makroja: #include exit(EXIT_SUCCESS); exit(EXIT_FAILURE); Jos main() päättyy ilman return- tai exit()-kutsua, ohjelman paluuarvo voi olla mitä vain.

Rekursio Funktio voi kutsua itseään: int kertoma (int n) { if (n<=1) return 1; else return n*kertoma(n-1); } Kaksi (tai useampi) funktio voi myös kutsua toisiaan; tällöin ne pitää yleensä esitellä ensin.

Muuttujista ja näkyvyysalueista Tunnisteen (muuttuja, funktio, tyyppi ym) näkyvyysalue (scope) määrää missä kohdassa koodia sitä voi käyttää, ja erityisesti myös mitä käytetään jos samaa tunnistetta on käytetty useaan kertaan.

Paikalliset muuttujat Funktion sisällä määritelty muuttuja on ko. funktiolle paikallinen, lokaali: sitä voi käyttää vain sen sisällä: int numerosumma(int n) { int summa=0; // lokaali muuttuja while (n) { summa += n%10; n/=10; } return summa; }

Yleisemmin {} -lohkon sisällä määritelty muuttuja näkyy vain siellä, ja peittää näkyvistä ulompana määritellyn: int a(int b) { int i=1; { int i=2; printf(“%d “,i); } // 2 printf(%d\n”, i); // 1 } Muuttujalla sanotaan olevan lohkonäkyvyys (block scope).

C99:ssä muuttujan voi määritellä keskellä lohkoakin, silloin se näkyy sen loppuun: { int i=1; { printf(“%d\n”, i); // 1 int i=2; printf(“%d\n”, ++i); // 3 } printf(“%d\n”, i); // 1 }

Muuttujan säilyvyys Oletuksena paikallisten muuttujien säilyvyys (storage duration) on “automaattinen”: niille varataan muistipaikka määriteltäessä ja se vapautetaan lohkon päättyessä. Avainsanalla “static” voi määritellä muuttujan pysyväksi niin, että sen arvo säilyy funktion kutsujen välillä.

int laskuri(void) { static int k=0; // alustus tehdään vain kerran return ++k; } int main() { int k=7; // ei vaikuta laskuriin printf(“%d\n”, laskuri()); // 1 printf(“%d\n”, laskuri()); // 2 printf(“%d\n”, laskuri()); // 3...

Globaalit muuttujat Muuttujan voi määritellä myös funktion ulkopuolella. Silloin sen näkyvyysalue on koko tiedosto määrittelykohdasta alkaen, ja säilyvyys aina staattinen (static-avainsanaa ei tarvita). Globaaleja muuttujia on yleensä syytä välttää.

int n=0; int laskuri(void) { return ++n; } int main() { n=5; printf(“%d\n”, laskuri()); // 6 printf(“%d\n”, laskuri()); // 7 return 0; }

Ohjelman organisoinnista C on varsin vapaamielinen eri ohjelmaelementtien järjestyksen suhteen, mutta järjestys vaikuttaa. Helpointa on laittaa elementit johdonmukaisesti esim. näin: #include -direktiivit #define -direktiivit tyyppimääritykset globaalien muuttujien määritykset funktioiden esittelyt (pl. main) main() muiden funktioiden määritykset

Osoittimet (pointterit) C:n ehkä tärkein (ja vaikein) erikoispiirre on osoittimet (pointterit, engl. pointers). Osoitin on periaatteessa vain kokonaisluku, joka kertoo missä päin muistia tietty muuttuja (tms) sijaitsee (vrt. taulukon indeksi). Osoittimia ei kuitenkaan voi käsitellä aivan samoin kuin kokonaislukuja: ne voivat olla eri kokoisia ja niillä laskemisessa on omat sääntönsä.

Osoitinmuuttuja on muuttuja, joka voi sisältää osoittimen, toisen muuttujan (tms) osoitteen - sanotaan, että se osoittaa tai viittaa tähän. Kukin osoitinmuuttuja voi viitata vain yhdentyyppisiin muuttujiin, ja ne määritellään lisäämällä määrityksessä * viitatun tyypin eteen: int *p; double *q; int a, *i; // a normaali int, i int-osoitin Viitattu tyyppi saa olla mikä vain, myös taulukko tai vaikka toinen osoitintyyppi.

Osoiteoperaattorilla & saa muuttujan osoitteen, jonka voi sijoittaa osoitinmuuttujaan: int a; int *p; p = &a; Osoitinmuuttujan voi myös alustaa tähän tapaan: int a, *p=&a;

Viittausoperaattorilla (indirection operator) * voi käyttää osoittimen (osoitinmuuttajan tai lausekkeen) osoittaman muuttujan sisältöä: int a, *p=&a; *p = 5; printf(“%d\n”, a); // 5 Huom. *:llä on eri merkitys määrittelylauseessa kuin lausekkeessa!

Osoite- ja viittausoperaattorit ovat tavallaan toistensa käänteisoperaatioita: a = *&b; // sama kuin “a = b” (jos b muuttuja) a = &*b; // sama kuin “b=a” jos b osoitinmuuttuja // (muuten “*b” ei ole laillinen)

Samaan muuttujaan voi osoittaa useampi osoitinmuuttuja yhtaikaa, ja osoitinmuuttujan voi sijoittaa toiseen samantyyppiseen osoitemuuttujaan. int i=3, j, *q; int *p = &i; q = &j; // ei tähteä *! *q = *p; // j=i (3) q = p; // nyt myös q osoittaa i:hin *q = 5; // i=5 printf(“i=%d, j=%d\n”, i, j); // 5, 3

Osoitinargumentit Funktion argumentti voi olla osoitin, ja silloin funktio voi muuttaa sen osoittamaa muuttujaa: void int_swap(int *a, int *b) { int t = *a; *a = *b; *b = t; } int x=5, y=6; int_swap(&x, &y); // kutsussa &

Osoitinargumenttina voi olla myös osoitinmuuttuja, ja silloin &-merkkiä ei tarvita: int a=5, b=6; int *p = &b; int_swap(&a, p); scanf(“%d”, p); // scanf(“%d”, &b);

void min_max(int a[], int n, int *min, int *max) { int i; *min = *max = a[0]; for (i=0; i<n; ++i) { if (a[i]<*min) *min=a[i]; if (a[i]>*max) *max=a[i]; } int t[100] = { 64,2,745,-456,8,5,6 }; // loput nollaa int m, n; min_max(t, 100, &m, &n);

Osoitinargumentin voi määritellä vakioksi niin, että sen osoittamaa muuttujaa ei saa muuttaa: int f(const int *a, int j) { *a = 0; // VIRHE a = &j; // OK Tuo ei estä itse a:n (paikallisen kopion) muuttamista. Jos sitä halutaan: int f(int * const a, int j) { { *a = 0; // OK a = &j; // VIRHE Molemmatkin voi tehdä: int f(const int * const a, int j) { //...

Funktion paluuarvokin voi olla osoitin: int *min(int *a, int *b) { if (*a<*b) return a; else return b; } int *p, i=5, j=6; p = min(&i, &j); *p = 3; // i=3 *min(&i,&j)=3;

Paluuarvo voi olla myös globaalin tai staattisen paikallisen muuttujan osoite: int *laskuri(void) { static int n=0; n++; return &n; } int *p; printf(“%d\n”, *laskuri()); // 1; *laskuri() = 6; printf(“%d\n”, *laskuri()); // 7

Myös taulukon yksittäisillä alkioilla on omat osoitteensa: int a[10] = { 1, 2, 3}, *p = &a[5]; int *tmax(int a[], int n) { int i, *t=&a[0]; for (i=0; i<n; i++) if (a[i] > *t) t = &a[i]; return t; } *p=-4; p = tmax(a,10); *p = 6;

Osoittimilla laskeminen Osoittimille on määritelty kolme laskutoimitusta: * Kokonaisluvun lisääminen osoittimeen; * Kokonaisluvun vähentäminen osoittimesta; ja * Osoittimen vähentäminen osoittimesta Yleensä nämä ovat hyvin määriteltyjä vain osoittimen osoittaessa (samaan) taulukkoon.

Olennaisesti “osoitin + 1” == “osoitin taulukon seuraavaan alkioon”. Osoitteita ajatellen tämä tarkoittaa osoitteen kasvattamista taulukon alkion koolla. Jos sizeof(int)=4 ja int-muuttujan x osoite on 8, &x + 1 osoittaisi osoitteeseen 12. Jos char-muuttujan c osoite olisi 8, &c + 1 osoittaisi osoitteeseen 9. Osoititinten “raa'at” arvot saa printf-formaatilla %p: printf(“%p\n”, &x);

int a[10] = { 1, 2, 3 }, *p, *q, n; p = &a[1]; q = p + 5; *q = 6; // a[6]=6 *(q += 2) = 8; // a[8]=8, q=&a[8] *p++ = 11; // a[1]=11, p=&a[2] *--q = 7; // a[7]=7, q=&a[7] n = q - p; // 5

int a[N], *p, summa=0; for (p=&a[0]; p<&a[N]; ++p) summa += *p; Huom: p<&a[N] on sallittu vaikka a[N]:ää ei ole - taulukon “viimeistä seuraavan” alkion osoitteen saa laskea tällä tavoin. Taulukon nimeä voi käyttää osoittimena (osoittaa ensimmäiseen alkioon): p=a; while (p < a+N) summa += *p++;

Funktion argumenttina taulukkoa kohdellaan kuten osoitinta: void nollaa(int a[], int n) { int *p; for (p=a; p<a+n; p++) *p=0; } Parametriksi voi kirjoittaa osoittimen, vaikutus on sama: void nollaa(int *a, int n)

Osoitinta voi myös käyttää kuten se olisi taulukko: int i, a[N], *p = a, sum=0; for (i=0; i<N; i++) sum += p[i]; Yleisesti: p[i] == *(p+i) (mistä seuraa myös että p[i] == i[p]!)

Taulukko ja osoitin ovat yleensä keskenään vaihtokelpoisia funktioiden määrittelyissä ja esittelyissä, lausekkeissa ja funktiokutsuissa, mutta eivät muuttujamäärittelyissä eikä esim. sizeof'in (ei funktio vaan operaattori!) kanssa.

Kaksiulotteinen taulukko on C:n mielestä yksiulotteinen taulukko, jonka alkiot ovat myös yksiulotteisia taulukoita, ja taulukon nimi on tyypiltään osoitin yksiulotteiseen taulukkoon: int a[10][10]; int (*p)[10]; // sulut välttämättömät p=a; (*p)[1] = 5; // a[0][1] (*++p)[6] = 7; // a[1][6]

Kaksiulotteisen taulukon riviä voi käsitellä kuten yksiulotteista taulukkoa yleensäkin: int a[10][10], (*p)[10]; p = &a[2]; // toinen rivi void nollaa(int a[], int n) { for(int i=0; i<n; i++) a[i]=0; // C99 } nollaa(a[3], 10); // nollataan rivi 3

Sarakkeen nollaus: int a[5][6], (*p)[6], sar; for (p= &a[0]; p<&a[5]; ++p) (*p)[sar]=0; Silmukassa p osoittaa aina kutakin riviä, *p rivin ensimmäistä alkiota ja (*p)[sarake] ko. rivin alkiota sar. Huom: p on osoitin int[6] -taulukkoon - jollaista *ei* käytetä käsiteltäessä yksittäistä int[6]-taulukkoa (siihen käytettäisiin int-osoitinta).

Kaksiulotteista taulukkoa voi kohdella yksiulotteisena: int a[10][10], *p, *q; p=&a[0][0]; q=p+100; while (p<q) *p++=0; Toimii melkein kaikilla kääntäjillä, periaatteessa kiellettyä nykyisin.

int *asum(int *a, int *b, int n) { int *p = b; while (p<b+n) *a+=*b; return a; }

int a[100], *p=a; *(p+1) * *(p+2)... // toimii int a, b, c, *p=a; *(p+1) * *(p+2)... // EI aina toimi! // muuttujien järjestys muistissa voi olla mikä vain