-1

I have a recursive function that uses printf() and scanf() to deal with user input. If the user accidentally presses a wrong key (not 'y'), it loops back. However, if the user enters multiple characters, the function asks the user for input multiple times at once. The printf() lines are repeated as many times as characters there are in the input.

Why does having excessive characters in the terminal buffer result in this type of behavior rather than the whole thing crashing or the terminal just ignoring the following characters?

int testDetectorWhite(){
    char userConfirmation;
    
    printf("Please place a WHITE disk directly below the detector\n");
    printf("Press 'y' when ready:\n");
    scanf("%c", &userConfirmation);
    printf("\n");
    
    if(userConfirmation != 'y'){
        testDetectorWhite();
    }
    
    //more code
}

I tried rewriting the code so that the recursive if() is substituted for a while() loop, like the following:

while(userConfirmation != 'y') {
        printf("Please place a WHITE disk directly below the detector\n");
    printf("Press 'y' when ready:\n");
    scanf("%c", &userConfirmation);
}

However, I still got the exact same bug.

I tried solving the issue by making userConfirmation a string, which solved the issue of multiple printf() functions running but resulted in more issues that are outside the scope of my question.

  • Are you aware of the concept of [buffering](https://stackoverflow.com/questions/23298717/what-is-meant-by-stream-buffering)? – Bob__ May 10 '23 at 08:57
  • I would suggest reading up on 'scanf', it is quite simple to google this. Recursion has its usages but the while loop is a better approach. I would also try single stepping through your source line by line as you are reading it, this will allow you to refactor and more importantly, understand the flow of your code. – Neil May 10 '23 at 09:02
  • 3
    When you press `y` or `n` and the Return key you are actually entering two characters, e.g. `y` and `\n`. Use format `" %c"`. Read your C book or teaching material about strings in C. `char userConfirmation[] = "";` is an array of a size matching the initialization which is 1 `char` in this case. It can only hold an empty string or a single character that is not a valid string because there is no space for the terminating `'\0'` after something else. The `scanf` is likely to write past the end of the array. You cannot compare strings with `=` or `!=`, you need functions like `strcpy`. – Bodo May 10 '23 at 09:15
  • 1
    see also https://stackoverflow.com/q/5240789/10622916 – Bodo May 10 '23 at 09:19
  • because every time you call scanf if reads one character from the terminal buffer? – user253751 May 10 '23 at 09:35

1 Answers1

0

You have two problems, both related to the scanf function and its many deficiencies.

  1. To read a single non-whitespace character, as you're trying to do here, the format "%c" does not work as you expect. You need to use " %c", with an extra space in there. See scanf() leaves the newline character in the buffer .
  2. If you want to write code that deals gracefully with a user's mistakes, asking the user to try again if that happens, scanf is not a good choice. The problem, in general, is that "bad" input tends to stay on the input stream, unread, meaning that you may have to try to "flush" it somehow. See also How to properly flush stdin in fgets loop and Using fflush(stdin) .

In general, if you want the user to type input of the form A, but you're afraid the user might type input of the form B instead, you have to let the user type, and you have to read in, that input of the form B. You can't just write code that tries to read input of the form A, hoping that input of the form B will be magically discarded. For example, and as you've seen here, if you write code that reads single characters using %c in a loop, and the user wrongly types three characters, your loop will run three times.

So in the general case, if you want to handle the case where the user might wrongly type input in any random form B that wasn't what you wanted, you end up having to read the user's input as a string, using scanf %s, or maybe fgets. Then you have to detect whether the input was in the form you wanted ("form A"). Then you may have to convert the input into the form you wanted (like, converting from a string to a single character, or from a string to an integer). But if you detect that the input wasn't what you wanted, you'll have at least read (and discarded) it all, so that after you print your "please try again" prompt, you and the user will be starting from a blank slate.

This is, admittedly, more work to do, and somewhat of a nuisance. If you're just starting out, I recommend concentrating on correct input, that is, writing code that quietly assumes the user never types anything wrong. Obviously it's nice from a human factors standpoint to detect bad input, to print a nice prompt asking the user to try again, but it's surprisingly difficult to code that correctly! It's a problem you might want to defer for a few weeks, while you learn more abut the other C tools you'd need in order to solve it.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103