• C

How do I validate a simple fgets() statement in C programming?

I want the fgets() in line 222 to be able to accept the inputs A, B, C, and D, with no case sensitivity. I want a, b, c and d to be acceptable too. If the user enters a number by accident I want that to trigger some sort of error handling that will tell the user that their entry is invalid. What's the simplest way to do this?

#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[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
char eventInput;



void StatusCheck(){
    printf("\nWomen in bathroom: %d \nMen in bathroom: %d\n", women_in_bathroom, men_in_bathroom);
    printf("Queue after Cycle: %d: ",cycle);
    for (int i = 0; i <= men_in_queue + women_in_queue; i++){
        if(queueContents[i] == 'M'){
            printf("Man ");
        }
        else if(queueContents[i] == 'W'){
            printf("Woman ");
        }
    }
    printf("\n");
}


void QueueReorganizer(){
    //removing the blank slots in the queue as a result of the flush
    for (int i = 0; i < men_in_queue + women_in_queue; i++){
        if(queueContents[i] == NULL && queueContents[i+1] !=NULL){
            queueContents[i] = queueContents[i+1];
            queueContents[i+1] = NULL;
            i = 0;
        }
    }
}

void QueueFlusher(){
    if(queueContents[0] == 'W'){ //if a woman is first in line upon the bathroom emptying out
        for (int i = 0; i < 10; i++){
            if(queueContents[i] == 'W'){ //replace all the female in the queue with NULLS
                queueContents[i] = NULL;
                women_in_queue--; //decrement the females-in-queue count as many times as needed until no more females remain
                women_in_bathroom++; //increment females in bathroom
            }
        }
        printf(" One or more women have entered the bathroom.");
    }
    else if(queueContents[0] == 'M'){ //if a man is first in line upon the bathroom emptying out
        for (int i = 0; i < 10; i++){
            if(queueContents[i] == 'M'){
                queueContents[i] = NULL;
                men_in_queue--;
                men_in_bathroom++;
            }
        }
        printf(" One or more men have entered the bathroom.");
    }
    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 < 10; i++){
                if(queueContents[i] == NULL){
                queueContents[i] = 'W';
                break;
                }
            }
            women_in_queue++;
        }
        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.");
            women_in_queue++;
            for (int i = 0; i <= women_in_queue + men_in_queue; i++){
                if(queueContents[i] == NULL){
                    queueContents[i] = 'W';
                    break;
                }
            }
        }
        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();
}





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 < 10; i++){
                if(queueContents[i] == NULL){
                    queueContents[i] = 'M';
                    break;
                }
            }
            men_in_queue++;
        }
        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.");
            men_in_queue++;
            for (int i = 0; i <= women_in_queue + men_in_queue; i++){
                if(queueContents[i] == NULL){
                    queueContents[i] = 'M';
                    break;
                }
            }
        }
        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();
}





void WomanLeaves()
{
    if(women_in_bathroom == 0 ) //if there are no women in the bathroom, tell the user the problem with his request
    {
        printf("Invalid choice. There are already no women in the bathroom.\n");
    }
    else{ //if there are some women in the bathroom, decrement the women by 1, and find a woman in the queue and decrement queue
        women_in_bathroom--;
        printf("A woman has left the bathroom.");
        if(women_in_bathroom == 0){
            QueueFlusher();
        }
        else if(women_in_queue > 0){ //if there are women in the queue...
            while (women_in_bathroom < 10) { //and there is space in the bathroom...
                women_in_bathroom ++; //add a woman to the bathroom
                women_in_queue --; //decrement the women-in-queue count
                for (int i = 0; i < 10; i++){ //go into the queue and remove the first woman
                    if(queueContents[i] == 'W'){
                        queueContents[i] = NULL;
                        break;
                    }
                }
                QueueReorganizer(); //remove the NULL in between the people in the queue
            }
        }
        StatusCheck();
    }
}

void ManLeaves()
{
    if(men_in_bathroom == 0 )
    {
        printf("Invalid choice. There are already no men in the bathroom.\n");
    }
    else{
        men_in_bathroom--;
        printf("A man has left the bathroom.");
        if(men_in_bathroom == 0){
            QueueFlusher();
        }
        else if(men_in_queue > 0){
            while (men_in_bathroom < 10) { //does this have to execute at least once? that would be bad
                men_in_bathroom ++;
                men_in_queue --;
                for (int i = 0; i < 10; i++){
                    if(queueContents[i] == 'M'){
                        queueContents[i] = NULL;
                        break;
                    }
                }
                QueueReorganizer();
            }
        }
        StatusCheck();
    }
}





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


    return 0;
}

//reusing i so often bad? pointer clearing?

Open in new window

shampouyaAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

arnoldCommented:
Best to test whether the ascii value of the entered data is between 65-69, the other option is to use case instead of cascading ifs..
arnoldCommented:
You need to surround fgets in a while loop as you have but instead of cycle check when the pattern is met, break out or use ......whether , that will continually notify and prompt the user for a valid selection.
Your current will cycle through 25 times
If you want 25 samples have the fget surrounded by an inner while  loop.

You can use toupper() to capitalize the imputed character.
Subrat (C++ windows/Linux)Software EngineerCommented:
fgets() accepts a string. It might be digit or char. If you want to validate digits, you can check char by char and validate the ascii value from 0-9 i.e 48-57(If I have remembered correctly(Check the ASCII table for confirmation).
If you want immediate intimation to user, you can use fgetc() inside a loop and terminate loop while feof(). In the meanwhile you can validate the inputs.
Get Certified for a Job in Cybersecurity

Want an exciting career in an emerging field? Earn your MS in Cybersecurity and get certified in ethical hacking or computer forensic investigation. WGU’s MSCSIA degree program was designed to meet the most recent U.S. Department of Homeland Security (DHS) and NSA guidelines.  

ozoCommented:
Don't use 48-57, it is not guaranteed that the execution character set is ASCII.
Better to use '0'-'9', which is guaranteed to work, and doesn't require people to remember correctly or check the ASCII table to understand what the code is doing.
shampouyaAuthor Commented:
What's the C code for validating the ascii value of fgets from '0'-'9'?
ozoCommented:
char eventInput[3];
fgets(&eventInput, 3, stdin);
if( isdigit(eventInput[0]) ){
   printf("valid digit");
}

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
arnoldCommented:
I'll just modify the section in question  218-237
please define int
    while (cycle <= 25) {
         int accepted=0; /* locally declare accepted with a 0 value. */
         while (accepted==0) {  /* run this loop until a valid character is selected below */
         
        printf("\nChoose one of the following events for cycle %d:\n", cycle);
        printf("A) woman wants to enter bathroom\nB) man wants to enter bathroom\nC) woman leaves bathroom\nD) man leaves bathroom\n");
        printf("Enter A,B,C or D here --> ");
        fgets(&eventInput, 3, stdin);
        printf("\n");
        eventinput=toupper(eventinput); /* convert whatever character is entered to upper case  tolower() is the opposit*/
/* I would have use the switch (eventinput) { case 'A': do stuff ;break; case 'B': do other stuff...... ;break; with default: action.  but your will work as well. /*
        if(eventInput == 'A'){
            WomanWantsToEnter();
            accepted=1;
        }
        else if(eventInput == 'B'){
            ManWantsToEnter();
            accepted=1;

        }
        else if(eventInput == 'C'){
            WomanLeaves();
            accepted=1;
        }
        else if(eventInput == 'D'){
            ManLeaves();
            accepted=1;
        }
        else {
                printf ("%s %c $s\n","Please note the instructions that follow. The character you have selected/entered: " ,eventinput, " is not valid!");
        }
} /* close while loop waiting for valid input */
        cycle++;
    }

Open in new window

jmcgOwnerCommented:
I hope you noticed that ozo changed the declaration of eventInput to a character array. That was a bug waiting to bite you, when it was declared as char.
arnoldCommented:
Concentrating on the questing missing the implementation. Your current fgets is seeking 3 characters including the null string \0 string terminator.
Do you want your input to react to a single key press rather than having the

Scant a character at a time might be another approach where the input will be acted upon as soon as a key is pressed.
Scanf ("%c",&eventInput); instead of fgets.
I think that's right, but will double check.
jmcgOwnerCommented:
Arnold, we've been trying to get away from scanf(%c ...) pattern since shampouya asked his earlier question: Q_28667075 Why isn't my scanf halting the execution of code in my C program?

To have the program react to single keypresses would involve setting the tty to CBREAK or RAW mode, which is starting to get a little too advanced for the stage at which shampouya is in learning C.
arnoldCommented:
Oh, I see, the fgets is set to 3. But the condition evaluates the entire string

In this case is test has to loop through the length of eventinput's 0 the input character, I think this is the suggestion and changes ozo suggested, limiting the definition to 3 and comparing the first character/entry in the string.
jmcgOwnerCommented:
Yes, I've learned over the years that Ozo is nearly always right, but sometimes a bit terse, so one may want to ask for clarification.

And on ExpertsExchange, there's always a difficult line to walk between teaching someone who is trying to learn and just doing the work for them. But you're an old hand here, 1997!!!, so I will defer to your greater experience.
arnoldCommented:
In the first few comments, provided what needs to be considered, but I think I mixed the remarks of others as though coming from the asker.

it is not always clear that a question is a progression unless a reference to the earlier question is included.
shampouyaAuthor Commented:
For Ozo's code below, what's the best way to loop that so that the code keeps asking the user for a valid entry each time the user enters a digit instead of a character?

char eventInput[3];
fgets(&eventInput, 3, stdin);
if( isdigit(eventInput[0]) ){
   printf("valid digit");
}
arnoldCommented:
forget fgets use getchar() instead.
just the code dealing with getting input
int cycle=0;
        printf("\nChoose one of the following events for cycle %2d:\n", craptest
);

while (cycle <= 25) {
         char eventInput='\0';
         int accepted=0; /* locally declare accepted with a 0 value. */
         while (accepted==0) {  /* run this loop until a valid character is selected below */

        printf("\nChoose one of the following events for cycle %2d:\n", cycle
);
        printf("A) woman wants to enter bathroom\nB) man wants to enter bathroom\nC) woman leaves bathroom\nD) man leaves bathroom\n");
        printf("Enter A,B,C or D here --> ");
/*        (char)  eventInput=fgets(&eventInput, 3, stdin); */
       eventInput=getchar();
        printf("\n");
        eventInput=toupper(eventInput); /* convert whatever character is entered
 to upper case  tolower() is the opposit*/
/* I would have use the switch (eventinput) { case 'A': do stuff ;break; case 'B
': do other stuff...... ;break; with default: action.  but your will work as wel
l. */
          if(eventInput == 'A'){
                      printf ("%s%c%s\n","The A input is ",eventInput," test");
                      accepted=1;
          }
          else if(eventInput == 'B'){
                      printf ("%s%c%s\n","The B input is ",eventInput," test");
                      accepted=1;
                }

          else if(eventInput == 'C'){
                      printf ("%s%c%s\n","The C input is ",eventInput," test");
                      accepted=1;
                }
          else if(eventInput == 'D'){
                      printf ("%s%c%s\n","The D input is ",eventInput," test");
                      accepted=1;
          }
          else {
                       printf ("%s %c %s\n","Please note the instructions that follow. The character you have selected/entered: " ,eventInput, " is not valid!");
        printf ("%s %d\n","The current cycle is: ",cycle);
          }
        printf ("%s %d\n","The current cycle is: ",cycle);
          } /* close while loop waiting for valid input */
        cycle++;
    }

printf ("%s\n","we are done.");

Open in new window

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.