Patrick Roberts
Patrick Roberts

Reputation: 51946

C program loops infinitely after scanf gets unexpected data

I have a program where I want the input integer to be between 2 and 64 inclusive, so I put scanf inside a do { ... } while loop. Here's the code I initially tested:

int initialBase;

do {
  printf("Initial base: ");
  scanf("%i", &initialBase);
} while (initialBase < 2 || initialBase > 64);

The problem is whenever the input is not a valid integer, it just outputs the printf statement indefinitely and no longer prompts for user input, instantly flooding the console. Why is that happening and what's a better way of reading input that satisfies the conditions I want?

Upvotes: 2

Views: 190

Answers (1)

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53016

When scanf() fails, the argument is not automatically initialized, and uninitialized values could be any value, so it might be less than 2 or greater than 64 no one knows.

Try this

int initialBase;

/* some default value would be good. */
initialBase = 2;
do {
  printf("Initial base: ");
  if (scanf("%i", &initialBase) != 1)
      break;
} while ((initialBase < 2) || (initialBase > 64));

the check will break out of the loop if you input something that is not a number, the initialiazation of initialBase is just a good habit which in your case could have prevented the behavior you describe, but in this case it's there to prevent accessing an uninitialized value after the while loop.

The reason the loop didn't stop, was because scanf() leaves some characters in the input stream when they are not matched, and calling scanf() again while those characters are still there will make scanf() keep waiting for valid input, but returning immediatly with the currently invalid input that is in the stream, if you want to keep reading, try reading characters from the stream until a '\n' is found, this way

int initialBase;

initialBase = 0;
do {
    printf("Initial base: ");
    if (scanf("%i", &initialBase) != 1)
    {
        while (fgetc(stdin) != '\n');
        continue;
    }
} while ((initialBase < 2) || (initialBase > 64));

Upvotes: 3

Related Questions