0

I'm trying to make a program where the user inputs value to an array. What is actually required is that the program should validate against a char character. So if the user inputs a random char such as 'n' the program should tell him "You introduced a char, please input an integer: ".

How is that possible to make that without using a char variable?

for (i = 1; i <= size; i++) {
      printf("Introduce the value #%d of the list: ", i);
      scanf("%d", &list[i]);
      if () { // I'm blocked right in this line of code.
        printf("What you tried to introduce is a char, please input an integer: ");
        scanf("%d", &list[i]);
      }

Thanks in advance.

  • Please provide a [mcve]. – Yunnosch Mar 28 '19 at 01:00
  • start by checking the return value of `scanf`. it will tell you when it fails. – MFisherKDX Mar 28 '19 at 01:02
  • @Yunnosch: As the page you link to says, an MCVE is for asking about a problem caused by existing code. This is not such a question. It asks about how to accomplish something with code that does not exist yet. An MCVE is not required. – Eric Postpischil Mar 28 '19 at 02:30
  • @EricPostpischil Yes you are right. An MCVE is required only for questions about existing but not working code. It would be stretching things to interpret this as such a question. However, OP does seem to have code which does not work as desired. Either becaue it does use a char variable (why would otherwise the question explicitly ask for solutions which don't?) or for not achieving the goal. The shown code seems to come from that second alternative. So what I am asking for is a more complete code (i.e. defining `list` and giving more of a foundation for answer) and verifiably gets as ... – Yunnosch Mar 28 '19 at 05:47
  • ... close as possible to the goal. I think the term MCVE is applicable to what I ask and what would help answer this question, even if it is not required for this question. I do agree with your input (blindly asking for a MCVE in "I have no idea how to start" is what I also reguarily challenge). – Yunnosch Mar 28 '19 at 05:50
  • Daniel Logvin, sorry for that link without explaining that it only describes what would be useful, though the explained reasons are slightly off the mark for your question. Please note that I neither downvoted nor close-voted, I just asked for more of your code context, without wanting any "full code". – Yunnosch Mar 28 '19 at 05:52

2 Answers2

2

As @MFisherKDX says, check the return value of scanf. From the scanf man page:

These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.

The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.

So capturing the return value of scanf in an int variable and then comparing that variable to 1 (in your case, because you are only attempting to read 1 item) should tell you if scanf successfully read an integer value.

However, there is a nasty pitfall when using scanf that you should be aware of. If you do type n at the prompt, scanf will fail and return 0, but it will also not consume the input you typed. Which means that the next time you call scanf, it will read the same input (the n character you typed), and fail again. And it will keep doing so no matter how many times you call scanf. It always amazes me that computer science educators continue to teach scanf to students, given not only this potential pitfall, but several other pitfalls as well. I wish I had a nickel for every hour that some CS student somewhere has spent struggling to get scanf to behave the way their intuition tells them it should. I'd be retired on my own private island by now. But I digress.

One way around this particular pitfall is to check if scanf failed, and if so, to purposely consume and discard all input from stdin up to and including the next newline character or EOF, whichever comes first.

First let's look at some unfixed code that causes an infinite loop if you enter a non-integer as input:

// Typing the letter 'n' and hitting <Enter> here causes an infinite loop:
int num, status;
while (1) {
  printf("Enter a number: ");
  status = scanf("%d", &num);
  if (status == 1)
    printf("OK\n");
  else
    printf("Invalid number\n");
}

The above code will (after you type n and hit <Enter>), will enter an infinite loop, and just start spewing "Invalid number" over and over. Again, this is because the n you entered never gets cleared out of the input buffer.

There are a few possible ways to get around this problem, but the consensus seems to be that the most portable and reliable way to do so is as follows:

// Fixed. No more infinite loop.
int num, status;
while (1) {
  printf("Enter a number: ");
  status = scanf("%d", &num);
  if (status == 1)
    printf("OK\n");
  else {
    printf("Invalid number\n");
    // Consume the bad input, so it doesn't keep getting re-read by scanf
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF) ;
    if (ch == EOF) break;
  }
}
Mike Holt
  • 4,054
  • 1
  • 13
  • 22
  • Good, yet somehow `while (1) {` loop should quit on `EOF`. – chux - Reinstate Monica Mar 28 '19 at 02:23
  • @chux, Good point. I only meant this code as an exercise (i.e., throwaway code) to demonstrate the concept, and I was just terminating the program with Ctrl-C. But you're right that it should probably `break` if `ch == EOF`. – Mike Holt Mar 28 '19 at 02:25
  • Actually, that's still not quite fixed, since `scanf` can return EOF. But I'll leave that as an exercise for the reader. – Mike Holt Mar 28 '19 at 02:37
0

The function scanf() will returns the number of elements read, so in this case it will return 1 every time it reads an int and 0 when it reads a char, so you just need to verify that return value. Keep in mind that after reading a character it will remain in the buffer so if you use the scanf() command again it will read the character again and repeat the error. To avoid that you need to consume the character with while(getchar() != '\n');

With that in mind I modified your code so that it works properly printing an error message if a character is introduced and asking for a new int.

for (int i = 1; i <= size; i++) {
      printf("Introduce the value #%d of the list: ", i);
      while (!scanf("%d", &list[i])) { //verifies the return of scanf
        while(getchar() != '\n'); //consumes the character in case of error
        printf("What you tried to introduce is a char\n");
        printf("please introduce the value #%d of the list: ", i);
      }
    }
ssoBAekiL
  • 635
  • 2
  • 13
  • Thank you for the explanation, but, `please introduce the value #%d of the list: ", i` is not necessary to be added on the 5th line because the program will print two times the same thing (on line 6). Anyways, I learned something new. Cheers. – Daniel Logvin Mar 28 '19 at 20:00
  • You're welcome and you're rigth, it was a mistake copying the code i will edit it now. – ssoBAekiL Mar 28 '19 at 20:12