Weblessen.nl - Voor iedereen die wat wil leren..


C

Index
C Index
Voorwoord
De eerste stap
Een inleiding tot C
Programma besturing
Toekennen en Logisch vergelijken
Funkties en Variabelen
Defines en Macros
Strings en Tabellen
Pointers
Standaard Invoer / Uitvoer
Bestands Invoer / Uitvoer
Structuren en Unions
Dynamisch ngeheugen aanvragen
Karakter- en bitmanipulatie

Appendix
Hungarian Notation
Voorbeeldprogramma's
Totaal programma
Scherm- en bestands beschrijvingen
Aanpassingen voor VM/CMS

Funkties en Variabelen

 

Definitie van funkties

Bestudeer het programma KWADRSOM.C als voorbeeld van een C programma met funkties. Eigenlijk is dit niet de eerste keer dat we een funktie tegenkomen, omdat het main programma, dat we tot nu toe steeds gebruikten, technisch gezien ook een funktie is. Hetzelfde geldt voor de printf() funktie. Deze laatste is een funktie uit een funktie-bibliotheek die geleverd werd bij de compiler. int som; /* Dit is een globale variabele */ main () { int index; kop (); /* Roep kop aan */ for (index = 1; index <= 7; index++) kwadr (index); /* Kwadraat funktie */ voet (); /* Roep voet aan */ } kop () /* Dit is de 'kop' funktie */ { som = 0; /* Initialisatie */ printf ("Getallen kwadrateren en optellen ...\n\n"); } kwadr (invoer) /* Deze funktie geeft het kwadraat van een getal */ int invoer; { int kwadraat; kwadraat = invoer * invoer; som += kwadraat; printf ("Het kwadraat van %d is %d\n", invoer, kwadraat); } voet () /* Dit is de 'voet' funktie */ { printf ("\nDe som der kwadraten is %d\n", som); } Let eens op de statements in dit programma. Het bevat een regel met als inhoud kop(). Op deze manier wordt in C een funktie aangeroepen. De haakjes zijn verplicht, omdat de C compiler ze gebruikt om te ontdekken dat het hier om een funktie aanroep gaat en niet een foutieve declaratie van een variabele.

Zodra het programma bij dit statement aankomt, wordt de funktie met de naam kop aangeroepen, de statements van die funktie uitgevoerd en teruggekeerd naar het statement volgend op de aanroep. In dit geval is dat een for lus die zeven keer wordt doorlopen. Binnen de lus wordt een andere funktie aangeroepen met de naam kwadr. Tenslotte wordt nog een funktie met de naam voet aangeroepen en uitgevoerd. Vergeet op dit moment even de variabele index die tussen de haakjes van de funktie aanroep van kwadr() staat. Samenvattend zien we dus dat dit programma een funktie voor een kopregel aanroept, dan zeven keer de kwadraat funktie en tenslotte een funktie voor een voetregel.

De kop() funktie is opgebouwd volgens de regels die we tot nu toe voor main() gezien hebben. Het enige verschil is dat de naam anders is. Hetzelfde geldt voor de kwadr en de voet() funkties.

Het eerste statement van kop() maakt de variabele som gelijk aan nul. Deze variabele zullen we gebruiken om de som der kwadraten in op te slaan. Omdat de variabele som gedeclareerd werd voor de eerste funktie, is hij beschikbaar in alle funkties van het programma. Het is een zogenaamde globale variabele en zijn scope is het hele programma, in dit geval alle funkties. Over de scope van variabelen wordt later uitgebreider ingegaan. Het tweede statement drukt een kopregel af. De funktie eindigt en keert terug naar main().

In principe kunnen de twee statements van kop() ook direct in main() gezet worden en de funktie aanroep in zijn geheel vervangen. Het programma doet dan nog precies hetzelfde. Het is gedaan om de werking van funkties uit te leggen. Funkties zijn namelijk zeer waardevolle instrumenten in de programmeertaal C.


Parameter overdracht

In dit programma is meteen gebruik gemaakt van hetgeen je in de vorige les geleerd hebt. Om de for lus een aantal malen te doorlopen wordt een teller opgehoogd. In dit geval is dat de variabele index middels de C constructie index++.

De aanroep van de kwadraat funktie bevat iets nieuws, namelijk de variabele index++ tussen de haakjes. Voor de compiler is dit een indicatie dat bij de aanroep van kwadr() de waarde van de variabele index moet worden overgedragen aan de funktie. De funktie kan er dan verder mee rekenen.

Kijken we dan naar de funktie kwadr() dan vinden we ook daar de naam van een variabele tussen de haakjes, hier invoer. Dit is de naam van de variabele zoals we hem in de funktie graag willen hanteren. Het mag elke naam zijn, zolang hij maar aan de regels van een identifier voldoet. De funktie moet weten van welk type de variabele is. De declaratie wordt gedaan na de haakjes en voor de openings accolade. De programma regel int invoer; vertelt de funktie dat de doorgegeven parameter van het type integer is. Met dit alles hebben we bereikt dat de waarde van index uit main is overgedragen aan kwadr en terecht is gekomen in variabele invoer.

In de kwadraat funktie zelf wordt de variabele kwadraat gedeclareerd, puur voor gebruikt binnen de funktie zelf. De funktie berekend het kwadraat van de doorgegeven parameter en kent de waarde daarvan toe aan invoer. Tevens wordt de som der kwadraten bijgewerkt. De ingevoerde waarde en zijn kwadraat worden afgedrukt en vervolgens wordt teruggekeerd naar het aanroepende programma.

Bij de aanroep van de kwadraat funktie werd niet de variabele index zelf doorgegeven, doch een kopie gemaakt. De variabele index wordt daarmee beschermd tegen overschrijven en blijft onaangetast. De variabele invoer mag dus worden gewijzigd, hij is eigendom van de kwadraat funktie. Op deze manier is het echter niet mogelijk een eventueel gewijzigde waarde terug te geven aan de aanroepende funktie. Hoe dat gaat zullen we hierna behandelen. Nu zullen we ons behelpen met globale variabelen, waarover later in dit hoofdstuk nog wat meer zal worden verteld.

Tenslotte wordt in het programma nog de funktie voet() aangeroepen. Deze funktie bevat zelf geen variabelen en drukt slechts een voetregel af met de waarde van de som der kwadraten. Na voet() is er niets meer te doen en eindigt het programma.
Compileer en test dit programma nu.


Nogmaals parameter overdracht

We hebben geleerd dat we waarden vanuit een funktie terug kunnen geven aan een aanroepend programma met behulp van globale variabelen. Het kan echter mooier en om dat te laten zien moet je nu het programma KWADRAAT.C bestuderen. In dit programma zie je hoe een enkelvoudige waarde wordt teruggegeven aan een aanroepend programma. Voor een samengestelde waarde echter hebben we een andere oplossing nodig. Deze zal worden besproken in de hoofdstukken over tabellen en pointers. main () { int x, y; for (x = 0; x <= 7; x++) { y = kwadr (x); /* Haal het kwadraat van x */ printf ("Het kwadraat van %d is %d\n", x, y); } for (x = 0; x <= 7; ++x) { printf ("Het kwadraat van %d is %d\n", x, kwadr (x)); } } kwadr (invoer) /* Deze funktie geeft het kwadraat van een getal */ int invoer; { int kwadraat; kwadraat = invoer * invoer; return (invoer); } In main() worden twee variabelen gedeclareerd en begint een for lus die acht keer wordt doorlopen. Het eerste statement van de for lus luidt y = kwadr (x);, hetgeen nieuw voor je is. Het deel kwadr (x) moet niet al te veel problemen opleveren; het is de aanroep van een kwadraat funktie met x als parameter. Kijk eens naar de funktie zelf. Je ziet dat de parameter hier invoer wordt genoemd en dat de waarde met zichzelf vermenigvuldigd aan de variabele kwadraat wordt toegekend.

Dan volgt er een nieuw statement, het return statement. De waarde die tussen de haakjes staat wordt aan de funktie zelf toegekend en wordt als bruikbare waarde aan het aanroepende programma teruggegeven. Een funktie levert dus een waarde af. In het voorbeeld krijgt kwadr (x) dus de waarde van het kwadraat van x. Deze waarde wordt toegekend aan de variabele y. Als x de waarde 4 heeft, krijgt y als gevolg van de funktie aanroep de waarde 16.

Je kunt er ook als volgt bekijken. De combinatie kwadr (x) kan gezien worden als een variabele van het type integer en als waarde het kwadraat van zijn argument. Deze variabele mag overal staan waar C toestaat een normale variabele te programmeren.

Om dit principe nader te tonen is nogmaals een for lus in het programma opgenomen. De variabele y is nu weg gelaten en aan de printf() funktie wordt nu direct het resultaat van de kwadraat funktie aangeboden.

Tenslotte nog dit, het type van de betrokken variabele(n) en het type van funktie moeten met elkaar overeenstemmen. Als niets wordt opgegeven zal de C compiler integer als standaard waarde nemen. Dit betekent dat als het type waarmee wordt gewerkt anders dan integer is, dit expliciet moet worden opgegeven. Het hoofdstuk hierna beschrijft hoe dit in zijn werk gaat.


Een Floating Point funktie

Bestudeer het programma KWADRFLT.C voor een voorbeeld van een funktie van het type floating point. Begonnen wordt met de declaratie van een globale floating point variabele. In de main() funktie worden achtereenvolgens een integer en twee floating point variabelen gedeclareerd. Daarna zien we hoe we de C compiler vertellen dat we gebruik willen maken van het resultaat van twee funkties, hier sqr en glsqr, van het type floating point. De expressie float sqr(); geeft dus aan dat de funktie een float terug zal geven en geen int. float z; /* Dit is een globale variabele */ main () { int index; float x, y, sqr(), glsqr(); for (index = 0; index <= 7; index++) { x = index; /* Converteer int naar float */ y = sqr (x); /* Kwadrateer x */ printf ("Het kwadraat van %d is %10.4f\n", index, y); } for (index = 0; index <= 7; index++) { z = index; y = glsqr (); printf ("Het kwadraat van %d is %10.4f\n", index, y); } } float sqr (invoer) /* Kwadrateer een float, return een float */ float invoer; { float kwadraat; kwadraat = invoer * invoer; return (kwadraat); } float glsqr () /* Kwadrateer een float, return een float */ { return (z * z); } Kijk nu eens naar de funktie sqr() in het midden van het programma en merk op dat de naam wordt voorafgegaan door het woordje float. Voor de compiler is dit een aanwijzing dat de funktie van het type floating point is en dus een waarde zal teruggeven van het type float aan het aanroepende programma. Aanroep en funktie zijn nu met elkaar in overeenstemming. Verder zien we dat ook de lokale variabele invoer van het type float is.

De tweede funktie, glsqr(), geeft ook een floating point waarde terug. Deze funktie gebruikt een globale variabele als invoer en bevat zelf geen variabelen. Toch zal ook hier een correcte waarde worden teruggegeven.

De werking van dit programma als geheel moet nu duidelijk zijn en wordt daarom niet verder besproken. Compileer en test dit programma nu.


De scope van variabelen

Bestudeer het programma SCOPE.C voor een bespreking van wat we in C onder de scope van variabelen verstaan. int telling; /* Dit is een globale variabele */ main () { register int index; /* Deze variabele is lokaal voor main */ head1 (); /* Funktie aanroep */ head2 (); /* Funktie aanroep */ head3 (); /* Funktie aanroep */ } int teller; /* Deze variabele is beschikbaar vanaf hier */ head1 () { int index; /* Deze variabele is lokaal voor head1 */ index = 23; printf ("De waarde van index in 'head1' is %d\n", index); } head2 () { int telling; /* Deze variabele is lokaal voor head2 */ telling = 53; printf ("De waarde van telling in 'head2' is %d\n", telling); teller = 77; } head3 () { printf ("De waarde van teller in 'head3' is %d\n", teller); } De eerste variabele die we tegen komen is de globale variabele telling. Deze is beschikbaar in elke funktie van dit programma vanwege het feit dat hij werd gedeclareerd voor de definitie van deze funkties.

Een eindje verderop in het programma vinden we de variabele teller. Ook dit is een globale variabele die beschikbaar is in elke funktie van dit programma, behalve in main(), vanwege het feit dat hij werd gedeclareerd voor de definitie van de funkties. en na de definitie van main().

Een globale variabele is een variabele die gedeclareerd wordt buiten elke funktie. Globale variabelen zijn altijd aanwezig, een begrip wat we nog nader zullen leren kennen. Ze worden ook wel eens externe variabelen genoemd, omdat ze buiten elke funktie gedeclareerd zijn.

We keren terug naar het programma en zien dat er een variabele index wordt gedeclareerd van het type integer. Het woordje register geeft aan dat de compiler een register mag toewijzen aan deze variabele, indien de processor die beschikbaar heeft. Deze variabele is alleen beschikbaar in main(), omdat hij daar wordt gedeclareerd. Het is tevens een automatic variabele, hetgeen betekent dat hij slechts bestaat op het moment dat de funktie wordt aangeroepen en wordt uitgevoerd. Zodra de funktie wordt verlaten, wordt ook deze variabele weggegooid. In dit geval maakt het niet uit, immers de funktie main() is altijd actief, zelfs wanneer een andere funktie wordt aangeroepen.

Kijk naar de funktie head1(). Ook deze bevat een automatic variabele index. Deze heeft echter geen enkele relatie met die uit main(). Zolang head1() niet wordt uitgevoerd bestaat de variabele niet. Zodra head1() wordt uitgevoerd, wordt er ruimte voor de variabele gereserveerd. Wanneer de funktie wordt verlaten, wordt deze ruimte weer vrijgegeven. De variabele index uit main() blijft onaangetast.

Automatische variabelen zijn dus variabelen waarvoor ruimte wordt gereserveerd (en weer vrijgegeven) voor het moment dat ze nodig zijn. Het is belangrijk te onthouden dat de waarden van automatische variabelen, bij meerdere aanroepen van eenzelfde funktie, niet bewaard blijven. Ze bevatten dat, wat er op dat moment in het geheugen staat.

C kent nog een type variabele, de static variabele. Door het gereserveerde woord static voor de declaratie van een variabele binnen een funktie te plaatsen, wordt een variabele als zijnde statisch gedefinieerd. Statische variabelen blijven bestaan, ook tussen verschillende funktie aanroepen in. De ruimte die ze in het geheugen innemen wordt dus niet telkens vrijgegeven.

Door het gereserveerde woord static voor de declaratie van een externe variabele te plaatsen (buiten een funktie dus), wordt een variabele als zijnde private gedefinieerd. Private variabelen zijn niet bereikbaar vanuit andere programma's. Het is namelijk mogelijk in C om te refereren aan variabelen uit andere programma's. Door ze private te maken, worden ze voor de buitenwereld afgeschermd.

Kijk nog eens naar funktie head2(). Deze bevat de declaratie van de variabele telling. Hoewel telling reeds eerder werd gedeclareerd als globale variabele, is het toegestaan dit nog eens te doen binnen de funktie. Het is een nieuwe variabele die geen enkele relatie heeft met de globale variabele met dezelfde naam. De declaratie zorgt er echter voor dat de globale variabele onbereikbaar is voor head2(). Dit principe geeft je de mogelijkheid bestaande funkties te gebruiken, zonder je zorgen te hoeven maken wat de namen van de variabelen in die funkties zijn, er kan immers geen conflict ontstaan. Je moet wel je aandacht richten op de variabelen die als interface tussen functies gebruikt worden.

Funktie parameters worden gedefinieerd na de funktie haakjes en voor de openings accolade. Funktie variabelen worden gedeclareerd aan het begin van de funktie na de openings accolade en voor enig statement.


Standaard funktie bibliotheken

Elke C compiler wordt geleverd met standaard funkties, die je ter beschikking staan. Grofweg zijn dit Invoer/Uitvoer funkties, karakter- en string manipulatie funkties en rekenfunkties.

De meeste moderne compilers voegen daar nog een heleboel funkties aan toe die niet direct standaard zijn maar je wel helpen al het mogelijke uit je computer te halen. In het geval van de IBM PC zijn er funkties die de BIOS funkties van MS-DOS benaderen en funkties voor het uitgebreid aansturen van de grafische kaarten. Het totaal programma bevat heel veel van dit soort funktie aanroepen. Kijk dus zo af en toe eens naar Appendix C, "Totaal programma".


Recursie

Recursie is een programmeer techniek die in eerste instantie moeilijker lijkt dan het is. Bestudeer het programma RECURSIE.C om er kennis mee te gaan maken. Het is waarschijnlijk het meeste eenvoudige recursieve programma dat je kunt schrijven en om die reden van weinig nut. Maar voor ons doel (er wat van leren) is het uitstekend geschikt. main () { int index = 0; index = 8; tel_af (index); } tel_af (telling) int telling; { telling--; printf ("De waarde van de telling is %d\n", telling); if (telling > 0) tel_af (telling); printf ("De telling is nu %d\n", telling); } Recursie is niets meer dan een funktie die zichzelf aanroept. Om die reden ontstaat er een lus, een iteratie die op de een of andere manier beëindigd moet worden. In het voorbeeld programma wordt voor dit doel de variabele telling gebruikt, die bij eerste aanroep de waarde 8 heeft en in elke vervolgstap 1 lager is. Dit aflagen gebeurd doordat de funktie tel_af() zichzelf aanroept met de afgelaagde teller. Er zal uiteindelijk een moment komen dat telling nul is geworden en de funktie zichzelf niet meer aanroept. In plaats daarvan zal de funktie terugkeren naar de vorige stap en vandaar weer naar de vorige stap enz. enz., totdat weer wordt teruggekeerd naar de aanroep door main().

Voor een beter begrip kun je het beste denken dat er 8 kopieën van de funktie tel_af() in het geheugen staan, die elkaar een voor een aanroepen. Dat is niet wat er in werkelijkheid gebeurt, het gaat om het begrip.

Bij de recursieve aanroep worden alle variabelen en interne vlaggen die het systeem nodig heeft om te functie te kunnen beëindigen, ergens in een blok in het geheugen opgeslagen. Bij de volgende recursieve aanroep gebeurt weer hetzelfde, enz.. Bij de laatste aanroep wordt teruggekeerd, het geheugen blok opgehaald en opgeruimd. Er wordt weer teruggekeerd, opgehaald en opgeruimd enz. totdat de eerste weer bereikt is. De blokken worden intern opgeslagen in een geheugengebied die de stack wordt genoemd. De stack wordt door het systeem onderhouden en hier verder niet beschreven.

Wat belangrijk is bij recursief programmeren is dat het programma stopt met zichzelf aanroepen, bijvoorbeeld door een teller naar nul te laten lopen en bij deze nulwaarde terug te springen. Als dit niet gebeurt zal het programma zichzelf aan blijven roepen en daardoor op een gegeven moment abnormaal eindigen omdat de stack vol is.

Er volgt nu nog een voorbeeld van recursie. Bestudeer daartoe het programma TERUG.C.

main () { char regel[80]; int index = 0; strcpy (regel, "Dit is een string.\n"); heenweer (regel, index); } heenweer (regel, index) char regel[]; int index; { if (regel[index]) { printf ("%c", regel[index]); heenweer (regel, index+1); } printf ("%c", regel[index]); } Dit programma is nagenoeg gelijk aan het vorige programma, echter hier wordt gebruik gemaakt van een tabel van karakters (character array). Elke opvolgende aanroep van de funktie heenweer() drukt een volgend karakter van de tekst Dit is een string. af. Telkens als de funktie eindigt, wordt ook een karakter afgedrukt, echter dit keer van achter naar voren vanwege de recursie.

Maak je nog maar geen zorgen over de tabel van karakters die hier is toegepast. We willen je er vast mee vertrouwd maken. Er wordt in Hoofstuk 7, "Strings en Tabellen" uitgebreid op ingegaan.

Compileer en test deze programma's en kijk naar de resultaten.



Webdesign

Maak van Weblessen.nl uw startpagina!
Plaats Weblessen.nl bij uw favorieten. Neem contact met me op.
Heb je een Hosting?
Geef hier jouw mening over jouw web hosting

Webadres.info: Goede domeinnaam kiezen

Gesponsorde links:
Budget Webhosting
Web2host.nl
10eurohost.nl
Denit Hosting Solutions
YourHosting.nl
Starthosting.nl
Eduvision.nl
Educruitment.nl
Webadres.info


De link top 5:
Gratis Computercursussen
WebmasterStartpagina
MijnStartpagina.nu
Bluebird Animatie
Anouksweb
Link aanmelden
Alle Partners

Webmasterwoordenboek
A | B | C | D | E | F
G
| H | I | J | K | L | M
N
| O | P | Q | R | S | T
U | V | W | X | Y | Z

Films vanavond op Tv:

De klok:

(advertentie)

HTML leren
PHP cursus
XML lessen
XHTML les
CSS leer
leer C
REXX online
Red Hat Linux cursus