Wiki

Clone wiki

CPL01 / scanf

Hoe voorkom ik dat mijn programma rare dingen doet als in plaats van een getal een letter wordt ingetypt?

Als je in C programma een getal inleest met scanf dan gebeuren er vreemde dingen als je in plaats van een getal letters intypt.

Bijvoorbeeld probleem.c:

#!C
#include <stdio.h>

int main(void)
{
    int getal;
    printf("Geef een geheel getal: ");
    scanf("%d", &getal);
    printf("Het ingelezen getal is %d.\n", getal);
    return 0;
}

Als je dit programma uitvoert en als invoer het woord Hallo intypt dan verschijnt de volgende uitvoer:

#!none
Geef een geheel getal: Hallo
Het getal is 55.

Oplossing 1

Deze fout kun je vrij eenvoudig afvangen door de returnwaarde van de functie scanf te testen. Deze functie geeft de integer waarde EOF terug als er iets fout gaat bij het inlezen. Anders geeft de functie het aantal variabelen terug dat succesvol is geconverteerd en ingelezen.

oplossing1.c:

#!C
#include <stdio.h>

int main(void)
{
    int getal, ret;
    do
    {
        printf("Geef een geheel getal: ");
        ret = scanf("%d", &getal);
        if (ret == 0)
        {
            printf("Dat was geen getal!\n");
            char karakter;
            scanf("%c", &karakter);
            printf("Maar het karakter %c.\n", karakter);
        }
        else if (ret == EOF)
        {
            printf("Er is een fout opgetreden bij het lezen!\n");
        }
    }
    while (ret != 1);
    printf("Het ingelezen getal is %d.\n", getal);
    return 0;
}

Als je dit programma uitvoert en als invoer het woord Hallo en daarna de waarde 23 intypt dan verschijnt de volgende uitvoer:

#!none

Geef een geheel getal: Hallo
Dat was geen getal!
Maar het karakter H.
Geef een geheel getal: Dat was geen getal!
Maar het karakter a.
Geef een geheel getal: Dat was geen getal!
Maar het karakter l.
Geef een geheel getal: Dat was geen getal!
Maar het karakter l.
Geef een geheel getal: Dat was geen getal!
Maar het karakter o.
Geef een geheel getal: 23
Het ingelezen getal is 23.

Oplossing 2

Het bij oplossing 1 gegeven programma geeft als je een woord intypt voor elke letter een aparte foutmelding. Dat is een beetje overdreven. Je kunt dit in Windows voorkomen door voordat je scanf aanroept alle nog aanwezig invoer weg te gooien door fflush(stdin) aan te roepen. Het bij oplossing 1 gegeven programma maakt als het inlezen niet lukt nog onderscheid tussen een leesfout en verkeerde invoer. Vaak willen we de scanf net zolang herhalen totdat het inlezen is gelukt zonder dat we er in geïnteresseerd zijn waarom het niet lukt.

oplossing2.c:

#!C
#include <stdio.h>

int main(void)
{
    int getal;
    do
    {
        printf("Geef een geheel getal: ");
        fflush(stdin);
    }
    while (scanf("%d", &getal) != 1);
    printf("Het ingelezen getal is %d.\n", getal);
    return 0;
}

Als je dit programma uitvoert en als invoer het woord Hallo en daarna de waarde 23 intypt dan verschijnt de volgende uitvoer:

#!none
Geef een geheel getal: Hallo
Geef een geheel getal: 23
Het ingelezen getal is 23.

Zeer uitgebreide informatie over de functie scanf kun je vinden op: http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html.

De aanroep fflush(stdio) werkt alleen op het Windows operating systeem en niet op andere operating systems zoals bijvoorbeeld Linux.

Oplossing 3

Het bij oplossing 2 gegeven programma werkt alleen correct op het Windows operating systeem. Volgens de C standaard mag de functie fflush alleen gebruikt worden met output streams. Op http://en.cppreference.com/w/c/io/fflush staat:

For input streams (and for update streams on which the last operation was input), the behavior is undefined.

stdin is een input steam dus de aanroep ffush(stdin) is undefined. De onderstaande oplossing maakt alleen gebruik van scanf en werkt correct op alle operating systems.

oplossing3.c:

#!C
#include <stdio.h>

int main(void)
{
    int getal;

    printf("Geef een geheel getal: ");
    while (scanf("%d", &getal) != 1)
    {
        char karakter;
        do
        {
            scanf("%c", &karakter);
        }
        while (karakter != '\n');
        printf("Geef een geheel getal: ");
    }
    printf("Het ingelezen getal is %d.\n", getal);
    return 0;
}

Als je dit programma uitvoert en als invoer het woord Hallo en daarna de waarde 23 intypt dan verschijnt de volgende uitvoer:

#!none
Geef een geheel getal: Hallo
Geef een geheel getal: 23
Het ingelezen getal is 23.

Updated