C Language
Iteratiestatements / loops: voor, zolang, terwijl
Zoeken…
Syntaxis
- /* alle versies */
- voor ([expressie]; [expressie]; [expressie]) one_statement
- voor ([expressie]; [expressie]; [expressie]) {nul of meerdere beweringen}
- terwijl (expressie) one_statement
- terwijl (expressie) {nul of meerdere beweringen}
- do one_statement while (expressie);
- doe {een of meer statements} while (expressie);
- // sinds C99 naast het bovenstaande formulier
- voor (verklaring; [uitdrukking]; [uitdrukking]) one_statement;
- voor (verklaring; [uitdrukking]; [uitdrukking]) {nul of meerdere verklaringen}
Opmerkingen
Iteratie Statement / Loops vallen in twee categorieën:
- head-gecontroleerde iteratie statement / loops
- voetgestuurde iteratie-instructie / lussen
Head-Controlter Iteration Statement / Loops
for ([<expression>]; [<expression>]; [<expression>]) <statement>
while (<expression>) <statement>
for ([declaration expression]; [expression] [; [expression]]) statement
Voetgestuurde herhalingstekst / lussen
do <statement> while (<expression>);
For loop
Om een codeblok opnieuw en opnieuw uit te voeren, komen lussen in beeld. De for
lus moet worden gebruikt wanneer een codeblok een vast aantal keren moet worden uitgevoerd. Om bijvoorbeeld een array met grootte n
te vullen met de gebruikersinvoer, moeten we scanf()
n
keer uitvoeren.
#include <stddef.h> // for size_t
int array[10]; // array of 10 int
for (size_t i = 0; i < 10; i++) // i starts at 0 and finishes with 9
{
scanf("%d", &array[i]);
}
Op deze manier wordt de functie-aanroep scanf()
n
keer uitgevoerd (10 keer in ons voorbeeld), maar wordt deze slechts eenmaal geschreven.
Hier is de variabele i
de lusindex en kan deze het beste als gepresenteerd worden opgegeven. Het type size_t
(type formaat) moet worden gebruikt voor alles dat telt of lussen door middel van data-objecten.
Deze manier om variabelen in de for
declareren, is alleen beschikbaar voor compilers die zijn bijgewerkt naar de C99-standaard. Als je om de een of andere reden nog steeds met een oudere compiler zit, kun je de lusindex vóór de for
lus declareren:
#include <stddef.h> /* for size_t */
size_t i;
int array[10]; /* array of 10 int */
for (i = 0; i < 10; i++) /* i starts at 0 and finishes at 9 */
{
scanf("%d", &array[i]);
}
Herhalingslus
Een while
lus wordt gebruikt om een stukje code uit te voeren terwijl een voorwaarde waar is. De while
lus moet worden gebruikt wanneer een codeblok een variabel aantal keren moet worden uitgevoerd. De getoonde code krijgt bijvoorbeeld de invoer van de gebruiker, zolang de gebruiker getallen invoert die niet 0
. Als de gebruiker 0
invoegt, is de voorwaarde while niet meer waar, dus de uitvoering verlaat de lus en gaat door naar een volgende code:
int num = 1;
while (num != 0)
{
scanf("%d", &num);
}
Do-While-lus
Anders dan for
en while
lussen, controleren do-while
lussen de waarheid van de voorwaarde aan het einde van de lus, wat betekent dat het do
blok één keer wordt uitgevoerd en vervolgens de toestand van de while
code onderaan het blok controleert. Dit betekent dat een do-while
lus altijd minstens één keer wordt uitgevoerd.
Deze do-while
lus krijgt bijvoorbeeld getallen van de gebruiker, totdat de som van deze waarden groter is dan of gelijk is aan 50
:
int num, sum;
num = sum = 0;
do
{
scanf("%d", &num);
sum += num;
} while (sum < 50);
do-while
lussen zijn relatief zeldzaam in de meeste programmeerstijlen.
Structuur en controlestroom in een for-lus
for ([declaration-or-expression]; [expression2]; [expression3])
{
/* body of the loop */
}
In een for
lus heeft de lusvoorwaarde drie expressies, alle optioneel.
- De eerste expressie,
declaration-or-expression
, initialiseert de lus. Het wordt precies één keer aan het begin van de lus uitgevoerd.
Het kan een declaratie en initialisatie van een lusvariabele zijn, of een algemene uitdrukking. Als het een verklaring is, wordt het bereik van de gedeclareerde variabele beperkt door de instructie for
.
Historische versies van C stonden hier alleen een expressie toe en de verklaring van een lusvariabele moest vóór de for
worden geplaatst.
- De tweede expressie,
expression2
, is de testvoorwaarde . Het wordt eerst uitgevoerd na de initialisatie. Als de voorwaardetrue
, komt de besturing in het lichaam van de lus. Zo niet, dan verschuift deze naar buiten het lichaam van de lus aan het einde van de lus. Vervolgens wordt deze voorwaarde gecontroleerd na elke uitvoering van de hoofdtekst en de update-instructie. Als hettrue
, gaat de besturing terug naar het begin van het lichaam van de lus. De voorwaarde is meestal bedoeld als een controle op het aantal keren dat de body van de lus wordt uitgevoerd. Dit is de primaire manier om een lus te verlaten, de andere manier is om jump-instructies te gebruiken . - De derde expressie,
expression3
, is de update-instructie . Het wordt uitgevoerd na elke uitvoering van het lichaam van de lus. Het wordt vaak gebruikt om een variabele te verhogen die het aantal keren dat het luslichaam heeft uitgevoerd, verhoogt en deze variabele wordt een iterator genoemd .
Elke uitvoering van het luslichaam wordt een iteratie genoemd .
Voorbeeld:
for(int i = 0; i < 10 ; i++)
{
printf("%d", i);
}
De output is:
0123456789
In het bovenstaande voorbeeld wordt eerst i = 0
uitgevoerd, waardoor i
wordt geïnitialiseerd. Vervolgens wordt de voorwaarde i < 10
gecontroleerd, die evalueert als true
. De besturing gaat het lichaam van de lus binnen en de waarde van i
wordt afgedrukt. Vervolgens verschuift de besturing naar i++
, waarbij de waarde van i
wordt bijgewerkt van 0 naar 1. Vervolgens wordt de voorwaarde opnieuw gecontroleerd en gaat het proces verder. Dit gaat door totdat de waarde van i
wordt. Vervolgens wordt de voorwaarde i < 10
false
geëvalueerd, waarna de besturing uit de lus komt.
Oneindige lussen
Van een lus wordt gezegd dat het een oneindige lus is als de besturing binnenkomt maar nooit het lichaam van de lus verlaat. Dit gebeurt wanneer de testvoorwaarde van de lus nooit als false
evalueert.
Voorbeeld:
for (int i = 0; i >= 0; )
{
/* body of the loop where i is not changed*/
}
In het bovenstaande voorbeeld wordt de variabele i
, de iterator, geïnitialiseerd op 0. De testvoorwaarde is aanvankelijk true
. i
wordt echter nergens in het lichaam gewijzigd en de update-expressie is leeg. Daarom zal i
0 blijven en zal de testvoorwaarde nooit als false
evalueren, wat leidt tot een oneindige lus.
Ervan uitgaande dat er geen springinstructies zijn, is een andere manier om een oneindige lus te vormen, door de voorwaarde expliciet waar te houden:
while (true)
{
/* body of the loop */
}
In een for
lus is de voorwaarde-instructie optioneel. In dit geval is de toestand altijd vacuuum true
, wat leidt tot een oneindige lus.
for (;;)
{
/* body of the loop */
}
In bepaalde gevallen kan de voorwaarde echter opzettelijk true
worden gehouden, met de bedoeling de lus te verlaten met behulp van een jump-statement zoals break
.
while (true)
{
/* statements */
if (condition)
{
/* more statements */
break;
}
}
Loop Unrolling en Duff's Device
Soms kan de rechtlijnige lus niet volledig in het luslichaam worden opgenomen. Dit komt omdat de lus moet worden gevuld met enkele uitspraken B. Vervolgens begint de iteratie met enkele uitspraken A , die vervolgens weer worden gevolgd door B voordat een lus wordt gemaakt.
do_B();
while (condition) {
do_A();
do_B();
}
Om mogelijke knip / plak problemen met het tweemaal herhalen van B in de code te voorkomen, kan Duff's Device worden toegepast om de lus vanaf het midden van de while
body te starten, met behulp van een schakelinstructie en doorvalgedrag.
switch (true) while (condition) {
case false: do_A(); /* FALL THROUGH */
default: do_B(); /* FALL THROUGH */
}
Duff's Device is eigenlijk uitgevonden om lusafrollen te implementeren. Stel je voor dat je een masker op een geheugenblok toepast, waarbij n
een getekend integraal type is met een positieve waarde.
do {
*ptr++ ^= mask;
} while (--n > 0);
Als n
altijd deelbaar was door 4, zou je dit gemakkelijk kunnen uitrollen als:
do {
*ptr++ ^= mask;
*ptr++ ^= mask;
*ptr++ ^= mask;
*ptr++ ^= mask;
} while ((n -= 4) > 0);
Maar met Duff's Device kan de code dit afrollende idioom volgen dat op de juiste plaats in het midden van de lus springt als n
niet deelbaar is door 4.
switch (n % 4) do {
case 0: *ptr++ ^= mask; /* FALL THROUGH */
case 3: *ptr++ ^= mask; /* FALL THROUGH */
case 2: *ptr++ ^= mask; /* FALL THROUGH */
case 1: *ptr++ ^= mask; /* FALL THROUGH */
} while ((n -= 4) > 0);
Dit soort handmatig uitrollen is zelden vereist bij moderne compilers, omdat de optimalisatie-engine van de compiler namens de programmeur lussen kan uitrollen.