Ohjelmointiparadigmat PROSEDURAALINEN OHJELMOINTI (CKL) Proseduraalinen ohjelmointi Olio-ohjelmointi Funktionaalinen ohjelmointi Logiikkaohjelmointi Rinnakkaisohjelmointi Piia Räsänen Proseduraalinen ohjelmointi Ohjelma jaetaan toiminnallisiin osiin Top-down Bottom-up Aliohjelmat Abstraktio Parametriohjaus Pääohjelma Suoritus lauseittain, järjestyksessä Ohjausrakenteet Proseduraalinen ohjelmointi Staattiset muuttujat Alkeistieto Taulukot Dynaamiset muuttujat Tietorakenteet Osoittimet (pointterit) C-kieli Historiaa Kehitettiin 1970-luvun alussa Kehittäjä Dennis Ritchie, AT & T:n Bellin laboratorio Alun perin suunnattu järjestelmäohjelmointiin Syntyi UNIX-käyttöjärjestelmää suunniteltaessa Uudelleenkoodauksen kieli Yleistyi pian myös sovellusohjelmoinnissa Standardi ANSI C ANSI/ISO 9899 Ensimmäinen versio 1990 Laajennettu versio 1999 C vs. Java Samankaltainen syntaksi Molemmissa tyypitys C proseduraalinen kieli, Java oliokieli!!! Muistin hallinta Javassa automaattista, C:ssä ohjelmoijan vastuulla C:ssä osoitintyyppi, Javassa viittaus-tyyppi (sama asia, mutta ei sinne päinkään) C:ssä otsikkotiedostot ja makrot Java tulkattava kieli, C käännetään suoraan 1
Termit haltuun Termit haltuun Lause Ohjelman toiminnallinen perusosa Päättyy puolipisteeseen Esim. rakenteinen lause (if, for jne.) Hyppylause (break, continue, goto) Paluulause (return) Koottu lause (lohko) Tyhjä lause (;) Lauseke päätettynä puolipisteeseen Lauseke Ohjelmointikielinen ilmaus, jolla on arvo Vakiot Muuttujat Aritmeettiset laskutoimitukset Funktion kutsut Pääohjelma Ohjelman kääntäminen #include <stdio.h> cs:ssä oleva gcc-kääntäjä int main(void) { printf("hello world!\n"); return 0; } gcc koodi.c./a.out Esimerkki: hello.c Ohjelman kääntäminen Pääohjelma gcc:n parametreja -Wall Tulostetaan myös varoitukset Esimerkki: kaanneltava.c -o Tulostiedosto -ansi ANSI-C:n mukaista koodia Muita pääohjelman otsikkoja void main(void) int main() void main() main() main(void) Käyttöympäristökohtaisia, vanhentuneita jne. ÄLÄ KÄYTÄ! Ikivanhat kääntäjät eivät tunne void-sanaa 2
Pääohjelma Tunnukset Parametrien välittäminen pääohjelmalle int main(int argc, char **argv) int main(int argc, char *argv[]) Sallitut merkit: a-z ja A-Z 0-9 _ (alaviiva) Ensimmäinen merkki ei saa olla numero Käytännössä 1-31 merkkiä Muuttujat Tyypitetty kieli Muuttujan määrittely: double luku; int a, b=8, c; Tulostusfunktio printf() #include <stdio.h> printf(ohjausjono, tieto1, tieto2...); Ohjausjono Aina lainausmerkeissä Voi sisältää ns. konversiomäärittelyitä, joihin parametrina annettavat tiedot viittaavat printf("muuttujan luku arvo on %d.\n",luku); printf():n tavallisimmat konversiomäärittelyt printf():n tavallisimmat konversiomäärittelyt Tyypit %c char Tyypit %f float, double %d %i (signed) int %lf double %u unsigned int %L long double %ld %li long int %s merkkijono %lu unsigned long %o etumerkitön oktaaliluku %x %X etumerkitön heksaluku 3
printf():n tavallisimmat konversiomäärittelyt Kentän leveys & tarkkuus Annetaan %-merkin ja tyypin välissä kentta.tarkkuus printf("%4.2f",doubleluku); Esimerkki: tulostelua.c Perustietotyypit Arvoalueet riippuvat ympäristöstä sizeof(tyyppi) sizeof(muuttuja) Yksittäinen merkki Kokonaisluku Desimaaliluku Merkkityypit Yksittäinen merkki tai pieni kokonaisluku Tilanvaraus (vähintään) yksi tavu (8b) char unisigned & signed Kokonaislukutyypit short int Vähintään16bit int Vähintään 16bit, usein 32bit long int Vähintään 32bit long long int Vähintään 64bit char! Kokonaislukutyypit Signed Etumerkillinen luku Kahden komplementti Unsigned Etumerkitön Pienin arvo nolla Koko sama kuin vastaavalla etumerkillisellä muuttujalla Desimaalilukutyypit Liukulukuja Aina enemmän tai vähemmän likiarvoja float Mantissa vähintään 6 numeroa Eksponentti vähintään [-37,37] double Mantissa vähintään 10 numeroa Eksponentti vähintään [-37,37] long double Mantissa vähintään 10 numeroa Eksponentti vähintään [-37,37] 4
Arvoalueiden rajat Ylivuoto #include <limits.h> CHAR_MIN CHAR_MAX UCHAR_MAX SHRT_MIN SHRT_MAX USHRT_MAX INT_MIN INT_MAX UINT_MAX LONG_MIN LONG_MAX ULONG_MAX LLONG_MIN LLONG_MAX ULLONG_MAX Esimerkki: perustietotyypit.c Jos laskennan tulos menee arvoalueen ulkopuolelle, bitit "valuvat yli" merkitsevästä päästä 01111111 (127 10 ) + 00000010 (2 10 ) 10000001 (-127 10 ) 01111111 (127 10 ) + 01111111 (127 10 ) 11111110 (-2 10 ) Tyypinmuunnokset Lausekkeessa keskenään erityyppisiä operandeja Sijoitusoperaatiossa sijoitettavan arvo eri tyyppiä kuin sijoituksen kohdemuuttuja Yleinen muunnos lausekkeen arvon laskemiseksi Laskennassa ei käytetä int-tyyppiä suppeampaa tarkkuutta Tarkkuus voi kärsiä sijoitettaessa muuttujaan Eksplisiittinen tyypinmuunnos Ohjelmoijan vastuulla! Tyypinmuunnoksen vaikutus muutettavaan arvoon Kokonaisluku kokonaisluku Jos muutettava mahtuu kohteen tyyppiin arvo ja merkki säilyvät Jos muutettava ei mahdu kohteen tyyppiin ratkaisu järjestelmäkohtainan Joka tapauksessa menee pieleen Desimaaliluku kokonaisluku Desimaaliosa jää pois Jos kokonaisosa mahdollista esittää kohdetyypissä arvo ja etumerkki säilyvät Tyypinmuunnoksen vaikutus muutettavaan arvoon Kokonaisluku desimaaliluku Jos muutettavan arvon merkitsevien numeroiden määrä ei ylitä kohtaan merkitsevien numeroiden määrää arvo ja merkki säilyvät Desimaaliluku desimaaliluku Suppeammasta laajempaan arvo ja merkki säilyvät Jos muutettavan arvon merkitsevien numeroiden määrä ei ylitä kohtaan merkitsevien numeroiden määrää arvo ja merkki säilyvät Esimerkki: tyyppitesti.c Totuusarvot C-kielessä ei varsinaista totuusarvotyyppiä Totuusarvot kokonaislukuja epätosi == 0 tosi!= 0 5
Kokonaislukuvakiot Desimaalilukuvakiot Tyyppi voidaan määrätä Esitysmuoto desimaali-, oktaali- tai heksadesimaalijärjestelmän mukaan Oletuksena 10-kantainen int Kokonaislukujen loppuliitteet l, L long (18L) u, U unsigned (18U) Kokonaislukujen etuliitteet 0 oktaaliluku (022) 0x, 0X heksadesimaaliluku (0X12) Tyyppi voidaan määrätä Oletustyyppi double Desimaalilukujen loppuliitteet f, F float (123.4F) l, L long double (123.4L) Eksponenttiesitysmuoto e, E (1.23E+2) Merkkivakiot Erikoismerkkejä Kirjoitetaan heittomerkkien sisään \n \t \a \r \b \f \\ \' \" \? rivinvaihto tabulointi äänimerkki rivin alkuun peruutus sivunvaihto kenoviiva heittomerkki lainausmerkki kysymysmerkki Taulukot Joukko muuttujia, jotka ovat keskenään samaa tyyppiä Taulukon alkiot Vierekkäiset paikat keskusmuistissa alkio_tyyppi tunnus[koko]; int luvut[10]; char merkit[] = {'a','b','c'}; double taulukko[3][4]; Periaatteessa max 12 ulottuvuutta tunnus[indeksi] = alkio; Taulukon ylivuoto Taulukon ulkopuolella olevia alkioita voidaan käyttää Muistiosoite taulukon lopussa Sisältö?! Esimerkki: taulukot.c 6
Nimetyt vakiot #define VUOSI 2009; Operaattorit sitovuusjärjestyksessä () []. -> ++ -- ++ -- sizeof (type) - +! ~ & * * / % + - >> << < > <= >= ==!= & ^ &&?: Bittioperaatiot <<, >> & ~ Bittien siirtäminen yhdellä vasemmalle/oikealle Bittirinnakkainen AND-operaatio Bittirinnakkainen OR-operaatio Binääriluvun komplementti Esimerkki: bittijuttuja.c Laskentajärjestys Operaattoreiden sitovuus Alilausekkeiden arvottamisjärjestystä ei määrätty Poikkeuksena &&? :, Laskentajärjestys pääasiassa vasemmalta oikealle Poikkeuksena pointtereihin liittyvät * ja & sekä sijoitukset Esimerkki: laskentajarjestys.c Laskentajärjestys Sequence point Rajattu osa ohjelmaa, jonka laskenta on irrallaan ympäristöstä Muuttujien arvojen oltava yksikäsitteisiä Optimointi Tätä rikottaessa ratkaisut järjestelmäkohtaisia Raja: Tietyt operaattorit ( &&?: ) Lauseen loppu Myös rakenteiset lauseet Esimerkki: sequencepoint.c Kommentit /* Tämä on kommentti */ // Tämä ei ole kommentti 7
Ehtolause Ehtolause if(ehto) lause; if(ehto) lause; else lausek; if(ehto){ lausea; lauseb; } else { lausec; laused; lausee; } switch-lause Ehdollinen lauseke switch(lauseke){ case vakio1: lauseita; break; case vakio2: lauseita; case vakio3: case vakio4: lauseita; break; default; lauseita; } ehto? lausekea : lausekeb Jos ehto on tosi, lausekkeen arvo on lausekea, muuten lausekeb i = (a>b)? a : b; while-lause do-while-lause while(ehto) lauseke; do lauseke; while(ehto); while(ehto) { lausekea; lausekeb; } do { lausekea; lausekeb; } while(ehto); 8
for-lause Ehdottomat hyppylauseet for(lausekea; lausekeb; lausekec) lause; for(alustus; ehto; päivitys) { lausea; lauseb; lausec; } break Poistuminen switch-rakenteesta Toiston katkaiseminen continue Ohitetaan toistorakenteen rungon loppuosa return Funktiosta poistuminen Ehdottomat hyppylauseet Funktiot goto Siirtyminen määrättyyn koodin kohtaan Erittäin kyseenalainen lause, ei koskaan välttämätön! C:ssä kaikki aliohjelmat ovat funktioita Lähdekoodin määritykset voimassa esittelykohdasta eteenpäin Funktio täytyy olla kirjoitettuna ennen kutsuaan Funktion prototyyppimäärittely tyyppi fkt_nimi(tyyppi par1, tyyppi par2,... tyyppi parn); Esittely mahdollistaa aliohjelman kutsun myös silloin, kun se ei ole "näkyvissä" kääntäjälle Yleensä sama kuin funktion otsikkorivi - runko Pelkät parametrien tyypit riittää Funktion kutsu koostuu funktion nimestä ja suluissa olevasta parametrilistasta Funktiot Funktion kutsu koostuu funktion nimestä ja suluissa olevasta parametrilistasta Parametrittomuus = void Parametrit arvoparametreja Arvo kopioituu Paluuarvo Tietue "Olio ilman metodeja" Kootaan yhteen (eri tyyppistä) tietoa Ohjelmoijan määrittelemä tietotyyppi Voidaan määritellä joko tietotyyppinä tai muuttujan määrittelyn yhteydessä Tietuetyypin esittely voidaan tehdä metodin sisällä, lähdekooditiedostossa irrallisena tai erillisessä otsikkotiedostossa Kenttiin viittaaminen pistenotaatiolla Esimerkki tietueita.c, muistia.c 9
Tietue Omat tietotyypit struct PVM { int pp; int kk; int vv; }; struct PVM pva; pva.pp=21; pva.kk=4; pva.vv=2009; struct { int x,y; } piste; piste.x=2; piste.y=5; typedef tietotyyppi omanimi; Esimerkki: typedef.c, prototyyppi.c Pointterit Pointterit Pointteri on muuttuja, jonka sisältönä on toisen muistipaikan osoite Operaattorit: & muistipaikan osoite * osoitteessa olevan muistipaikan sisältö Pointteri on tyypitetty, sitä määriteltäessä täytyy kertoa sen kohteen tyyppi float palkka = 1500.0; float *p; p = &palkka; Muuttujan arvon käsittely aliohjelmassa Parametrina muistiosoite Pointterin osoittaman muuttujan käsittely Sisältöoperaattorin avulla Indeksoimalla (taulukko) Nuolioperaattorilla (tietue) Esmerkki: pointterit.c, pointterit2.c Syöttöfunktio scanf() #include <stdio.h> scanf(ohjausjono, kohde1, kohde2...); Ohjausjono lainausmerkeissä Mitä tietoa luetaan, konversiomäärittelyt Kohdemuuttujien muistiosoitteet & scanf("%d",&luku); Syöttöfunktio scanf() Tavallisimmat konversiomäärittelyt %d int (10-järjestelmä) %ld long %i int (myös heksa- ja oktaaliluvut) %li long (myös heksa- ja oktaaliluvut) %u unsigned %lu undisgned long %f float %lf double %c char %s char[n] (merkkijono) 10
Funktiot Merkkijono Pointteri parametrina "Muuttujaparametri" Itse parametri on edelleen arvoparametri Pointteri osoittaa muistipaikkaan, joka on varattu kutsuvassa ympäristössä Esimerkki pointteriparametrit.c Taulukko parametrina Pointteri taulukon ensimmäiseen soluun Esimerkki: taulukkoparametrit.c C-kielessä merkkijono on joukko char-muuttujia peräkkäisissä muistipaikoissa char mjono1[10], *mjono2; Merkkijonon lopussa loppumerkki '\0' Käsittely ohjelmoijan vastuulla (virhealtista) Merkkijonovakio voidaan ilmaista lainausmerkeissä Esimerkki: merkkijonoja.c #include <string.h> Esimerkki: merkkijonojenkasittely.c size_t strlen(const char *) size_t erikoistietotyyppi, käytännössä etumerkitän kokonaisluku parametrina osoitin (merkkijonon ensimmäiseen) merkkiin const kertoo, ettei merkkijonoa muuteta funktiossa char *strcpy(char *s1, const char *s2) Kopioi s2:n osoittaman merkkijonon s1:n osoittamaan paikkaan Palauttaa osoittimen s1-merkkijonon alkuun char *strncpy(char *s1, const char *s2, size_t n) Kuten strcpy Kopioi korkeintaan n merkkiä Huom! Jos loppumerkki ei sisälly kopioitaviin, se jää pois! int strcmp(const char *s1, const char *s2) Verrataan s1:n ja s2:n osoittamia merkkijonoja merkki kerrallaan <0 jos s1 ennen s2 ==0 jos s1 ja s2 samat >0 jos s1 s2:n jälkeen int strncmp(char *d, const char *s, size_t n) Kuten strcmp Vertaa korkeintaan n merkkiä alusta lukien 11
char *strcat(char *s1, const char *s2) Yhdistää s2:n osoittaman merkkijonon s1:n osoittaman merkkijonon loppuun Huolehdittava, että s1:lle varattu riittävästi tilaa! char *strncat(char *s1, const char *s2, size_t n) Kuten strcat Liittää korkeintaan n merkkiä char *strchr(const char *s, int c) Etsii merkin c ensimmäisen esiintymän s:n osoittamassa merkkijonossa Palauttaa osoittimen ko. merkkiin (merkkijonoon) Jos merkkiä ei löydy, palauttaa NULL-pointterin char *strstr(const char *s1, const char *s2) Etsii ensimmäistä s2:n osoittamaa alimerkkijonoa s1:n osoittamasta merkkijonosta #include <stdio.h> int sprintf(char *s1, const char *s2,...) Asettaa s1:n osoittamaan merkkijonoon muotoillun merkkijonon s2 int sscanf(const char *s1, const char *s2,...) Lukee s1:n osoittamasta merkkijonosta muotoillun merkkijonon s2 mukaisesti Merkkijonotaulukot #include <stdlib.h> int atoi(const char *); long atol(const char *); double atof(const char *) Määritellään yleensä merkkijonoihin osoittavia pointtereita sisältävänä taulukkona Mahdollista toteuttaa myös kaksiulotteisena merkkitaulukkona 12
Standarditietovirrat Merkkitieto Binääritietovirta Tieto siirtyy sellaisenaan Tekstitietovirta Merkkijono Rivejä Syöttövirta stdin Tulostevirta stdout Yksittäiset merkit char-tyyppiä Merkkivakio heittomerkeissä Merkkitietoa luetaan puskuroidusti Merkkitiedon lukeminen Merkkijonon lukeminen scanf("%c",&merkki); int getchar(void) scanf("%s",&mjono) fgets() Rivinlukufunktio Liittää aina loppuun loppumerkin gets() Jos tila loppuu, loppumerkki jää pois! Esmierkki: lukuajakirjoitusta.c Merkkijonon tulostaminen printf("%s",mjono); puts(const char *); Tiedostojen käsittely Tiedostoa avattaessa ilmoitetaan tiedoston ulkoinen nimi sekä käsittelytapa Lukeminen "r" "rb" Kirjoittaminen "w" "a" "a+" "wb" "ab" "ab+" Päivittäminen "r+" "w+" "rb+" "wb+" Tiedoston lopussa EOF-merkki stdio.h:n symbolinen vakio Tiedosto-osoitin siirtyy automaattisesti luettaessa 13
Tiedoston avaaminen ja sulkeminen FILE *fopen(const char *, const char *); Avaa tiedoston käsittelyä varten Jos avaaminen ei jostain syystä onnistu, palautuu NULL int flcose(file *); Nollasta poikkeava arvo tapahtui virhe Tulisi muistaa tehdä aina! FILE *freopen(const char *, const char *, FILE *); Liittää parametritietovirran tiedostoon Tiedoston alkuun palaaminen void rewind(file *); Palauttaa tiedosto-osoittimen tiedoston alkuun Tekstitiedostoon kirjoittaminen Tekstitiedostosta lukeminen int fputc(int, FILE *); Merkin kirjoittaminen tiedostoon char *fputs(const char *, FILE *); Merkkijonon kirjoittaminen fprintf(file *, const char *,...); Muotoiltu kirjoittaminen int fgetc(file *); Merkin lukeminen tiedostosta char *fgets(char *, int, FILE *); Merkkijonon lukeminen tiedostosta fscanf(file *, const char *,...); Muotoiltu lukeminen Esimerkki: tekstitiedostot.c Binääritiedostoon kirjoittaminen size_t fwrite(const void *, size_t, size_t, FILE *); Osoitin lohkoon Koko 1-n tavua Esim. tietue Lohkon koko ja lohkojen lukumäärä Osoitin tiedostoon Binääritiedostosta lukeminen size_t fread(void *, size_t, size_t, FILE *); Osoitin luettavaan lohkoon Lohkon koko ja lohkojen lukumäärä Osoitin tiedostoon Esimerkki: binaaritiedosto.c 14
Dynaaminen muistialueen varaus include <stdlib.h> void *malloc(size_t n); Varaa muistia n tavua Palauttaa osoittimen varatun alueen alkuun Huom! Tyyppinä void * Muistitila pysyy varattuna kunnes se vapautetaan! void free(void *); Vapauttaa dynaamisesti varatun muistin Lisää dynaamisesta muistin varaamisesta void *calloc(int lkm, size_t n); Varaa muistia lkm kappaletta n tavun lohkoja Muuten kuten malloc void *realloc(void *ptr, size_t n); Suurentaa/pienentää ptr:n osoittaman dynaamisen muistitilan kokoa Alunperin varattu: malloc tai calloc Joko lisätilaa alkuperäisen perään tai kokonaan uusi tila jolloin osoite muuttuu Muistinvarausfunktiot palauttavat NULL (0) jos varaus epäonnistui 15