0

I'm currently learning C and C++ on my own. In this little "program practice" I ask the user to enter either 'i' or 'd' to know whether they want to work with integers or decimal (float) numbers. I have a while loop that makes sure the user enter 'i' or 'd' by telling them if they entered the wrong char. For some reason, the prompt inside the while loop prints two times before going to the getchar(). I'm having a bit of hard time understanding what's happening under the hood in this situation. Any help is super appreciated. I'm using Xcode (don't know if it's relevant).

#include <stdio.h>

int main()
{

  char action;

  printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n"); 

  scanf("%c", &action); 

   while (action != 'i' || action != 'd')
   {
     printf("You didn't entered the right command. Please try again (i/d)\n");
     action = getchar()
   }
 }

So what I'm getting as an output is this:

You didn't entered the right command. Please try again (i/d)
You didn't entered the right command. Please try again (i/d)
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
Confiture
  • 11
  • 1
  • 2

3 Answers3

4

What is happening is that when you enter a character and hit a return, you are actually entering two characters - the character and the return character ('\n'). The loop executes once for each character. Which is why you see it go through twice.

The trick is to filter out the return character explicitly, like so:

#include <stdio.h>

int main()
{

  char action;

  printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n"); 

  scanf("%c", &action); 

   while (action != 'i' || action != 'd')
   {
     if (action != '\n')
     {
       printf("You didn't entered the right command. Please try again (i/d)\n");
     }
     action = getchar();
   }
}
Ziffusion
  • 8,779
  • 4
  • 29
  • 57
  • 2
    Similar comments apply here as to the other answer. You could fix it 'better' by using `" %c"` (with a space before the `%c`) for the format string. That skips any leading white space on the first line of input. It might be better to use `scanf()` a second time. You should also always check that `scanf()` reports success; if someone feeds this code input from `/dev/null`, the loop is going to run for a very long time, for example. Ditto `getchar()`. – Jonathan Leffler Jul 26 '13 at 23:47
  • HEY ! Thanks a bunch for taking the time. I'll definitely need to read a whole lot more about it. – Confiture Jul 27 '13 at 07:53
  • If you think this answer helped you, you may want "accept" it as the right answer by clicking the check mark on the left. – Ziffusion Jul 27 '13 at 16:30
1

As correctly diagnosed by Ziffusion in his answer, you get the double prompt because you get the newline after the user's incorrect input as a separate character, and that too is neither i nor d.

Here is a rewrite with some improvements:

#include <stdio.h>

int main(void)
{
    char action = '\0';

    printf("Please enter 'i' to work with integers or 'd' to work with decimals: "); 

    while (scanf(" %c", &action) == 1 && action != 'i' && action != 'd')
        printf("You didn't enter the right command. Please try again (i/d): ");

    printf("Action selected: %d\n", action);
}

What's changed?

  1. The prompt doesn't end with a newline, so the user's response appears immediately after it. Standard I/O normally synchronizes standard output and standard input so that the prompt will be flushed, despite not ending with a newline. If the prompt doesn't appear, you can add a fflush(stdout); or fflush(0); after each of the prompting printf() statements.

  2. The result of scanf() is checked to deal with EOF.

  3. The format of scanf() includes a leading space. This will skip white space before the character that's returned, so you get a non-blank, non-newline character.

  4. The original condition action != 'i' || action != 'd' is always true; you need the && instead.

  5. Nitpick: improve grammar of error message.

Note that after the loop, action might not be either i or d if the user triggered EOF (typed Control-D or equivalent). If you get EOF (for example, the user ran the program with standard input from /dev/null), you would not have a deterministic value in action except for the initialization to '\0'.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

Here I fixed you code:

#include <stdio.h>

    int main()
    {

      char action;

      printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n");


      scanf("%c", &action);
       while (action != 'i' && action != 'd') // here the loop will stop if action is 'i' or 'd'
       {
         printf("You didn't entered the right command. Please try again (i/d)\n");
         scanf("\n%c", &action);// here to deal with '\n'
       }
     }
Lidong Guo
  • 2,817
  • 2
  • 19
  • 31
  • 1
    You could fix it 'better' by using `" %c"` (with a space before the `%c`) for the format string. That skips any leading white space, and in the second `scanf()` skips past the newline that is waiting to be read. You should also always check that `scanf()` reports success; if someone feeds this code input from `/dev/null`, the loop is going to run for a very long time, for example. – Jonathan Leffler Jul 26 '13 at 23:45
  • @JonathanLeffler Yeah,you are right. Also "\n%c" can work as good as " %c". – Lidong Guo Jul 26 '13 at 23:54
  • @LidongGuo at Jonathan Leffler Jesus do I learn little tricks here and there when I post questions on here. – Confiture Jul 27 '13 at 07:55
  • @Confiture What actual you meaning about? I am not understand.I am bad in English – Lidong Guo Jul 27 '13 at 08:00
  • @Confiture My auwser make you upset? – Lidong Guo Jul 27 '13 at 08:02
  • Noooo haha the contrary. I said that I learn a lot when posting here. I'm learning a lot of little good tricks. – Confiture Jul 27 '13 at 08:30