0

The following code compiles and works as expected, despite one frustrating error in program flow that I don't understand ..
The loop in the middle of the main function works fine if I pass 2 or 5 as input. However, when I pass -3 or anything below zero (such as a character, which return -1), the loop continues forever and the program doesn't even pause for me to provide input for the scanf function ..

#include <stdio.h>
#include <stdlib.h>

void getNum(char * prompt, int*num)
{
    printf("%s", prompt);
    scanf("%d", num);
}

int main(int argc, char ** argv)
{
    int num = -1;
    while(num < 0) { // problem here
        getNum("Number of times you go to the gym in a week: ", &num);
    }
    return EXIT_SUCCESS;
}

I wonder were the mistake is ..

I noticed something strange .. When I change the loop to a do-while loop it works just fine ..

int main(int argc, char ** argv)
{
    int num;
    do {
        getNum("Number of times you go to the gym in a week: ", &num);
    } while (num < 0); // this works fine ..
    return EXIT_SUCCESS;
}

Also, for some reason, I recompiled the code and it worked fine ..

Can anybody explain this ?

Amr Ayman
  • 1,129
  • 1
  • 8
  • 24

2 Answers2

2

After accept answer

scanf("%d", num);, upon reading non-numeric input simple returns 0, leaving *num alone. The offending text is still in stdin and subsequent calls will get the same text and same results. Code should check the scanf() result value.

// weak
scanf("%d", num); // fails to consume offending input.

// good
*num = 0; // default answer
int retval;
do {
  printf("%s", prompt);
  retval = scanf("%d", num);  // returns EOF, 0, or 1
  // consume rest of line
  int c;
  while ((c = fgetc(stdin)) != '\n' && c != EOF);    
} while (retval == 0);  // repeat is no number read and stdin still open

[Edit]

Avoid using scanf(). Offer How to test input is sane as a solution to well handle reading int.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

You could try clearing STDIN data after you tried scanf :

void getNum(char * prompt, int*num)
{
    printf("%s", prompt);
    scanf("%d", num);

    // clean stdin
    char c;
    scanf("%c",&c);
    while (c != '\n' && c != EOF) scanf("%c",&c);
}
lpg
  • 4,897
  • 1
  • 16
  • 16
  • I suppose that makes sense .. Can't I just fflush that ? – Amr Ayman Aug 07 '14 at 11:16
  • 2
    +1, but I suggest `int c; while ((c = fgetc(stdin)) != '\n' && c != EOF);` to clean stdin – David Ranieri Aug 07 '14 at 11:16
  • This solution fails. When `scanf("%c",&c);` is called and the `stdin` is closed, `c` does not get the value `EOF` which may not fit in a `char` anyways. _Nothing_ is put in `c`! It has random data in it. @Alter Mann is correct, use `int c; while ((c = fgetc(stdin)) != '\n' && c != EOF);` to flush `stdin` up to the end-of-line. Neither does this answer insure `*num` has valid data. – chux - Reinstate Monica Aug 07 '14 at 19:11