Kirjoittaja: Metabolix
Kirjoitettu: 06.06.2006 – 06.06.2006
Tagit: koodi näytille, vinkki
Ohjelmointi on ihmeitä täynnä, ja tämä esimerkki onnistuu käsittelemään jo useampaa kappaletta. Vinkin tarkoitus on näyttää hieman, kuinka voi käyttää argumenttilistaa eli kuinka tehdä funktio, joka printf:n tapaan voi ottaa argumentteja juuri sen verran, kuin niitä annetaan. Lisäksi samalla tulee esiteltyä dynaamista muistinkäsittelyä, moniulotteisia taulukoita ja rekursiivisia funktioita.
Esimerkkinä toimii funktiopari, jolla saa luotua ja tuhottua moniulotteisia taulukoita. Luontifunktio ottaa taulukon yhden alkion koon, ulottuvuuksien määrän ja ulottuvuudet. Tuhoajafunktio ottaa taulukon, ulottuvuuksien määrän ja ulottuvuudet viimeistä lukuun ottamatta.
Virheentarkistusta koodissa ei taaskaan ole, mutta sen sijaan siitä löytyy esimerkillinen goto-viritelmä, jonka ansiosta ohjelman sammumisen estämiseen ei tarvita purukumia.
Funktiot
/* Otsikot */ #include <stdarg.h> #include <stdlib.h> /* Funktio, joka varaa rekursiivisesti tietyn taulukon. ** "Viimeinen argumentti" on argumenttilista. */ void * v_tee_taulu(int alkio, int ulottuvuuksia, va_list argp) { void * taulu; int pituus, i; /* Kyllä niitä suuntia saisi edes jokunen olla */ if (ulottuvuuksia < 1) return NULL; /* Jos on yksi ulottuvuus, luodaan sellainen */ if (ulottuvuuksia == 1) return calloc(va_arg(argp, int), alkio); /* On vielä useampi ulottuvuus. ** Otetaan päällimmäinen ulottuvuus, varataan tilaa uusille osoittimille ** ja luodaan niihin uudet taulukot vähemmillä ulottuvuuksilla */ /* va_arg ottaa listan ja tyypin */ pituus = va_arg(argp, int); taulu = malloc(pituus * sizeof(void *)); for (i = 0; i < pituus; ++i) { ((void **)taulu)[i] = v_tee_taulu(alkio, ulottuvuuksia - 1, argp); } return taulu; } /* Funktio, joka tuhoaa rekursiivisesti tietyn taulukon */ void v_tuhoa_taulu(void * t, int ulottuvuuksia, va_list argp) { int pituus, i; /* Jos ei ole ulottuvuuksia, mennään pois vain */ if (ulottuvuuksia < 1) return; /* Jos on yksi ulottuvuus, tuhotaan se */ if (ulottuvuuksia == 1) return free(t); /* On vielä useampi ulottuvuus. ** Otetaan päällimmäinen niistä, tuhotaan taulukot ja itsemme */ pituus = va_arg(argp, int); for (i = 0; i < pituus; ++i) { v_tuhoa_taulu(((void **)t)[i], ulottuvuuksia - 1, argp); } free(t); } /* Kutsuttavat funktiot. ** Näissä vain avataan argumenttilista ja kutsutaan listallista funktiota. ** Argumenttina annetaan alkion koko, ulottuvuuksien määrä ja itse ulottuvuudet. */ void * tee_taulu(int alkion_koko, int ulottuvuuksia, ...) { void * t; va_list argp; /* Lista alustetaan viimeisen oikean parametrin avulla. */ va_start(argp, ulottuvuuksia); t = v_tee_taulu(alkion_koko, ulottuvuuksia, argp); /* Lopuksi se pitää sulkea. */ va_end(argp); return t; } /* Tuhoajafunktiolle annetaan taulukko, ulottuvuuksien määrä ja ulottuvuudet. ** Viimeistä ulottuvuutta ei kuitenkaan tarvitse antaa. */ void tuhoa_taulu(void * t, int ulottuvuuksia, ...) { va_list argp; va_start(argp, ulottuvuuksia); v_tuhoa_taulu(t, ulottuvuuksia, argp); va_end(argp); }
Esimerkki
#include <stdio.h> int main(void) { int maara, vastaus; char ** t; Alku: /* Varataan taulukko, jossa on viisi sadan merkin char-taulua */ t = (char **) tee_taulu(1, 2, 5, 100); /* Käytetään niitä vähän */ printf("Anna viisi sanaa.\n>> "); scanf("%99s %99s %99s %99s %99s", t[0], t[1], t[2], t[3], t[4]); printf("'%s', '%s', '%s', '%s' ja '%s'\n", t[4], t[3], t[2], t[1], t[0]); /* Tuhotaan taulu. Viimeistä ulottuvuutta ei tarvitse ilmoittaa, ** kuten ei myöskään alkion kokoa */ tuhoa_taulu(t, 2, 5); Lopetetaanko: printf("Joko lopetetaan? Vastaa 1 tai 0.\nVastaus: "); maara = scanf("%i", &vastaus); if (maara != 1 || (vastaus != 1 && vastaus != 0)) goto Lopetetaanko; if (vastaus == 0) goto Alku; return 0; }
Hyi hyi, ei mitään gotoja, nehän olisi jo pitänyt kuopata qbasic aikana.
Vaan vinkin pääasia on muualla, ja esimerkki on hyvä. Aika harvoin kyllä tarvitsee tuollaisia funktioita.
GOTO on ihan toimiva jos sitä osaa käyttää oikeissa paikoissa.
Omenasalaatti vyöryi banaanimäkeä ylävasempaan. Missä viisi.
Kiitos tästä vinkistä. Opin paljon uutta! :-)