© Harry Broeders.
Deze pagina is bestemd voor studenten van de Haagse Hogeschool - Academie voor Technology, Innovation & Society Delft.
Bij het vak GESPRG krijg je regelmatig een opdracht die als volgt begint: Schrijf een programma dat ... Hoe pak je zoiets (als beginnend programmeur) nu aan? Als voorbeeld neem ik de opdracht: schrijf een programma dat een geheel getal 0 < n < 7 inleest en vervolgens de tafels van 1 t/m n naast elkaar afdrukt.
De methode die ik gebruik om tot een werkend programma te komen dat aan de opdracht voldoet is stapgewijze verfijning (Engels: stepwise refinement). Ik begin met een eenvoudig programma en breid het programma stap voor stap uit tot ik uiteindelijk het gewenste programma heb. Ik test het programma na elke stap. De bovenstaande opdracht zou ik als volgt aanpakken.
De eerste stap heeft nog niets met programmeren te maken. Voordat ik begin te programmeren denk ik eerst over de opdracht na. Snap ik wat ik moet maken? Het helpt vaak als ik mogelijke testgevallen bedenk. Bijvoorbeeld: bij de invoer 4 moet het programma de volgende uitvoer produceren:
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 2 x 4 = 8 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 3 x 4 = 12 4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16 5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 8 x 1 = 8 8 x 2 = 16 8 x 3 = 24 8 x 4 = 32 9 x 1 = 9 9 x 2 = 18 9 x 3 = 27 9 x 4 = 36 10 x 1 = 10 10 x 2 = 20 10 x 3 = 30 10 x 4 = 40
Bij het zien van deze gewenste uitvoer realiseer ik mezelf dat het erg belangrijk
is dat de regels van de tafels netjes onder elkaar worden afgedrukt. Ik herinner
me hoe in de les is behandeld dat je bij het afdrukken van een geheel getal
met behulp van printf
een veldbreedte kunt opgeven, bijvoorvbeeld
printf("3d", getal);
zal de waarde van de variabele
getal
op een veld van 3 karakters breed afdrukken. Als getal
de waarde 7
heeft dan wordt dus afgedrukt
<spatie><spatie>7
.
Elk C programma heeft hetzelfde begin en einde. Ik heb een bestandje
c.c gemaakt
waarin een C programma staat dat niets doet. Ik begin met een kopietje van
dat bestand en noem dat
tafels_stap1.c
:
#include <stdio.h>
/* © 2012 Harry Broeders */
int main(void) {
/* Hier komt de code */
fflush(stdin);
getchar();
return 0;
}
Het is altijd handig om met de invoer te beginnen. Ik begin dus met het eerste
deel van de opdracht: schrijf een programma dat een geheel getal 0 <
n < 7 inleest. Ik herinner mij uit de les dat ik een geheel getal
kan inlezen met behulp van scanf
. Voordat ik de waarde van
n inlees wil ik de gebruiker eerst vertellen wat er van hem/haar verwacht
wordt door op het scherm te zetten: Geef de waarde van n (1..6):
,
dat kan ik doen met behulp van printf
. Om te kijken of het inlezen
is gelukt druk ik de waarde van n af. Zie
tafels_stap2.c:
#include <stdio.h>
/* © 2012 Harry Broeders */
/* Dit programma leest een geheel getal 0 < n < 7
en drukt vervolgens de tafels van 1 t/m n naast elkaar af */
int main(void) {
int n;
printf("Geef de waarde van n (1..6): ");
scanf("%d", &n);
printf("Test n = %d", n);
fflush(stdin);
getchar();
return 0;
}
Als ik de waarde 4 invoer dan ziet de uitvoer van het programma er als volgt uit (de invoer is onderstreept weergegeven):
Geef de waarde van n (1..6): 4 Test n = 4
Als ik de waarde -3 invoer dan ziet de uitvoer van het programma er als volgt uit:
Geef de waarde van n (1..6): -3 Test n = -3
Ik bedenk me dat het netjes is om te controlleren of het ingevoerde getal binnen de gestelde grenzen ligt. Wat moet er gebeuren als de gebruiker een getal invoert dat buiten deze grenzen ligt? Ik besluit om de gebruiker opnieuw te vragen om de waarde in te voeren (zonder foutmelding) en de ingevoerde waarde opnieuw in te lezen. Ik wil dus het programmadeel:
printf("Geef de waarde van n (1..6): ");
scanf("%d", &n);
herhalen totdat een geldige waarde is ingevoerd. Ik herinner me uit de les
dat er verschillende herhalingsinstructies zijn (for
, do
while
en while
). Het bovenstaande programmadeel moet
minstens 1x herhaald worden en het is afhankelijk van de gebruiker hoe vaak
het herhaald moet worden. Het programmadeel moet dus een onbekend aantal
maal >=1 herhaald worden. Om die reden moet ik (volgens de theorieles)
kiezen voor een do while
lus. Zie
tafels_stap3.c:
#include <stdio.h>
/* © 2012 Harry Broeders */
/* Dit programma leest een geheel getal 0 < n < 7
en drukt vervolgens de tafels van 1 t/m n naast elkaar af */
int main(void) {
int n;
do {
printf("Geef de waarde van n (1..6): ");
scanf("%d", &n);
} while(n < 1 || n > 6);
printf("Test n = %d", n);
fflush(stdin);
getchar();
return 0;
}
Bij het testen probeer ik eerst een aantal ongeldige waarden en constateer dat het programma correct werkt:
Geef de waarde van n (1..6): -3 Geef de waarde van n (1..6): 0 Geef de waarde van n (1..6): 8000 Geef de waarde van n (1..6): 7 Geef de waarde van n (1..6): 4 Test n = 4
De waarde van n wordt nu dus succesvol ingelezen en op de juiste wijze gecontroleerd. Het tweede deel van de opdracht was: ... en vervolgens de tafels van 1 t/m n naast elkaar afdrukt. Het tweede deel van de opdracht is voor een beginnend programmeur misschien te moeilijk om in één stap uit te voeren. Ik bedenk dat het niet zo moeilijk is om de eerste regel van de tafels af te drukken. Dus bij de invoer 4 moet het programma de volgende uitvoer produceren:
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4
en bij de invoer 6 moet het programma de volgende uitvoer produceren:
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 1 x 5 = 5 1 x 6 = 6
Het valt meteen op dat het stukje uitvoer 1 x i =
i
wordt herhaald voor i = 1 tot en met i
= n. Hierbij is i het nummer van de tafel. We moeten het
programmadeel dat dit stukje print dus n maal herhalen. Het aantal
herhalingen is dus bekend als de herhaling begint (want de waarde van
n is dan al ingelezen). Omdat het aantal herhalingen bekend is moet
ik (volgens de theorieles) kiezen voor een for
lus. Zie
tafels_stap4.c:
#include <stdio.h>
/* © 2012 Harry Broeders */
/* Dit programma leest een geheel getal 0 < n < 7
en drukt vervolgens de tafels van 1 t/m n naast elkaar af */
int main(void) {
int n, tafel;
do {
printf("Geef de waarde van n (1..6): ");
scanf("%d", &n);
} while(n < 1 || n > 6);
for (tafel = 1; tafel < n + 1; tafel = tafel + 1) {
printf(" 1 x %d = %2d ", tafel, 1 * tafel);
}
printf("\n");
fflush(stdin);
getchar();
return 0;
}
Bij het testen blijkt dat het programma correct werkt:
Geef de waarde van n (1..6): 6 1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 1 x 5 = 5 1 x 6 = 6
Als ik alle 10 regels van de tafels wil afdrukken dan moet ik het programmadeel waarin de eerste regel wordt afgedrukt 10x herhalen. Het programmagedeelte dat herhaald moet worden is dus:
for (tafel = 1; tafel < n + 1; tafel = tafel + 1) {
printf(" 1 x %d = %2d ", tafel, 1 * tafel);
}
printf("\n");
De constante 1 die in de eerste regel wordt afgedrukt moet in de tweede regel
vervangen worden door de constante 2, in de derde regel door de constante
3 enz. Ik maak een variabele factor
aan die "loopt" van 1 t/m
10. Omdat het aantal herhalingen bekend is (10x) gebruik ik een
for
loop. Zie
tafels_stap5.c:
#include <stdio.h>
/* © 2012 Harry Broeders */
/* Dit programma leest een geheel getal 0 < n < 7
en drukt vervolgens de tafels van 1 t/m n naast elkaar af */
int main(void) {
int n, tafel, factor;
do {
printf("Geef de waarde van n (1..6): ");
scanf("%d", &n);
} while(n < 1 || n > 6);
for (factor = 1; factor < 11; factor = factor + 1) {
for (tafel = 1; tafel < n + 1; tafel = tafel + 1) {
printf("%2d x %d = %2d ", factor, tafel, factor * tafel);
}
printf("\n");
}
fflush(stdin);
getchar();
return 0;
}
Bij het testen blijkt dat het programma correct werkt:
Geef de waarde van n (1..6): 6 1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 1 x 5 = 5 1 x 6 = 6 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 2 x 4 = 8 2 x 5 = 10 2 x 6 = 12 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 3 x 4 = 12 3 x 5 = 15 3 x 6 = 18 4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16 4 x 5 = 20 4 x 6 = 24 5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25 5 x 6 = 30 6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 6 x 5 = 30 6 x 6 = 36 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 8 x 1 = 8 8 x 2 = 16 8 x 3 = 24 8 x 4 = 32 8 x 5 = 40 8 x 6 = 48 9 x 1 = 9 9 x 2 = 18 9 x 3 = 27 9 x 4 = 36 9 x 5 = 45 9 x 6 = 54 10 x 1 = 10 10 x 2 = 20 10 x 3 = 30 10 x 4 = 40 10 x 5 = 50 10 x 6 = 60
Bij het testen type ik per ongeluk een letter in. Het programma komt nu in een oneinige loop. Hier is een deel van de uitvoer:
Geef de waarde van n (1..6): a Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n ( 1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): G eef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1 ..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde v an n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de w aarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Ge ef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1. .6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde va n n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de wa arde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Gee f de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1.. 6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef de waa rde van n (1..6): Geef de waarde van n (1..6): Geef de waarde van n (1..6): Geef
Bij navraag blijkt dit een bekend probleem te zijn. Zie: Hoe voorkom ik dat mijn programma rare dingen doet als in plaats van een getal een letter wordt ingetypt?
Na bovenstaande verwijzing bestudeerd te hebben kom ik tot het volgende
programma, zie
tafels_final.c :
#include <stdio.h>
/* © 2012 Harry Broeders */
/* Dit programma leest een geheel getal 0 < n < 7
en drukt vervolgens de tafels van 1 t/m n naast elkaar af */
int main(void) {
int factor, tafel, n;
do {
printf("Geef de waarde van n (1..6): ");
fflush(stdin);
} while (scanf("%d", &n) != 1 || n < 1 || n > 6);
for (factor = 1; factor < 11; factor = factor + 1) {
for (tafel = 1; tafel < n + 1; tafel = tafel + 1) {
printf("%2d x %d = %2d ", factor, tafel, factor * tafel);
}
printf("\n");
}
fflush(stdin);
getchar();
return 0;
}
Bij het testen blijkt dat het programma correct werkt ook als je tekst invoert:
Geef de waarde van n (1..6): a Geef de waarde van n (1..6): Doe maar wat! Geef de waarde van n (1..6): -3 Geef de waarde van n (1..6): 0 Geef de waarde van n (1..6): 7 Geef de waarde van n (1..6): 300 Geef de waarde van n (1..6): 3 1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 8 x 1 = 8 8 x 2 = 16 8 x 3 = 24 9 x 1 = 9 9 x 2 = 18 9 x 3 = 27 10 x 1 = 10 10 x 2 = 20 10 x 3 = 30