Esittely latautuu. Ole hyvä ja odota

Esittely latautuu. Ole hyvä ja odota

Struct struct on tietotyyppi, joka koostuu kokoelmasta eri tyyppisiä, nimellä viitattavia elementtejä, jäseniä (members): struct { int tuotenumero; char.

Samankaltaiset esitykset


Esitys aiheesta: "Struct struct on tietotyyppi, joka koostuu kokoelmasta eri tyyppisiä, nimellä viitattavia elementtejä, jäseniä (members): struct { int tuotenumero; char."— Esityksen transkriptio:

1 struct struct on tietotyyppi, joka koostuu kokoelmasta eri tyyppisiä, nimellä viitattavia elementtejä, jäseniä (members): struct { int tuotenumero; char nimi[NIMEN_PITUUS + 1]; int varastossa; } osa1, osa2; struct'in jäsenten nimet näkyvät vain sen sisällä, jokaisella struct'illa on oma nimiavaruus.

2 struct'in alustus struct { int tuotenumero; char nimi[NIMEN_PITUUS + 1]; int varastossa; } osa1 = { 1, “vasara”, 57 }, osa2 = { 2, “kirves”, 13 }, osa3 = { 3, “sirppi”, 1 }; Alustuksessa saa yleensä käyttää vain vakioita (funktion sisällä myös sen parametreja) ja arvojen pitää olla samassa järjestyksessä kuin vastaavien jäsenten määrittelyssä; puuttuvat nollataan.

3 C99 tarjoaa enemmän alustusmahdollisuuksia: struct { int tuotenumero; char nimi[NIMEN_PITUUS + 1]; int varastossa; } osa1 = {.nimi=”vasara”,.tuotenumero= ++tuotelaskuri,.varastossa=57 }; C99 sallii muuttujien käytön alustuksessa, ellei alustettava muuttuja ole static.

4 struct'in jäseniin viitataan pisteellä (joka on tässä operaattori, prioriteetiltaan sama kuin postfix++ ym eli kaikkein korkein): osa1.varastossa = 66; osa2.varastossa--; printf(“%s:aa on varastossa %d\n”, osa3.nimi, osa3.varastossa);

5 Toisin kuin taulukon, struct'in voi kopioida suoraan sijoittamalla: osa1 = osa2; Tämä onnistuu myös jos structin jäsenenä on taulukko (tai useampi): struct { int a[10]; } x, y;... x=y; // OK Vertailu sen sijaan ei onnistu: if (x==y) {... // VIRHE

6 struct-tyypille voi antaa tunnisteen (tag): struct osa { int tuotenumero; char nimi[NIMEN_PITUUS + 1]; int varastossa; }; jota voi sitten käyttää muuttujamäärittelyissä: struct osa osa1, osa2; struct-tunnisteilla on oma nimiavaruutensa, ja ne toimivat vain struct-sanan kanssa.

7 Tunnisteen voi antaa samalla kun määrittelee muuttujia: struct osa { int tuotenumero; char nimi[NIMEN_PITUUS + 1]; int varastossa; } osa1, osa2; struct osa osa3, osa4; // “struct” pakollinen

8 Myös typedef toimii structin kanssa: typedef struct { int tuotenumero; char nimi[NIMEN_PITUUS + 1]; int varastossa; } osa; osa osa1, osa2; // ei struct-sanaa

9 Yleensä on sama käyttääkö struct-tunnistetta vai typedef-määritystä (molempiakin voi käyttää muttei yleensä kannata), mutta joissakin tilanteissa vain ensinmainittu toimii (linkitetyt listat, joissa struct sisältää osoittimen omaan tyyppiinsä). structia voi käyttää sekä funktion parametrina että paluuarvona. Se välitetään arvona (kopioimalla) eikä osoittimena kuten taulukko - silloinkin kun sen sisällä on taulukko.

10 C99:ssä voi käyttää struct-vakioita: print_osa( (struct osa){ 4, “ruuvi”, 57 } ); varaosa = { 5, “naula”, 0 }; piilo_osa = {.tuotenumero=6,.nimi=“mutteri” }; Puuttuvat jäsenet nollataan tässäkin.

11 Taulukoita ja structeja saa käyttää sisäkkäin vapaasti, taulukko voi sisältää structeja, struct voi sisältää paitsi taulukoita myös structeja jne. struct kokonimi { char etunimi[N]; char sukunimi[N]; }; struct opiskelija { struct kokonimi nimi; int numero, ika; char sukupuoli; }; struct opiskelija opiskelijat[100]; printf(“%s\n”, opiskelijat[5].nimi.etunimi);

12 struct-taulukon alustus: struct suuntanro { char *maa; int koodi; }; const struct suuntanro maakoodit[] = { {{ “Suomi”, 357}, { “Ruotsi”, 46}, {“USA”, 1}}; Sisemmät aaltosulut eivät ole pakollisia mutta luettavuuden kannalta suositeltavia. struct osa varasto[100] = { [0].tuotenumero=5, [0].nimi=”rautakanki” }; // C99

13 struct'in osoite on sama (mutta erityyppinen) kuin sen ensimmäisen jäsenen: struct laji { char tag; int lkm; } kala = { 'a', 2 }; char *n = &kala.tag; // == (char*) &kala; Jäsenten välissä (ja viimeisen jäljessä) voi olla tyhjää: sizeof(char)==1, sizeof(int)==4, sizeof(laji)==8

14 union union on myös tietotyyppi, jolla on monta mahdollisesti erityyppistä jäsentä, mutta ne sijaitsevat muistissa samassa paikassa, (osin) päällekkäin, ja yhden muuttaminen muuttaa muitakin: union { int i; double d; } Vain viimeksi muutetun jäsenen arvo on standardin mukaan yleensä määritelty.

15 union käyttäytyy syntaktisesti hyvin samaan tapaan kuin struct. Alustuksessa arvon voi antaa vain ensimmäiselle jäsenelle: union { int i; double d; } u = { 0 }; C99:ssä käy myös union { int i; double d; } u = {.d = 10.0 };

16 union voi säästää muistia etenkin struct'in kanssa. Esim. kahdenlaisia laatikoita, suorakulmaisia ja erikoisia, jälkimmäisistä vapaamuotoinen kuvaus: struct laatikko { int numero; double hinta; BOOL suorak; union { struct { double pituus, leveys, korkeus; }; char kuvaus[MAX]; }

17 unionin avulla voi tehdä sekatyyppisiä taulukoita: typedef union { int i; double d; } Numero; Numero taulu[N]; taulu[0].i = 5; taulu[1].d = 2.5; Huom. talletetuista arvoista ei ole mitään tapaa päätellä kumpana tyyppinä ne on talletettu!

18 Kulloinenkin tyyppi voidaan kuljettaa structissa: typedef struct { int tyyppi; union { int i; double d; } u; } Numero; Numero taulu[N]; taulu[5].tyyppi=0; taulu[5].u.i=4; taulu[5].tyyppi=1; taulu[5].u.d=3.14; void print_num(Numero n) { if (n.tyyppi==0) printf(“%d\n”, n.i) else printf(“%f\n”, n.d); }

19 enum enum maa { PATA, RISTI, RUUTU, HERTTA }; määrittelee luetellun tyypin “maa” ja sille arvot. Sitä voi sitten käyttää muuttujamäärittelyyn: enum maa a, b, c;

20 enum toimii myös typedef'in kanssa: typedef enum { PATA, RISTI, RUUTU, HERTTA } maa; maa a, b, c; #if __STDC_VERSION__ < 199001L typedef enum { false, true } bool; #endif

21 Vertaa: #define maa int #define PATA 0 #define RISTI 1 #define RUUTU 2 #define HERTTA 3 vs. typedef enum { PATA, RISTI, RUUTU, HERTTA } maa;

22 ● enum on “kannen alla” int, luetellut arvot ovat oikeasti vain nimettyjä kokonaislukuvakioita ● enum noudattaa C:n näkyvyyssääntöjä toisin kuin makrot: funktion sisällä määritelty enum näkyy vain siellä (structin sisällä määritelty enum näkyy siellä missä ko. structkin) ● enum-arvojen pitää olla yksikäsitteisiä toisin kuin muuttujanimien tai structin jäsenten, ne eivät peitä ulompana määriteltyjä

23 enum-vakioiden arvot ovat oletuksena 0, 1, 2,..., mutta ne voi myös määritellä eksplisiittisesti (kaikki tai osan, oletusarvo on aina edellinen+1): enum maa { PATA=1, RISTI=2, RUUTU=3, HERTTA=4 }; enum maa { PATA=1, RISTI, RUUTU, HERTTA }; // sama enum osasto { IT=7000, THK=4000, }; // loppupilkku ok enum-muuttujia voi kohdella kuten int-muuttujia, eikä niiden arvoja tarkisteta: enum maa m; // myös “int m;” toimii for (m=PATA; m<=HERTTA; m++) {... } int s = PATA; s++; // s==2 enum maa t; t=5; // toimii (valitettavasti)

24 enum-arvoja voi käyttää taulukoiden indekseinä, C99:ssä myös alustuksessa: enum arkip = { MA,TI,KE,TO,PE }; const char *menu[] = { [MA]=”keitto”, [TI]=”puuro”, [KE]=”pizza”, [TO]=”pihvi”, [PE]=”mureke” };

25 enum toimii hyvin unionin tyyppimarkkerina: typedef struct { enum { INT_T, DBL_T } tyyppi; union { int i; double d; } u; } num; void print_num(num n) { if (n.tyyppi == INT_T) printf(“%d\n”, n.u.i); else printf(“%f\n”, n.u.d); } int main() { num a, b = { INT_T, { 5 } }; a.tyyppi=DBL_T; a.u.d=2.5; print_num(a); print_num(b); return 0; }

26 Dynaaminen muistivaraus Normaalisti C:n tietorakenteet ovat kiinteän kokoisia (poikkeuksena C99:n muuttuvankokoiset taulukot, mutta niidenkään kokoa ei voi muuttaa sen jälkeen kun ne on luotu). Funktioiden sisällä paikallisten (ei-static) muuttujien muisti varataan dynaamisesti ja vapautetaan funktion lopussa, mutta funktion suorituksen ajan ne ovat kiinteän kokoisia eikä niitä voi palauttaa kutsuvalle ohjelmalle.

27 malloc, calloc & realloc Varsinaiseen dynaamiseen muistinvaraukseen (“allokointiin”) C:ssä on käytettävissä kolme funktiota: malloc: varaa muistilohkon alustamatta sitä calloc: varaa muistilohkon ja nollaa sen (hitaampi) realloc: muuttaa aikaisemmin varatun muistilohkon kokoa Niiden määritykset löytyvät stdlib.h:sta.

28 Koska malloc &c eivät tiedä minkätyyppiselle datalle muistia ollaan milloinkin varaamassa, ne palauttavat geneerisen osoittimen, tyyppiä void*, joka muunnetaan automaattisesti tarvittavaksi tyypiksi. Jos muistin varaus jostain syystä epäonnistuu (muistia ei riitä tms), palautettu arvo on NULL (null pointer). Osoitinta voi myös verrata (int) nollaan, historiallisista syistä se muunnetaan osoittimeen verrattaessa niin että vertailu toimii.

29 Muistinvarauksen onnistuminen on *aina* syytä tarkistaa: p = malloc(10000); if (p == NULL) { // myös “if (!p) {“ toimii fprintf(stderr, “muisti loppui\n”); exit(EXIT_FAILURE); }

30 malloc() malloc-funktion prototyyppi on tällainen: void *malloc(size_t size); size on varattavan muistilohkon koko tavuina (char = 1 tavu). Tyyppi void* muunnetaan automaattisesti, mutta dokumentoinnin vuoksi voi käyttää eksplisiittistä typecastia: #define STRLEN 80 char *p; p = (char*) malloc(STRLEN+1); // +1 loppunollaa varten

31 Esim. strcat-tyyppinen funktio, joka ei muuta argumenttejaan vaan palauttaa uuden merkkijonon: char *mycat(const char *s1, const char *s2) { char *r; r = malloc(strlen(s1)+strlen(s2)+1); if (!r) { printf(“Muisti loppui!\n”); exit(EXIT_FAILURE); } strcpy(r, s1); strcat(r, s2); return r; }

32 Osoitetaulukkona toteutetun merkkijonotaulukon käsittely dynaamisesti: char s[101], *p[10], int i; for (i=0; i<10; i++) { scanf(“%100s”, &s); p[i]=malloc(strlen(s)); if (!p[i]) { virhe(); } strcpy(p[i], s); }

33 Muilla kuin merkkijonoilla varattavan muistin koko pitää laskea sizeof'in avulla. Vertaa: int a[10]; int *a; a = malloc(10*sizeof(int)); Kummassakin tapauksessa a:ta käytetään samalla tavalla.

34 calloc() calloc-funktion prototyyppi on tällainen: void *calloc(size_t nmemb, size_t size); Siinä ensimmäinen argumentti on alkioiden lukumäärä ja toinen koko tavuina: int *a; a = calloc(sizeof(int), 10); Toisin kuin malloc, calloc alustaa varaamansa muistin nolliksi. Muistinvarauksen epäonnistuessa sekin palauttaa NULLin.

35 realloc() Aikaisemmin varatun muistilohkon kokoa voi muuttaa realloc- funktiolla: void *realloc(void *ptr, size_t size); Ensimmäinen parametri on aikaisemman malloc-, calloc- tai realloc-kutsun palauttama osoitin, paluuarvo osoitin (mahdollisesti siirtyneeseen) uuden kokoiseen lohkoon. Jos realloc ei pysty varaamaan tarvittavaa muistia, se palauttaa NULLin; alkuperäinen varaus säilyy. Muistilohkoa laajennettaessa uutta ei alusteta. realloc(NULL, size) on sama kuin malloc(size), realloc(ptr, 0) on sama kuin free(ptr).

36 free() C ei vapauta dynaamisesti varattua muistia automaattisesti, vaan se pitää tehdä eksplisiittisesti. Sitä varten on funktio free: void free(void *ptr); Huomaa erityisesti tilanne, jossa varattuun muistilohkoon ei viittaa yksikään osoitin: sitä ei voi käyttää eikä myöskään vapauttaa enää mitenkään! (Joissakin kielissä tällaiset siivotaan automaattisesti ns. garbage collectorilla, C:ssä sellaista ei ole.) Varo myös käyttämästä osoitinta sen viittaaman muistin vapauttamisen jälkeen (“dangling pointer”).

37 Linkitetyt listat Linkitetty lista toteutetaan C:ssä yleensä structilla, jonka yhtenä jäsenenä on osoitin samaan struct-tyyppiin: struct solmu { int arvo; struct solmu *seuraava; } struct solmu *alku = NULL; struct solmu *uusi;

38 -> -operaattori uusi = malloc(sizeof(struct solmu)); // EI sizeof(uusi)! (*uusi).arvo = 5; Pointterin osoittaman structin alkioon viittaamiseen on lyhyempikin keino, -> -operaattori: uusi->arvo = 5; scanf(“%d”, &uusi->arvo); // & tarvitaan

39 Solmun lisäys listan alkuun: uusi->seuraava = alku; alku = uusi; Listan läpikäynti käy vaikka for-silmukalla: for (p = alku; p != NULL; p = p->seuraava) { if (p->arvo == 5) {... } }

40 Listasta poistaminen: struct solmu *poista(struct solmu *lista, int n) { struct solmu *nyk, *ed; for (nyk=lista, ed=NULL; nyk!=NULL && nyk->arvo!=n; ed=nyk, nyk = nyk->seuraava) ; if (nyk==NULL) return lista; // ei löytynyt if (ed==NULL) lista=lista->seuraava; // listan alussa else ed->seuraava = nyk->seuraava; free(nyk); return lista; }

41 pointteripointterit Osoitin voi osoittaa osoittimeen, kuten merkkijonojen ja osoitintaulukoiden kanssa on jo nähty. Se on tarpeen myös jos halutaan tehdä funktio, joka muuttaa osoitinta osoittamaan jonnekin muualle. void lisaa_listaan(struct solmu **lista, n) { struct solmu *uusi; if (!(uusi=malloc(sizeof(struct solmu))) { virhe(); } uusi->arvo=n; uusi->seuraava=*lista; *lista=uusi; }

42 Funktiopointterit Osoittimilla voi viitata myös funktioihin. Esimerkiksi funktio, joka tulostaa taulukon funktion arvoja: void taul(int(*f)(int), int alku, int loppu, int askel) { int x; for (x=alku; x<=loppu; x+=askel) { printf(“%5d %10d\n”, x, (*f)(x)); }

43 Arvojen taulukointi kävisi nyt näin: int nelio(int x) { return x*x; } taul(nelio, 1, 10); Kun argumenttina on funktion nimi ilman sulkuja, se tulkitaan funktio-osoittimeksi. Yleisemminkin: int (*f)(int); f = nelio; // ei &-merkkiä taul(f, 2,5);

44 Funktio-osoitinta voi käyttää funktion kutsumiseen myös ilman (*)-notaatiota: void taul(int(*f)(int), int alku, int loppu, int askel) { int x; for (x=alku; x<=loppu; x+=askel) { printf(“%5d %10d\n”, x, f(x)); } Yleensä lienee kuitenkin parempi kirjoittaa (*f)(x), että lukija heti näkee kyseessä olevan osoittimen.

45 Funktio-osoittimen voi myös palauttaa funktion arvona, niitä voi tallettaa taulukkoon tai käyttää structin tai unionin jäsenenä. struct fun { char nimi[4]; double (*f)(double); double esim; }; struct fun trigs[3] = { { “sin”, sin, 0.5 }, { “cos”, cos, 1.0 }, { “tan”, tan, 2.0 }}; for (i=0; i<3; i++) printf(“%s(%f)=%f\n”, trigs[i].nimi, trigs[i].esim, trigs[i].f(trigs[i].esim));

46 Esim: funktio joka kysyy käyttäjältä mitä funktiota käytetään johonkin ja palauttaa osoittimen siihen. double (*menu(void))(double) { while (1) { printf(“Valitse: s=sin, c=cos, t=tan? “); switch(getchar()) { case 's': return sin; case 'c': return cos; case 't': return tan; } double (*f)(double); f = menu(); y = f(x); // tai (*f)(x)

47 restrict C99:ssä voi osoittimelle antaa määreen restrict: int * restrict p; Tämä on lupaus kääntäjälle, että osoitti p mihin tahansa, sitä ei muuteta muuten kuin p:n avulla. Kääntäjä ei tarkista sitä mutta voi käyttää sitä hyväkseen optimoinnissa.

48 struct hack Joskus structin sisään halutaan vaihtuvankokoinen taulukko. Esim. oma merkkijonotyyppi, jossa merkkijonon sisällä voi olla nul-merkkejä, voisi olla tällainen: struct vstring { int len; char chars[N]; } Tilaa ei kuitenkaan haluttaisi varata turhaan.

49 Klassinen ratkaisu tähän on ns. struct hack: määritellään taulukon kooksi 1 mutta varataan sille tilaa oikeasti tarvittava määrä: struct vstring { int len; char chars[1]; /* dummy */ } struct vstring *str = malloc(sizeof(struct vstring) + n - 1); str->len = n; Standardi ei takaa tämän toimivuutta, mutta se on silti hyvin yleinen ja toimii ainakin melkein kaikkialla. GCC:ssä toimii myös “char chars[0];”, standardi ei salli sitäkään.

50 C99:ssä on tähän siistimpi ratkaisu: struct vstring { int len; char chars[]; } struct vstring *str = malloc(sizeof(struct vstring) + n); str->len=n; Muuttuvankokoisen taulukon täytyy olla structin viimeinen jäsen, siinä pitää olla ainakin yksi muu jäsen, ja structin kopiointi = -operaattorilla ei kopioi muuttuvaa jäsentä. Tällaista structia ei myöskään voi käyttää toisen structin tai unionin jäsenenä eikä taulukon alkiona.

51 Esittelyt (declarations) Esittely (declaration) tarkoittaa yleisesti tunnisteen merkityksen kertomista kääntäjälle. Siinä on aina ensin ominaisuusmääreet (specifiers) ja sitten tunnistemääreet (tunniste mahdollisine osoitin-, taulukko- tai funktiotarkenteineen). Ominaisuusmääreitä on 3 (C99:ssä 4) lajia: * muistivaraustyyppi (storage class), esim. static; näiden pitää olla ensin, muiden järjestys on vapaa * tyyppitarkennin (type qualifier), esim. const * tyyppimääre (type specifier), esim. int * C99: funktiomääre (function specifier): inline

52 Muistivaraustyypit (storage class) Muuttujilla on C:ssä kolme yleistä ominaisuutta: * säilyvyys (storage duration): miten kauan muuttuja säilyttää arvonsa * näkyvyys (scope): missä tunnisteeseen voidaan viitata * linkitettävyys (linkage): voidaanko muuttujaa tai funktiota käyttää toisesta ohjelman osasta (eri tiedostosta)

53 Esimerkki: // globaali muuttuja: int i; // staattinen (pysyvä) säilyvyys // tiedostonäkyvyys // linkitettävissä // lokaali muuttuja void f(void) { int j; // automaattinen (tilapäinen) säilyvyys // lohkonäkyvyys // ei linkitettävissä }

54 Näitä ominaisuuksia voidaan muuttaa muistinvaraustyyppi-määreillä, joita on neljä: auto, static, extern ja register. auto: Sallittu vain lohkon sisällä. Muuttujan säilyvyys on automaattinen (loppuu lohkon lopussa), näkyvyys lohko, ei linkitettävissä. Oletus lohkon sisäisissä määrityksissä, ei juuri koskaan tarvitse käyttää eksplisiittisesti. auto

55 static: Sallittu kaikkialla mutta vaikutus eri paikoissa erilainen: lohkon sisällä muuttaa säilyvyyden pysyväksi, ulkopuolella (globaalille muuttujalle) estää linkitettävyyden. Säilyvyys aina pysyvä, alustetaan automaattisesti nollaksi. int j; // säilyvä, tiedostonäkyvyys, linkitettävissä static int i; // säilyvä, tiedostonäkyvyys, ei linkitettävä void f(void) { int k; // tilapäinen, lohkonäkyvyys, ei linkitettävä static int l; // pysyvä, lohkonäkyvyys, ei linkitettävä } static

56 extern kertoo, että muuttujan muistivaraus tehdään jossain muualla, se vain esitellään tässä. Jos kuitenkin extern-muuttuja alustetaan, se tulkitaan määrittelyksi: extern int i=1; on sama kuin int i=1; extern

57 register -määre on vain vihje kääntäjälle, että ao. muuttuja kannattaisi sijoittaa rekisteriin tai yleensä mahdollisimman nopeaan muistiin - kääntäjän ei tarvitse välittää siitä. register-muuttuja toimii kuten auto, mutta siihen ei voi osoittaa pointterilla (&-operaattori ei ole sallittu). register

58 funktioiden muistivarausmääreet Funktioille voi käyttää static ja extern -määreitä: extern ei vaikuta mitään; voi käyttää dokumentoimaan ulkoista linkitettävyyttä. static estää linkitettävyyden (kuten globaaleilla muuttujillakin); voi (ja kannattaa) käyttää nimikonfliktien välttämiseksi (useassa tiedostossa voi käyttää erilaisia samannimisiä static-funktioita).

59 Tyyppitarkenteet Tyyppitarkenteita on kaksi (C99:ssä kolme): const: kertoo että muuttuja on “read-only”: kääntäjä saattaa tarkistaa sen tai jopa sijoittaa koko muuttujan ROM-muistiin; hyvä myös dokumentointimielessä. volatile: kertoo muuttujan voivan muuttua itsekseen (i/o-väylä, kello,...) restrict (C99, vain osoittimille): kertoo, että ao. osoittimella on yksinoikeus osoittamaansa muistipaikkaan (optimointivihje)

60 Tunnistemääreet (declarators) Tunnistemääre (declarator) muodostuu tunnisteesta ja sitä mahdollisesti edeltävästä osoitinta tarkoittavasta *:stä ja seuraavista taulukkoa tarkoittavasta []:sta ja funktiota tarkoittavasta ():sta, joita voi yhdistellä hyvinkin monimutkaisin tavoin. Funktiomäärittelyssä sulkujen sisällä on parametrien määritykset, jotka noudattavat (rekursiivisesti) samoja sääntöjä.

61 Tunnistemääreiden tulkinta * Lue määreitä sisältä ulos: aloita tunnisteesta jota ollaan määrittelemässä ja jatka siitä ulospäin. * Lue “oikealta”, erityisesti [] ja () ennen kuin * double *d[10]; d d on [10] 10:n alkion taulukko * osoittimia double double-tyyppiin

62 int *f(float); f f on (float) funktio argumenttinaan float * joka palauttaa osoittimen int int-tyyppiin esimerkkejä

63 int (*fp)(float); fp on * osoitin (float) funktioon jonka argumentti on float int ja joka palauttaa int-arvon

64 float (*menu(void))(double) menu on (void) funktio jolla ei ole argumentteja * joka palauttaa osoittimen (double) funktioon jonka argumentti on double float ja joka palauttaa float-arvon

65 int *(*x[10])(void); x x on [10] 10 alkion taulukko * osoittimia (void) funktioon jolla ei ole argumentteja * joka palauttaa osoittimen int int-tyyppiin

66 Monimutkaisia tyyppimääreitä voi usein selventää typedefillä: int *(*x[10])(void); voidaan kirjoittaa näin: typedef int *Fcn(void); typedef Fcn *Fcn_ptr; typedef Fcn_ptr Fcn_ptr_taulu[10]; Fcn_ptr_taulu x;

67 Muuttujien alustuksesta Muistivaraustyyppi vaikuttaa alustukseen: * Pysyvän (globaali tai lokaali static) muuttujan alustuksessa saa käyttää vain vakiolausekkeita (käännösaikana laskettavissa olevia - const-muuttuja ei kelpaa). * Taulukon, structin ja unionin alustuksessa saa käyttää vain vakiolausekkeita vaikka ne olisivat automaattisiakin (C99:ssä tätä rajoitusta ei ole). * Pysyvät muuttujat alustetaan automaattisesti nolliksi. (Tähän luottaminen ei kuitenkaan ole hyvä idea jo luettavuuden takia.)

68 inline C99:ssä on funktiomääre inline: se vihjaa kääntäjälle, että funktio kannattaisi “purkaa” ts. kopioida sen koodi kaikkialle missä sitä kutsutaan. Kääntäjän ei tarvitse välittää tästä, se on vain optimointivihje. inline-funktioilla on joukko rajoituksia, mm. static- muuttujat niiden sisällä eivät toimi normaalisti, joissakin tilanteissa ne eivät voi viitata globaaleihin muuttujiin jne.


Lataa ppt "Struct struct on tietotyyppi, joka koostuu kokoelmasta eri tyyppisiä, nimellä viitattavia elementtejä, jäseniä (members): struct { int tuotenumero; char."

Samankaltaiset esitykset


Iklan oleh Google