0

I have written a simple programme to display the first n primes, where n is input by the user. So far, it executes fine if the user writes an integer.

However, I would like the programme to keep asking the user for a valid input if the input isn't an integer (primes(input) != 1).

I tried creating a loop (see code) to do so, but the programme enters an infinite loop.

For example, when the user inputs a letter the programme keeps displaying infinitely "How many n first primes do you want to display?" until I quit. The scanf in the loop is ignored for some reason.

Various sources gave me different explanations including a buffer problem.

What is the exact reason for this infinite loop happening, and what is the best way to get the programme to give the user as many goes as possible until input is correct?

Here is the code:

#include <stdio.h>

int primes(int input);

int main(void)
{

  int input;
  
  printf("How many n first primes do you want to display? ");
  scanf("%d", &input);

    while(primes(input) != 1)
    {
    printf("How many n first primes do you want to display? ");
    scanf("%d", &input);
    }

  return 0;
}

int primes(int input)
{
  
  int count1 = 0, count2 = 0, b = 1, n = 2;
  
  if(input>=1) 
  {

      while (count1 < input)  
      { 
        b = 1;
        count2 = 0;
        while (b <= n)
        {
        
          if (n%b == 0)
          {

        count2++;
       
          }
         
          b++;
        
        }   
        
        if(count2 == 2)   
        {
        
          printf("%d\n",n);
          count1++;
         
        }
         
        n++;
          
      }

  return 1;
  
  }

  return 0;
              
}   
D-I-S-C
  • 79
  • 1
  • 6
  • 3
    The key point is to check the *return* value of `scanf`. – Eugene Sh. Sep 27 '21 at 16:31
  • 2
    When the user enters bad data it will stay in stdin until you consume it. – 001 Sep 27 '21 at 16:33
  • 3
    If you want to read a simple integer from the user, use `scanf`. But if you want to read an integer from the user and do something intelligent if the user types something other than an integer, **do not use `scanf`**. It's as simple as that. `scanf` is no good for that job. You can spend three hours and solve half of the problem, but the user will still be able to type pathological input that screws you up. Instead, spend one hour learning [how to read input using something other than `scanf`](https://stackoverflow.com/questions/58403537), and you can do a much better job. – Steve Summit Sep 27 '21 at 16:33
  • 1
    See also [this very similar question](https://stackoverflow.com/questions/69236662/checking-if-user-provided-value-is-integer-and-if-not-asking-for-a-correct-value). TL;DR: make use of `fgets()` and `strtol()`, and don't forget to discard unread characters when user's input is longer than the allowed maximum line. – Luca Polito Sep 27 '21 at 16:43
  • Does this answer your question? [Checking if user-provided value is integer and if not asking for a correct value](https://stackoverflow.com/questions/69236662/checking-if-user-provided-value-is-integer-and-if-not-asking-for-a-correct-value) – Toby Speight Oct 05 '21 at 12:03

1 Answers1

0

It really depends on your requirements.

The easiest thing to do is to check the return value from scanf. It's basically done like this:

if(scanf("%d", &input) != 1) {
    // Code for input failure
}

However, the above would accept "7asdf" which may or may not be desirable. It would also accept leading whitespace, like " 7".

If you want more fine grained control, you could always read a line and then parse it manually. Here is an idea for how it can be done:

char buf[100];
if( !fgets(buf, sizeof buf, stdin)) { // Read one line as input
    // Handle input error
}

buffer[strcspn(buffer, "\n")] = 0;  // Remove newline character because fgets leaves it there

int len = strlen(buffer);

for(int i=0; i<len; i++) {
    if( !isdigit((unsigned char)buffer[i]) ) {
        // Handle error
    }
}

The above code would not accept any other characters than digits. For instance, it would fail on leading or trailing whitespace.

klutt
  • 30,332
  • 17
  • 55
  • 95