C-taal voor beginners - hoofdstuk 4

functies, prototypes en geheugenklassen


[4.1 functies] [4.2 pointers] [4.3 call by reference] [4.4 geheugenklassen] [4.5 enkele begrippen i.v.m. het geheugen] [4.6 optimalisatie]


4.1 functies

Een C-programma bestaat uit één of meerdere functies. Met functies kunnen we grote programma's opdelen in kleinere eenheden, wat het programmeren vergemakkelijkt. Verder kunnen functies die in het ene programma zijn ontwikkeld, in andere programma's worden gebruikt. Een functie beschrijft het rekenproces dat op de data van de functie moet worden uitgevoerd. De functie moet daarom zowel de data-objecten (declaraties) als de werking (statement) beschrijven.

Een programma kan uit meerdere functies bestaan, maar één van die functies moet de naam main hebben. Een functie heeft steeds één ingang en één uitgang. De statements worden van begin tot einde uitgevoerd. Als een functie een tweede functie aanroept, is het effect dat de uitvoering van de eerste functie tijdelijk wordt opgeschort op het punt dat de tweede functie wordt aangeroepen. Deze tweede functie wordt dan binnengegaan (bij de ingang), uitgevoerd en verlaten. Daarna gaat de aanroepende functie verder bij het statement, dat onmiddelijk volgt op het punt van de aanroep.

In het volgende voorbeeldprogramma moet vier keer de tijd in uren, minuten en seconden ingelezen worden en telkens de tijd in seconden berekend en afgedrukt worden. We kunnen dat oplossen door een functie bereken() viermaal aan te roepen:

#include<stdio.h>

void bereken(void); /* declaratie */
int main(void)
{

    bereken();    /* aanroep */
    bereken();    /* aanroep */
    bereken();    /* aanroep */
    bereken();    /* aanroep */
    return 0;
}

void bereken(void) /* definitie */
{
int uren, minuten, seconden, tijd;

    printf("\nGeef uren, minuten en seconden: ");
    scanf("%d%d%d", &uren, &minuten, &seconden);

    tijd=(60 * uren + minuten) * 60 + seconden;

    printf("\nDe tijd %d:%d:%d is omgerekend %d seconden\n", 
						uren, minuten, seconden, tijd);

    return;
}

Bovenstaand programma bevat 2 functies: main() en bereken(). Via de functie-aanroep bereken(); wordt de functie bereken() aangeroepen. De statements van de functie worden dan uitgevoerd. Als laatste instructie vinden we return; Deze instructie keert terug naar de aanroepende functie. De volgorde bij het gebruik van een functie is altijd: declareren, aanroepen en definiëren, zoals in het programma aangetoond wordt.

4.1.1 de waarde van een functie

In ons voorbeeld werd een ondergeschikte functie bereken() gebruikt, die verantwoordelijk was voor het berekenen van één tijd. Tussen de functies main() en bereken() werden geen waarden uitgewisseld.

In de C-taal bestaat een mechanisme om het resultaat van een door een aangeroepen functie uitgevoerde berekening terug te zenden naar de aanroepende functie. Dit gebeurt met een return statement. Het statement geeft aan dat er vanuit de aangeroepen functie wordt teruggekeerd en dat de waarde aan de aanroepende functie moet worden doorgegeven. Deze waarde kan door de aanroepende functie met behulp van een passend statement worden vastgehouden. Voorbeeld:

#include<stdio.h>

int bereken(void);
int main(void)
{
int sec;

    sec = bereken(); /* vasthouden van de waarde */

    printf("Omgerekend zijn dit %d seconden.", sec);
    return 0;
}

int bereken(void)
{
int uren, minuten, seconden, tijd;

    printf("\nGeef uren, minuten en seconden: ");
    scanf("%d%d%d", &uren, &minuten, &seconden);

    tijd=(60 * uren + minuten) * 60 + seconden;

    return tijd;
}

In de functie bereken() wordt het aantal seconden niet meer afgedrukt, maar wel doorgegeven aan het hoofdprogramma met behulp van het return statement. Bij de declaratie vertellen we wat voor soort waarde wordt teruggestuurd; hier een integer. Als een functie een waarde aflevert, moet het type van de af te leveren waarde in de functienaam vóór de naam van de functie worden geplaatst. Deze typespecificator is één van de vier elementaire types die C kent: int, char, float of double. Uiteraard moet dit type overeenkomen met (of kunnen geconverteerd worden naar) het type van de expressie die via de return wordt teruggegeven. Een return kan ook een expressie terugleveren zoals x + y - z. Dit wordt dan geëvalueerd en het resultaat wordt teruggelevert, wat men "call by value" noemt.

Een void functie is een functie die geen waarde aflevert. Dus als u met een return een waarde teruggeeft, mag de afleverende functie nooit van het type void zijn. Een functie die zonder typespecificator wordt gedefinieerd heeft impliciet het type int:

bereken(void)
{
    ....
}

De computer verwacht in dit geval dat een waarde van het type int zal worden teruggestuurd. Als u een programma schrijft met een functie die niet als het type void gedeclareerd is, maar die ook geen waarde terugleverd, kan u best als laatste lijn return 0; plaatsen, dit om waarschuwingen van de compiler te vermijden:

#include<stdio.h>
int main(void)
{
    ...
    return 0;
}

Zoals ik reeds eerder zei moeten we bij het gebruik van functies altijd drie zaken respecteren, in de juiste volgorde: declaratie, aanroep en definitie. De declaratie is noodzakelijk opdat de C-compiler gegevens over de attributen van het object kan verzamelen en deze informatie kan gebruiken als er naar het object verwezen wordt. Naar een functie mag echter wel verwezen (aangeroepen) worden, voordat deze is gedefinieerd. Als een functie eerst wordt aangeroepen en dan pas gedeclareerd, moet in de aanroepende functie een functieprototype staan zodat het type van de af te leveren waarde duidelijk is. Als u bijvoorbeeld in een programma twee integer functies heeft: functie1 en functie2, dan declareren we deze als volgt:

int functie1();
int functie2();

Ook mogelijk, maar moeilijker te onderhouden is het volgende:

int functie1(), functie2();

4.1.1.1 het return type van main()

In de originele definitie van C, gaven alle functies standaard een integer type variabele terug, behalve als de programmeur dit anders definieerde. Omdat het expliciet returnen van een waarde bij het verlaten van een functie optioneel was, werd het grootste deel van C als volgt geschreven:

main()
{
    ....
}

Omdat main() zonder argumenten (zie volgende paragraaf) volgens velen niets terrugleverde, plaatste men veelal het void type, waardoor het volgende toegepast werd:

void main()
{
    ....
}

Toen de ANSI-C standaard werd vervolledigd, was het enige legale teruglevertype het type int, op deze manier:

int main(void)
{
    ....
    return 0;
}

De meeste compilers zullen de void methode ondersteunen, maar enkel de int return methode word toegelaten door de ANSI-C standaard. In deze cursus zal overal de laatste (juiste ANSI-C) methode gebruikt worden.

4.1.2 argumenten van functies

In voorgaande programma's werd tussen de afzonderlijke functies geen data uitgewisseld, of werd slechts één waarde afgeleverd via het return statement. Er bestaan echter veel programmeerproblemen waarvoor functies nodig zijn die meer dan één object aan de aanroepende functie afleveren. Bovendien is het ook mogelijk dat de aanroepende functie waarden aan de aangeroepen functie wil doorgeven. In deze paragraaf bespreken we hoe de aanroepende functie argumenten (parameters) kan doorgeven.

We hebben reeds gebruik gemaakt van het doorgeven van argumenten van de aanroepende naar de aangeroepen functies. In de meeste programma's die we reeds ontwikkeld hebben, werd de functie printf() opgeroepen. Bij de aanroep van deze functie worden argumenten opgegeven, die als een lijst tussen haakjes en gescheiden komma's van de functie staan. In de aanroep:

printf("De som van %d en %d is %d", getal1, getal2, som);

worden vier argumenten doorgegeven: het stringargument en de drie expressies die de af te drukken waarden weergeven. We noemen deze argumenten de actuele argumenten. De manier waarop een functie wordt aangeroepen wordt de "calling sequence" genoemd. De functiedefinitie met argumenten heeft de vorm:

typespecificator functie(argumentenlijst);

De typespecificator is natuurlijk het type int, char, float of double. Nieuw is de argumentenlijst tussen de ronde haken. Deze noemen we de formele argumenten. De actuele en formele argumenten moeten in aantal en type overeenkomen. Voor elk formeel argument komt precies één corresponderend acteel argument voor bij de functieaanroep. Voorbeeld:

#include<stdio.h>

int main(void)
{
float som(float, float);
float x, y, resultaat;

    printf("Geef twee getallen: ");
    scanf("%f%f", &x, &y);

    resultaat = som(x, y);

    printf("De som van %f en %f = %f", x, y, resultaat);
    return 0;
}

float som(float a, float b)
{
float hulp;

    hulp = a + b;

    return hulp;
}

Een functie som() heeft twee floating point waarden als argumenten en geeft de som van deze twee via het return statement terug aan de oproepende functie.

Merk op: de namen van de actuele en formele argumenten mogen verschillend zijn. Bij de aanroep wordt immers de waarde van het actuele argument doorgegeven naar het formele argument. De variabelen resultaat en hulp zijn eigenlijk overbodig in het vorige programma. Als volgt kan het immers ook:

#include<stdio.h>

int main(void)
{
float som(float, float);
float x, y;

    printf("Geef twee getallen: ");
    scanf("%f%f", &x, &y);

    printf("De som van %f en %f = %f", x, y, som(x, y));
    return 0;
}

float som(float a, float b)
{
    return a + b;
}

U merkt dat we in een printf() statement evengoed een functie kunnen oproepen.

Indien een functie geen parameters aanneemt, kan u als u wil het void type in de hoofding gebruiken om dit aan te duiden:

int mijn_functie(void)
{
    ....
}

In deze cursus worden functies zonder argumenten trouwens op deze manier gebruikt.

4.1.2.1 de argumenten van main()

Een programma begint door het oproepen van de functie main(). Deze vereist geen prototype en kan dus zonder parameters gedefinieerd worden:

int main(void)
{
    ....
    return 0;
}

Er bestaat echter ook een mogelijkheid om parameters te gebruiken:

int main( int argc, char *argv[ ] )
{
    ....
    return 0;
}

De namen argc en argv zijn niet vereist, maar gewoon een standaardmanier om de argumenten te benoemen. U kan eender welke benaming gebruiken als die geldig is voor functieargumenten. Wanneer main() aangeroepen wordt (dit is onmiddelijk bij uitvoering van het programma) zal argc een teller zijn voor het aantal argumenten en argv zal een array zijn van die argumenten. Aangezien elk woord een string is die voorgesteld wordt als een pointer-naar-char, is argv een array-van-pointers-naar-char.

U vraagt zich waarschijnlijk af hoe we waarden aan de main() kunnen doorgeven. In feite gaat het hier om de command line, zoals we die kennen in Dos of Unix. Indien u bijvoorbeeld een programma 'mijn_prog.exe' heeft dat een bestandsnaam (argument of parameter) aanneemt en daar dan iets mee doet, zou u dat in Dos als volgt kunnen oproepen:

mijn_prog c:\map\ergens\mijn_bestand.txt

Sommige besturingssystemen laten zelfs toe dat u het bestand er op 'laat vallen'. U moet weten dat argv[0] de bestandsnaam van het programma zelf voorstelt en dus voor niets anders gebruikt kan worden. Bekijk het volgende voorbeeld dat simpelweg de inhoud van een opgegeven bestand toont.

#include <stdio.h>

int main(int argc, char *argv[ ])
{
int i;
FILE *fp;
int c;

    printf("De naam van dit programma is %s.\n", argv[0]);
    getchar(); /* wachten op een druk op <enter> alvorens verder te gaan */
    for(i = 1; i < argc; i++)
    {
        fp = fopen(argv[i], "r");
        if(fp == NULL)
            fprintf("kan %s niet openen\n", argv[i]);

        while((c = getc(fp)) != EOF)
            putchar(c);

        fclose(fp);
    }

    return 0;
}

4.2 pointers

De hierboven beschreven manier kan gebruikt worden om parameters door te geven van de aanroepende functie naar de aangeroepen functie. Er bestaat echter geen gelijkaardig mechanisme voor de tegengestelde richting. Veranderingen in de waarde van een formeel mechanisme binnen een functie brengt geen verandering in de waarde van het oorspronkelijke actuele argument. Dit is het gevolg van het feit dat het doorgeven van het argument via "call by value" is, zoals eerder besproken. Om een aangeroepen functie de toegang te verlenen tot een waarde in de aanroepende functie, moet de aanroepende functie het adres van haar lokale variabelen doorgeven. Als de aangeroepen functie dan het adres van een variabele in de aanroepende functie heeft, kan op dat adres een nieuwe waarde worden toegekend. We hebben dit reeds toegepast bij de scanf() functie, waarbij we het adres doorgeven van de variabele waarop de in te lezen waarde moet worden geplaatst (met het & teken). Om functies te kunnen schrijven die met adressen werken hebben we het begrip pointer nodig. (Zie hoofdstuk 5)

Een pointer is een variabele die het adres van een ander object bevat. Als een pointer een variabele is, moet deze net als alle andere variabelen een gebied in het geheugen beslaan, dat zelf een adres heeft. De inhoud van dat gebied in het geheugen is het adres van een andere variabele. Als, bijvoorbeeld, ptrx een variabele is die kan gebruikt worden om de integer variabele x te adresseren, kunnen we dit adres als volgt aan de pointer toekennen:

ptrx = &x;

ptrx verwijst nu naar de variabele x en bevat het adres waarop variabele x in het geheugen te vinden is. De indirectieoperator * neemt nu de inhoud van de geheugenplaats waarnaar de pointer verwijst. Dus

*ptrx

geeft de waarde van de variabele x. Bekijk & als "adres van" en * als "inhoud van". We kunnen een pointer op dezelfde manier declareren als variabelen, bijvoorbeeld:

int *ptrx;

Hiermee wordt een pointer gedeclareerd die verwijst naar een variabele van het type integer. Een ander voorbeeld:

int a = 14, b;
int *q;
q = &a;	/* q verwijst naar het adres van variabele a */
b = *q;	/* b neemt de inhoud van de variabele waarnaar pointer q verwijst */

Hieruit kunnen we dan afleiden dat b = 14.

4.3 call by reference

Voorbeeld:

#include<stdio.h>

int main(void)
{
int uren, minuten, seconden, tijd;
void bereken(int, int, int, int*); /* declaratie */

    printf("\nGeef uren, minuten en seconden: ");
    scanf("%d%d%d", &uren, &minuten, &seconden);

    bereken(uren, minuten, seconden, &tijd); /* aanroep */

    printf("Berekende tijd: %d", tijd);
    return 0;
}

void bereken(int u, int m, int s, int *t) /* definitie */
{
    *t = (60 * u + m) * 60 + s;
}

In een functie main() wordt een tijd ingelezen in uren, minuten en seconden. De bedoeling is dit om te rekenen naar het totaal aantal seconden door gebruik te maken van een ondergeschikte functie bereken(). Het resultaat van de berekening moet teruggestuurd worden naar main() vermits dit daar wordt afgedrukt. De functie bereken() heeft dus vier argumenten: de eerste drie stellen de oorspronkelijke tijd voor, terwijl de laatste de door de functie berekende tijd voorstelt. Dit laatste argument moet een adres (of pointer) zijn, zodat de functie bereken() de berekende waarde in de desbetreffende geheugenplaats kan plaatsen.

4.4 geheugenklassen

Tot nu toe hebben we altijd met hetzelfde soort variabelen gewerkt. In de C-taal kan men echter meerdere types gebruiken. Er zijn 4 geheugenklassen voor variabelen in C:

4.4.1 automatisch

Het bereik van een automatische variabele is beperkt tot de functie waarin hij gedeclareerd is. Automatische variabelen hebben waarden die lokaal zijn ten opzichte van de functies waarin ze gedeclareerd zijn. Dat wil zeggen dat een variabele x die gedeclareerd is in een functie kan veranderd worden, zonder dat dit een invloed heeft op enige x elders in het programma.

Automatische variabelen bestaan slechts totdat de functie afgelopen is. De geheugenruimte die door de compiler gereserveerd werd is dan niet langer voorzien en de waarden van deze variabelen is dan ook verloren. Als de functie nadien opnieuw wordt opgeroepen zijn de waarden van de vorige keer niet meer beschikbaar.

Om aan te duiden dat we een automatische variabele willen plaatsen we het woordje auto voor de declaratie:

auto char letter;
auto int i, j, k;
auto float btw = 20.5;

De automatische geheugenklasse is de default geheugenklasse voor variabelen in C in een functie. Daarom kunnen we auto ook weglaten, wat we normaal ook doen.

auto char letter;
auto int i, j, k;
auto float btw = 20.5;

is equivalent met

char letter;
int i, j, k;
float btw = 20.5;

Dus waar het op neerkomt is dat u het woordje auto helemaal niet moet kennen of bestuderen, en zeker niet moet toepassen. De geheugenklasse op zich is echter wel belangrijk.

4.4.2 extern

Elke variabele die buiten functies gedeclareerd wordt is extern. Deze variabele kan dan gebruikt worden doorheen het ganse programma. Wanneer hun namen niet gebruikt worden in een functie, dan worden zij "verborgen" maar hun waarde kan niet vernietigd worden:

#include<stdio.h>

int x;

int main(void)
{
void functie1(void);
void functie2(void);

    x = 1;
    functie1();
    printf("x = %d\n", x);
    functie2();
    printf("x = %d\n", x);
    return 0;
}

void functie1(void) { x *= 10; }

void functie2(void) { x += 2; }

Met als uitvoer:

x = 10
x = 12

Hier is de variabele x dus extern. In de drie functies is deze beschikbaar en kan hij niet anders gedeclareerd worden. Variabele x is "globaal" beschikbaar. Het bereik van x gaat van het begin van het programma tot het einde en moet daarom dus niet als parameter doorgegeven worden. De verleiding is groot om zoveel mogelijk variabelen als extern te declareren. Dit brengt echter een heleboel problemen met zich mee bij grotere programma's. Gebruik dus niet te pas en te onpas externe variabelen.

De default geheugenklasse voor functies in C is de geheugenklasse extern.

Met dit in gedachte kan je een variabele of een functie op verschillende manieren definieren:

1. Lokaal in een functie: komt (meestal) op de stack (zie 4.5).
2. Lokaal static in een functie. Wordt 1 keer ongesteld op de geven waarde en veranderd dan niet tussen calls naar die routine. Deze waarde is dus alleen binnen de betreffende functie beschikbaar.
3. Globaal in een source file. Dit kan door alle functies in het ganse programma gebruikt worden.
4. Globaal static in een source file. Dit kan door alle functies in de betreffende source file gebruikt worden. Andere source files kunnen hem niet gebruiken.
5. Extern. Het object is gedefinieerd in een andere source file en is van type 3.

4.4.3 statisch

We weten nu dat we variabelen binnen (lokaal) of buiten (globaal) een functie kunnen declareren. Statische variabelen vormen een nieuwe geheugenklasse: zij kunnen zowel lokaal als globaal zijn. We duiden een statische variabele aan met het woordje static.

Lokale statische variabelen zijn intern ten opzichte van de functie waarin ze worden gedeclareerd, maar in tegensteling tot automatische variabelen blijven statische variabelen bestaan. Dit wil zeggen: zij behouden hun waarde ook nadat de functie is afgelopen. Daardoor is de waarde die de variabele had toen de functie de vorige keer verlaten werd nog dezelfde wanneer die functie opnieuw aangeroepen wordt.

Een lokale statische variabele kan met een constante expressie worden geïnitialiseerd, éénmaal aan het begin van het programma. Daarna is de waarde van een statische variabele bij het binnengaan van een functie gelijk aan de waarde die de variabele had toen de functie de vorige keer werd verlaten:

#include<stdio.h>
int main(void)
{
int i;
void functie(void);
    for(i=0;i<5;i++)
        functie();
    return 0;
}
void functie(void)
{
static int st_var = 0;
int au_var = 0;
    printf("auto=%d, static=%d\n", au_var, st_var);
    au_var++;
    st_var++;
}

De functie functie() bevat declaraties voor twee lokale variabelen. au_var is een automatische variabele van het type integer en st_var is een statische variabele van het type integer. De automatische variabele wordt bij elke aanroep op nul gezet, maar de initialisatie van de statische variabele wordt slechts één keer uitgevoerd bij het aanroepen van de functie. De uitvoer van het programma zal dan ook zijn:

auto=0, static=0
auto=0, static=1
auto=0, static=2
auto=0, static=3
auto=0, static=4

Als u het voorbeeld compileert kan het zijn dat u een waarschuwing krijgt in de vorm van "au_var is assigned a value that is never used". Als u een beetje nadenkt begrijpt u waarom. Het programma zou toch het gewenste resultaat moeten geven. De term static betekent niet alleen dat een variabele permanent is, maar ook dat deze in zekere mate privé-eigendom is. Interne statische variabelen zijn alleen bekend binnen de functie waarin ze gedeclareerd zijn.

4.4.4 register

Register variabelen worden in C gebruikt als de verwerkingssnelheid van belang is. De idee achter de register geheugenklasse is om de compiler één van de processor-registers te laten reserveren. Uiteraard is de register geheugenklasse bedoeld voor variabelen die intensief gebruikt worden, zoals loop-tellers. De opslagklasse register is alleen toepasbaar op automatische variabelen en functie-argumenten. Ze wordt aangegeven door het gereserveerde woord register voor een normale declaratie. Voor registervariabelen gelden echter enkele beperkingen i.v.m. het aantal beschikbare registers en de variabeltypes.

De compiler is op geen enkele manier verplicht om uw suggestie te volgen. Als  deze ervoor kiest om uw raad links te laten liggen, heeft de variabele dezelfde opslagklasse als wanneer hij gewoon gedeclareerd zou zijn. Van een variabele een register variabele proberen te maken verhindert u ook om het adres ervan te gebruiken en er een pointer naar te richten, aangezien er geen mogelijkheid is om een geheugenpointer naar een CPU-register te richten.

4.5 enkele begrippen i.v.m. het geheugen

Er zijn drie gebieden in het geheugen die speciale mogelijkheden hebben. Deze worden aangewezen door de compiler en de linker: (Deze begrippen en het gebruik ervan is wel nogal systeemspecifiek)

4.5.1 stack

De stack wordt door het systeem toegekend met een vaste grootte en wordt van boven naar onder gevuld met één element per keer. Elementen worden van ook boven naar onder verwijderd, één element per keer. Dus, het laatste element dat toegevoegd werd aan de stack is het eerste element dat verwijdert wordt wanneer het niet langer nodig is. Elk element op de stack is potentieel beschikbaar voor verwijzing of aanpassing door de uitvoerend code, maar de elementen worden enkel vanaf de top toegevoegd.

4.5.2 heap

Dit is het gebied dat naast de stack ligt. De heap wordt door het systeem voorbehouden met een vaste grootte en gebruikt in willekeurige volgorde. Dit wil niet zeggen dat er geen volgorde inzit, het betekent dat het geheugen niet op een vooraf vastgelegde manier wordt toegekend. In feite kan het gebruikt worden in blokken als het nodig is vanuit de heap. Geheugen in de heap dat niet gebruikt wordt staat in de free list, die aangesproken kan worden, indien nodig.

4.5.3 globaal geheugen

Dit is een verzameling van al het geheugen van de machine, dat niet aan de stack of heap toegewezen wordt.

4.6 optimalisatie

Het declareren van een functie buiten de scope van de main() is netter en eenvoudiger te onderhouden. Merk ook op dat de main() een integer returned. Voorbeelden in deze cursus zullen dit voorbeeld misschien niet altijd volgen, omdat het ook niet altijd verplicht is. Het zou een goede oefening zijn om de voorbeelden proberen te optimaliseren. Om de uitvoeringssnelheid van een programma te verbeteren kan u altijd het volgende proberen. Pas wel op dat dit de leesbaarheid van de broncode niet al te veel ten nadele komt.

1. Gebruik arrays in plaats van switch of if/else statements.
2. Reduceer. Verwerk niets als het ook niet nodig is.
3. Gebruik bibliotheekfuncties in plaats van een zelf ontworpen for loop, indien mogelijk.
4. Verander indien nodig de manier waarop een programma is georganiseerd.
5. Kijk hoe de compiler bepaalde zaken vertaalt. Herschrijf uw eigen functies om dit te optimaliseren.


opdrachten

In dit hoofdstuk werden een boel programma's getoond. Compileer en run ze en schrijf dan soortgelijke programma's, waaraan u telkens een paar dingen verandert en het resultaat daarvan bestudeert.

1. Schrijf een programma dat uw naam tien maal op het scherm drukt, door een functie op te roepen om het schrijven te doen. Verplaats de oproepfunctie ook eens voor de main om te kijken of uw compiler het toelaat.

2. Schrijf een programma voor de berekening van oppervlakten van vierkanten, rechthoeken en trapezia.

Gebruik zoveel verschillende functies als u nodig acht.

3. Schrijf een functie die een datum uitschrijft op grond van drie getallen: één voor de dag, één voor de maand en één voor hetjaar. Als de eeuwaanduiding ontbreekt, dan moet die er bij gezet worden. Je mag ervan uitgaan dat alle data tussen 1900 en 2000 liggen. Bijvoorbeeld:

Functie aanroepen met Uitvoer van de functie

31, 1 en 50                          31 januari 1950

16, 10 en 1960                     16 oktober 1960

4. Schrijf een programma waarin je de functie ggd() opneemt die op een recursieve manier de grootste gemene deler van twee niet-negatieve integers bepaalt. Het inlezen van de twee getallen en het afdrukken van hun grootste gemene deler gebeurt in het hoofdprogramma. Het berekenen gebeurt in de functie m.b.v. het volgend algoritme:

ggd(a,b)=a als a=b

ggd(a,b)=ggd(b,a%b) als a>b en a%b is niet 0


voorbeelden

4-1.c: Een afstand in inch vragen en in cm afdrukken in het hoofdprogramma.

4-2.c: De faculteit van een getal berekenen.

4-3.c: Een functie die a tot de macht b berekent, waarbij a en b twee positieve integer waarden zijn, met gebruik van herhaalde vermenigvulding.

4-4.c: Een functie die de waarden van haar argumenten verwisseld. De header van de functie is void wissel(int *x, int *y).


referenties

[The C Library Reference Guide]

Eric Huss

[C Language Tutorial]

Gordon Dodrill

[C FAQ]

Steve Summit

 

Verder naar hoofdstuk 5

Terug naar inleiding