2

I am writing a code asking the user to input 10 integers, which are then fed to him backwards. I would like to create a "scanf check" to restrict character input. The while loop works insofar that it doesn't accept char, but it skips a integer input.

int main()
{

    int i = 0, number[10] = {0};
    char buf[128] = {0};

    for (i = 0; i < 10; i++)
    {
      printf("Please input number %d : ", i+1);

         while(scanf("%d", &number[i]) != 1)
      {
         scanf("%s", &buf);
         printf("Sorry, [%s] is not a number. Please input number %d : ", &buf, i);
      }
    }

    for (i = 0; i < 10; i++)
    {
    printf("\n Number %d is %d", (10-i), number[9-i]);
    }

    return EXIT_SUCCESS;
}
Sam
  • 7,252
  • 16
  • 46
  • 65
MIIJ
  • 35
  • 4
  • Try `fflush(stdin)` before the next `scanf` statement – Sakthi Kumar Jan 28 '14 at 09:11
  • 9
    @SakthiKumar: No, never use `fflush(stdin)` - it results in UB on many platforms. – Paul R Jan 28 '14 at 09:14
  • 1
    @SakthiKumar, thanks for your input. Paul R, what would you recommmend? – MIIJ Jan 28 '14 at 09:15
  • @user3243738 I'd recommend you do not use `scanf()` at all. It's a horrible function (it's a mistake, it's a design error in the stdlib. It tries to do two completely different things - getting user input and parsing it -, and naturally, it fails to do either of them properly. Its usage is counter-intuitive, it's hard to get it right, especially for a beginner.) - use `fgets()` instead if you are satisfied with line-by-line input, or `fgetc()` if you need character level access. –  Jan 28 '14 at 09:17
  • 1
    You can use [fpurge](http://linux.die.net/man/3/fpurge) if your platform has it, or for maximum portability just read characters and discard until you hit a newline. – Paul R Jan 28 '14 at 09:17
  • 3
    Oops! `fflush` is only for *output streams*. Sorry for the comment. – Sakthi Kumar Jan 28 '14 at 09:20
  • @PaulR sorry for the noob question, what is UB? – Daan Timmer Jan 28 '14 at 09:22
  • When error occurs then scanf then input remains in stdin buffer you have to explicitly read-and-remove from input-buffer. Back in time I answer here [Scanf won't execute for second time](http://stackoverflow.com/questions/17827603/scanf-wont-execute-for-second-time/17827635#17827635) And modify OPsIthe ser2613444) code there. Although preferred way is read in a buffer then parse-and-validate it. – Grijesh Chauhan Jan 28 '14 at 09:24
  • @DaanTimmer: UB = [Undefined Behavio(u)r](https://en.wikipedia.org/wiki/Undefined_behavior). – Paul R Jan 28 '14 at 09:24
  • I apologize in advance for saying this but... stack overflow is AWESOME. sorry sorry. – MIIJ Jan 28 '14 at 09:25

2 Answers2

4

As pointed out by H2CO3, don't use scanf, an alternative is fgets and strtol:

int i, number[10] = {0};
char buf[128], *p;

for (i = 0; i < 10; i++) {
    printf("Please input number %d : ", i+1);
    while (1) {
        fgets(buf, sizeof(buf), stdin);
        if ((p = strchr(buf, '\n')) != NULL) {
            *p = '\0';
        }
        number[i] = (int)strtol(buf, &p, 10);
        if (p == buf || *p != '\0')  {
            printf("Sorry, [%s] is not a number. Please input number %d : ", buf, i + 1);
        } else {
            break;
        }  
    }
}
for (i = 0; i < 10; i++) {
    printf("\n Number %d is %d", (10-i), number[9-i]);
}
return EXIT_SUCCESS;
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • 2
    @MIIJ If you find an answer helpful (and correct), then thank them by up-voting the answer. Click on the arrow pointing upwards on the left side of the post. So in this case maybe up-vote both answers and accept the one you liked best (which you already did). – Lundin Jan 28 '14 at 10:51
  • 1
    @Lundin, thanks for the tip, I tried before but it seems I don't have enough "reputation" to do so. Will do so as soon as I can. – MIIJ Jan 28 '14 at 11:00
  • @Alter Mann, Is the following correct? [if ((p = strchr(buf, '\n')) != NULL) //if the buf holds a '\n' value (return key)]...[ *p = '\0'; //the p char variable is set to null-terminator, signifying the end of a string]...[ x = (int)strtol(buf, &p, 10); //x is the parsing, at base 10, from the chars in the buf, until the value of p, to int.]...[ if (p == buf || *p != '\0') // if p hasn't been parsed, that it is exactly equal to the buffer values //2) I don't understand the 2nd entity(when it is equal to only 'return')?] ... when does it check for letters? – MIIJ Jan 29 '14 at 08:33
  • 1
    @MIIJ, you can translate this as: if user types nothing or strtol fails to read a number – David Ranieri Jan 29 '14 at 09:40
  • 1
    @Alter Mann, thanks for your answer, I had failed to see that the "base 10" in the strtol was the filter for letters... 'a' does not have an int equivalent. Learning, learning. – MIIJ Jan 29 '14 at 10:06
1

The code works fine for integer also. The only mistake I found is while printing the sorry message, you are printing just i, it should be i+1.

    int i = 0, number[10] = {0};
    char buf[128] = {0};

    for (i = 0; i < 10; i++)
    {
      printf("Please input number %d : ", i+1);

         while(scanf("%d", &number[i]) != 1)
      {
         scanf("%s", &buf);
         printf("Sorry, [%s] is not a number. Please input number %d : ", &buf, i+1);
      }
    }

    for (i = 0; i < 10; i++)
    {
    printf("\n Number %d is %d", (10-i), number[9-i]);
    }
Dineshkumar
  • 1,468
  • 4
  • 22
  • 49