Link to home
Start Free TrialLog in
Avatar of shampouya
shampouya

asked on

Why isn't my scanf halting the execution of code in my C program?

I wrote the program below and started debugging. When I run the code, I expect the user to be prompted to enter an input once, but after the first prompt, there is an extra and redundant prompt in the subsequent cycles. It seems like scanf is not stopping the code from executing in order to give the user a change to enter an input. Why is that? How can I make sure that the user is asked to enter a value only once per cycle?

#include<stdio.h>
#include<stdlib.h>


int men_in_bathroom=0;
int women_in_bathroom=0;
int bathroom_capacity = 10;
int men_in_queue=0;
int women_in_queue=0;
int queue_capacity = 10;
int cycle=1;
char queueContents[1];
char eventInput;



void StatusCheck(){
    printf("\nStatus of Bathroom:\nCycle: %d  Women: %d  Men: %d\n",cycle, women_in_bathroom, men_in_bathroom);
    printf("Queue (last to first): ");
    for (int i = 0; i < men_in_queue + women_in_queue; i++){
        printf("%c ", queueContents[i]);
    }
    printf("\n");
}

void QueueReorganizer(){
    
}

void WomanWantsToEnter()
{
    if (women_in_bathroom + men_in_bathroom >= bathroom_capacity){ //if the bathroom is at full capacity
        if(men_in_queue + women_in_queue < queue_capacity){ //if the queue can accomodate more people
            printf("The bathroom is full. One woman has been added to the queue.");
            for (int i = 0; i < women_in_bathroom; i++){
                if(queueContents[i] == NULL){
                queueContents[i] = 'W';
                women_in_queue++;
                break;
                }
            }
            StatusCheck();
        }
        else{ //if the queue is at full capacity
            printf("Sorry, the bathroom and the queue are both full. No one can be added at this time.");
        }
    }
    else if(men_in_bathroom != 0){ //if the bathroom can accomodate more people but there are men currently inside the bathroom
        if(men_in_queue + women_in_queue < queue_capacity){ //if the queue can accomodate more people
            printf("Men are currently inside the bathroom. One woman has been added to the queue.");
        }
        else{ //if the queue is at full capacity
            printf("Men are currently inside the bathroom, and the queue is full. Cannot accomodate any women at the moment.");
        }
    }
    else if(men_in_bathroom == 0){ //if the bathroom can accomodate more people and there are no men currently inside the bathroom
        printf("A woman has entered the bathroom");
        women_in_bathroom++;
        StatusCheck();
        cycle++;
    }
}





void ManWantsToEnter()
{
    if (women_in_bathroom + men_in_bathroom >= bathroom_capacity){ //if the bathroom is at full capacity
        if(men_in_queue + women_in_queue < queue_capacity){ //if the queue can accomodate more people
            printf("The bathroom is full. One man has been added to the queue.");
            for (int i = 0; i < women_in_bathroom; i++){
                if(queueContents[i] == NULL){
                    queueContents[i] = 'M';
                    men_in_queue++;
                    break;
                }
            }
            StatusCheck();
        }
        else{ //if the queue is at full capacity
            printf("Sorry, the bathroom and the queue are both full. No one can be added at this time.");
        }
    }
    else if(women_in_bathroom != 0){ //if the bathroom can accomodate more people but there are women currently inside the bathroom
        if(men_in_queue + women_in_queue < queue_capacity){ //if the queue can accomodate more people
            printf("Women are currently inside the bathroom. One man has been added to the queue.");
        }
        else{ //if the queue is at full capacity
            printf("Women are currently inside the bathroom, and the queue is full. Cannot accomodate any men at the moment.");
        }
    }
    else if(women_in_bathroom == 0){ //if the bathroom can accomodate more people and there are no women currently inside the bathroom
        printf("A man has entered the bathroom");
        men_in_bathroom++;
        StatusCheck();
        cycle++;
    }
}





void WomanLeaves()
{
    if(women_in_bathroom == 0 )
    {
        printf("Invalid choice. There are already no women in the bathroom.");
    }
    else{
        women_in_bathroom--;
        for (int i = 10; i > 0; i--){
            if(queueContents[i] == 'W'){
                queueContents[i] = NULL;
                break;
            }
        }
        QueueReorganizer();
        StatusCheck();
        cycle++;
    }
}

void ManLeaves()
{
    if(men_in_bathroom == 0 )
    {
        printf("Invalid choice. There are already no women in the bathroom.");
    }
    else{
        men_in_bathroom--;
        for (int i = 10; i > 0; i--){
            if(queueContents[i] == 'M'){
                queueContents[i] = NULL;
                break;
            }
        }
        QueueReorganizer();
        StatusCheck();
        cycle++;
    }
}




int main() {
    
    while (cycle <= 20) {
        printf("\nChoose one of the following events for cycle %d:\n", cycle);
        printf("A) woman wants to enter\nB) man wants to enter\nC) woman leaves\nD) man leaves\n");
        printf("Enter A,B,C or D here --> ");
        scanf("%c", &eventInput);
        
        if(eventInput == 'A'){
            WomanWantsToEnter();
        }
        else if(eventInput == 'B'){
            ManWantsToEnter();
        }
        else if(eventInput == 'C'){
            WomanLeaves();
        }
        else if(eventInput == 'D'){
            ManLeaves();
        }
        cycle++;
    }
        

    return 0;
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Mark Bullock
Mark Bullock
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The problem is that %c only reads the first char, but because you need to hit the return key to get scanf to process the line you also end up with line feed characters in the buffer, which are subsequently process. Expert jmcg has alluded to this already.

You can (sort of) fix this by placing the following line after your scanf:

fseek(stdin, 0L, SEEK_END);

Open in new window


This basically seeks forward through the stdin file stream until it hits EOF, which is the same as saying that it has skipped through all the unwanted characters. It's a bit of a work around rather than a solution because the problem here is that scanf is just a wholly unsafe function to use. In fact the C programming language doesn't provide any nice standard way of getting clean user input and you nearly always have to resort to using platform specific functions to do things properly.

Meanwhile, I note you are using lots of if/then/else constructs for your input. You realise you can "switch" on a char, right?

switch (eventInput)
{
   case 'A':
      // do stuff for case A
      break;

   case 'B':
      // do stuff for case B
      break;

   case 'C':
      // do stuff for case C
      break;

   case 'D':
      // do stuff for case D
      break;

   default:
      // do stuff for default case (error/quit?)
      break;
}

Open in new window

Why isn't my scanf halting the execution of code
you may consider to using the following code instead of scanf call

       
while ((eventInput = getch()) != -1)
        {
            if (!strchr("ABCDQabcdq", eventInput))
            {
                continue;
            }
            eventInput = toupper(eventInput);
            printf("%c\n", eventInput);
            break;
        }

Open in new window


the getch gets one character from stdin but no echo. that allows to ignore invalid input and also to convert to upper case.
(note, i added also Q and q to the valid characters what allows the user to quit).

i added an else branch to  handle the 'Q':

else if (eventInput == 'D') {
       ...
}
else {
       break;   // break from while loop
}

Open in new window


note, the 'break' wouldn't work if you have changed to switch-case control as evilrix suggested since the break would end the case but not the loop. you would need to break the loop by making the loop condition wrong, for example by setting the 'cycle' counter to maximum.

case 'Q':
       cycle = 99; 
       break;
}

Open in new window


if the getch was not declared yet, you may include conio.h and ctype.h. the latter also provides a prototype of the toupper function. strchr is used to check whether the input is valid and is available thru <string.h>.

for windows platform you would either use _getch instead of getch or add

#ifdef WIN32
#define getch _getch
#endif

Open in new window


somewhere above main function.

one additional remark: your program currently compiles with c++ compiler but not with an ansi c compiler. that is due to for statements like 'for (int i = 0; ....' where you define variable i in the middle of a code block. in ansi c all variables must be defined at top of a block.

Sara
i dectected a few minor bugs:

if you test your code you will see that cycle was incremented twice for most cases. remove the cycle++ in the main function or (alternatively) in all the handler functions.

some printouts where stating woman where man is required.

Sara
Just note that the getch function isn't part of the C standard.