Wanneer je leert programmeren, gebeurt het wel meer dan eens dat er een fout in je programma zit. Sommige fouten zijn eenvoudiger te vinden dan andere. We hebben het hier over de fouten die ervoor zorgen dat je programma niet doet wat jij als programmeur ervan verwacht.
Normaal geef je een programma pas aan de gebruiker wanneer het volgens jou foutloos werkt. Toch glipt er soms nog een fout door. Zo’n overgebleven fout in een programma noemen we een bug.
Het woord bug komt uit het Engels en betekent letterlijk beestje. De term raakte in zwang bij de eerste computers: er kroop wel eens een echt insect tussen de onderdelen, waardoor de machine niet meer werkte. Het opsporen en wegwerken van fouten heet sindsdien debuggen.
We onderscheiden drie soorten fouten. Elke soort herken je op een andere manier, en hieronder bekijken we ze één voor één.
De eerste soort fouten kan je al hebben tegengekomen. Het zijn fouten die je maakt tegen de syntaxregels van de taal C#. Zoals elke taal heeft een programmeertaal regels: er is een grammatica en een woordenschat. Het vergeten van haakjes, accolades of een puntkomma op het einde van een zin zijn allemaal mogelijke fouten van deze soort.
In de code hieronder werden met opzet enkele schrijffouten gemaakt:
int getal1 = 5;
Console.WriteLin(getal1 / 0
Er zitten meerdere fouten in deze twee regels: WriteLin bestaat niet (het moet
WriteLine zijn), het sluithaakje ) ontbreekt en ook de afsluitende puntkomma
; is vergeten.
Hoe herken je ze? Een syntaxisfout verhindert dat je programma start: de code wordt eerst gecontroleerd en pas uitgevoerd als ze grammaticaal klopt. Krijg je je programma niet aan de praat en wijst de foutmelding naar een bepaalde regel, dan gaat het bijna altijd om een schrijffout. Begin steeds bij de eerste fout in de melding: vaak verdwijnen meerdere fouten zodra je die ene oplost. Sla dus niet meteen in paniek wanneer er verschillende fouten tegelijk verschijnen.
Naast echte fouten geeft de compiler soms ook waarschuwingen (warnings). Een waarschuwing wijst op iets dat misschien niet de bedoeling is, maar die je programma niet tegenhoudt: het start en loopt gewoon verder. Een typisch voorbeeld is een variabele die je wel declareert maar nergens gebruikt.
int ongebruikt = 5; // waarschuwing: gedeclareerd maar nooit gebruikt
Console.WriteLine("Hallo");
Een fout (error) moet je oplossen voor je programma kan draaien; een waarschuwing mag je in principe negeren, maar het is een goede gewoonte om ze toch weg te werken, want vaak wijzen ze op een vergetelheid.
Tijdens het uitvoeren van een programma kan je nog andere soorten fouten tegenkomen. De code is dan grammaticaal in orde en het programma start netjes op, maar onderweg loopt er iets mis. Wanneer je probeert te delen door nul, of wanneer een variabele het resultaat niet kan opslaan, ontstaat zo’n run-time fout.
Het programma wordt dan tijdens de uitvoering onderbroken en geeft een melding met de oorzaak en de plaats van de fout. Twee veelvoorkomende fouten:
System.FormatException — de invoer heeft de verkeerde vormDeze fout is vaak het gevolg van een omzetting van gegevens. Je vraagt via
Console.ReadLine een getal in te vullen, maar de gebruiker vult niets in of
typt letters. In je programma probeer je die tekst dan met Convert.ToInt32 om
te vormen tot een getal, en dat lukt uiteraard niet.
int leeftijd = Convert.ToInt32(Console.ReadLine());
Typt de gebruiker hier vijf in plaats van 5, dan kan C# daar geen getal van
maken en gooit het een System.FormatException.
System.DivideByZeroException — delen door nulWiskundig is delen door nul niet toegelaten. Het is dus ook logisch dat dit niet
kan in een programma. Bij een gehele deling door nul onderbreekt C# het
programma met een System.DivideByZeroException.
int teller = 10, noemer = 0;
int resultaat = teller / noemer;
Er bestaan nog veel meer mogelijke uitvoeringsfouten, zoals een
OverflowException wanneer een getal te groot wordt voor zijn type. Het is
onbegonnen werk om ze hier allemaal op te sommen. Komt er een fout voor, dan vind
je meestal op het internet voldoende informatie om de oorzaak ervan te
achterhalen.
Hoe herken je ze? Een run-time fout duikt pas op tijdens het uitvoeren, en
meestal alleen bij bepaalde invoer (lege invoer, letters in plaats van cijfers,
een noemer die nul wordt). De melding noemt het type uitzondering
(FormatException, DivideByZeroException, …) en wijst naar de regel waar het
misging. Verderop leer je hoe je zulke fouten netjes kan opvangen zodat je
programma niet crasht.
Dit soort fouten is het moeilijkst op te sporen. Na het schrijven van je code kan je programma gewoon worden uitgevoerd, zonder enige foutmelding, maar het resultaat is niet wat je ervan verwacht. Je hebt dan waarschijnlijk een denkfout gemaakt, of je hebt de werking van de programmeertaal nog niet helemaal door.
Een klassiek voorbeeld is de omzetting van graden Celsius naar graden Fahrenheit. In de code ziet het er voor ons goed uit, maar C# doet het niet zoals wij verwachten:
double celsius, fahrenheit;
celsius = Convert.ToDouble(Console.ReadLine());
fahrenheit = (9 / 5) * celsius + 32;
Console.WriteLine("Omgezet in graden Fahrenheit is dat " + fahrenheit);
De formule lijkt te kloppen, en toch krijg je een verkeerd antwoord. De oorzaak
is 9 / 5: omdat 9 en 5 allebei gehele getallen zijn, voert C# een
gehele deling uit. Het resultaat is 1 in plaats van 1.8, en daardoor klopt
de hele omzetting niet. De computer heeft exact gedaan wat er stond, alleen niet
wat wij bedoelden.
Hoe herken je ze? Een logische fout geeft geen foutmelding: het programma loopt netjes tot het einde. Je merkt ze enkel doordat de uitvoer niet klopt. Daarom is het belangrijk om je programma te testen met invoer waarvan je het juiste antwoord op voorhand kent. Klopt de uitvoer niet, lees dan je code zorgvuldig regel voor regel na en redeneer wat de computer op elke lijn precies doet.
Samengevat:
- Schrijffouten / syntaxisfouten — tegen de regels van de taal; het programma start niet.
- Uitvoeringsfouten / run-time fouten — het programma start, maar valt onderweg stil met een uitzondering (bv.
FormatException,DivideByZeroException).- Logische fouten — het programma loopt zonder melding, maar het resultaat klopt niet.