Double while loop for flushing data before a switch statement - c

I need to write a script for the user to enter a score between 0 and 10, flush the bad input out, if user inputs it and then using a switch statement, tell a user what grade did he/she got.
Here is my script:
...
int main()
{
int input; // input from user
printf("Enter the number between 0 and 10 and I will tell you your grade!");
while ((input=scanf("Your input:", &input) != EOF))
{
if (input < 0 || input > 10) //input is invalid
{
printf("Sorry, invalid character data.");
while (getchar() !='\n')
{
printf("Your input must be from 0 to 10.", input);
scanf("%d", &input); //This part looks very bad for me
}
}
else
switch (input)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
printf("Your grade is F. \n");
break;
case 6:
printf("Your grade is D. \n");
break;
...
I got this far with my homework, and here are some "leftover" problems I can't fight with.
1) Whenever user submits anything after enter, it goes into infinite loop and prints Your grade is F., even when case = 6 for example.
2) I used break; at the end of each case. It looks like they don't work(?)
3) It looks like the problem in the second line in the second loop
scanf("%d", &input); //This part looks very bad for me
but then I guess the scripts accepts it as true since the else statements that includes switch begins to work, because otherwise it wouldn't print Your grade is F.

Try the following code. Have a look at what flush_stream is doing when we have invalid data...
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void flush_stream();
void flush_stream() {
char c;
do {
c = getchar();
}
while (!isdigit(c) && c != '\n');
ungetc(c, stdin);
}
int main(void) {
const char *prompt = "Input please: ";
int input; // input from user
printf("Enter the number between 0 and 10 and I will tell you your grade!\n");
while(1) {
printf("%s", prompt);
int ret = scanf("%d", &input);
if(ret == 0) {
printf("Sorry, invalid character data, your input must be from 0 to 10.\n");
flush_stream();
continue;
}
if(ret > 0) {
if (input < 0 || input > 10) {
printf("Sorry, invalid character data, your input must be from 0 to 10.\n");
flush_stream();
continue;
}
switch (input) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
printf("Your grade is F. \n");
break;
case 6:
printf("Your grade is D. \n");
break;
}
}
}
}

It seems you are using scanf and printf wrong.
To input a number:
scanf("%d", &input);
To output a number:
printf("%d\n", input);
And in you while loop, when the input is illegal, why not just continue to the next loop?
while (true) {
printf("input your grade here: ");
if (scanf("%d", &input) == EOF) {
break;
}
if (input < 0 || input > 10) {
printf("your input is illegal.\n");
continue;
}
switch (input) {
...
}
}

Related

How can I modify program to set array range from 0 to 100 in program below

I need the code below to recognize if the grades entered is below 1 or greater than 100. If it is not within the parameters, I want to let the user know and allow them to enter another grade without exiting the program or losing grades they have already entered. I don't want the program to quit until the user enters q and I want to ensure all of the valid grades entered print at that time. I have tried numerous methods and am not getting the right results. I think I probably need some other else if statement, but I haven't been able to find the right one to work. Any information you can share to get me on the right track would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char choice;
int gradeArray[100];
int grades;
int gCount=0,i;
for(gCount=0; gCount<100; gCount++)
{
//for loop to read the grades till array size
printf("******Enter Choice Selection in Parenthesis******\n Add grades(a)\n Quit(q) \n");
scanf("%c",&choice);
if(choice == 'a' || 'A')
{
//if user choice is a, then read the grade
printf( "Enter grade: ");
scanf("%d", &grades);
getchar();
gradeArray[gCount] = grades; //add the grade to array
}
if(choice == 'q') //if the user choice is q, then exit the loop
{
break;
}
}
printf("Grades are:\n");
for(i=0; i<gCount; i++)
{
printf(" %d%%\n", gradeArray[i]); //print grades
}
return 0;
}
You can do a while loop to verify the user input. With a while you'll be able to force the user to enter the right grade.
if(choice == 'A' || choice == 'a'){
printf("Enter grade:");
scanf("%d", &grades);
getchar();
while(grade < 1 || grade > 100){
printf("You entered a wrong number\n");
printf("Enter a grade between 1 and 100: ");
scanf("%d", &grades);
getchar();
}
gradeArray[gCount] = grades;
}
your solution is almost aligned with what you had in mind. Here is how you can do it differently.
#include <stdio.h>
int main()
{
char choice;
int arraySize = 100; //change this to any number you wish
int gradeScore = 0;
int gradeArray[arraySize];
int gCount = 0;
int showCount = 0;
while(choice != 'q')
{
//to ask for user's input every time
printf("What do you want to do? Enter\n");
printf("'a' to add grades\n");
printf("'q' to quit\n");
scanf(" %c", &choice); //space is entered to ensure the compiler does not read whitespaces
//your implementation should check for user input before proceeding
if(choice != 'a')
{
//in this condition, 'q' is technically an incorrect input but your design states that 'q' is for quitting
//thus, do not alert the user here if 'q' is entered
if(choice != 'q')
{
//a condition to warn the user for incorrect input
printf("Incorrect input. Please enter only 'a' or 'q'\n");
}
}
else if(choice == 'a')
{
printf("Enter grade: \n");
scanf(" %d", &gradeScore);
//to check for user input if the grades entered are less than 1 or more than 100
if(gradeScore < 1 || gradeScore >100)
{
//print a warning message
printf("The grade you entered is invalid. Please enter a grade from 1 - 100\n");
}
//for all correct inputs, store them in an array
else
{
printf("Grade entered\n");
gradeArray[gCount] = gradeScore;
gCount++;
}
}
}
//prints grade when 'q' is entered
if(choice == 'q')
{
printf("Grades are: \n");
for(showCount = 0; showCount < gCount ; showCount++)
{
printf("%d\n", gradeArray[showCount]);
}
}
}
To sum up the important parts, be sure to check for the user grade input to be in range of 1 - 100. Store the grade in the array if it is within range and be sure to increase the array counter, otherwise it will always store it in gradeArray[0] for the subsequent grades. Hope this helps
Use a do-while loop to keep the program looping back to get another choice unless a valid choice has been entered. Use fgetc to read a single character - fewer problems. Only print grades if at least one grade has been entered.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char choice;
int gradeArray[100];
int grades;
int gCount=0,i;
for(gCount=0; gCount<100; gCount++)
{
//for loop to read the grades till array size
printf("******Enter Choice Selection******\n Add grades(a)\n Quit(q) \n");
do
{
choice = fgetc(stdin);
if(choice == 'a' || choice == 'A')
{
//if user choice is a, then read the grade
printf( "Enter grade: ");
scanf("%d", &grades);
getchar();
gradeArray[gCount] = grades; //add the grade to array
}
else if(choice != 'q')
printf("Invalid choice - try again\n");
} while (choice != 'a' && choice != 'A' && choice != 'q');
if(choice == 'q') //if the user choice is q, then exit the loop
break;
}
if(gCount > 0)
{
printf("Grades are:\n");
for(i=0; i<gCount; i++)
printf(" %d%%\n", gradeArray[i]); //print grades
}
return 0;
}

getchar() not waiting for input and jumping directly to next line

getchar() not waiting for input and jumping directly to next line. There is some mismatch between scanf and getchar I think but not able to make out what is it exactly.
#include<stdio.h>
#include<ctype.h>
int main()
{
char ch;
int n1,n2;
printf("Enter the operation of your choice\n");
printf("a. add\ts. subtact\nm. multiply\td. divide\nq. quit\n");
while((ch=getchar())!='q')
{
printf("\nEnter 1st number:\n");
if(scanf("%d",&n1)!=1)
{
printf("Please enter an integer value.\n");
continue;
}
printf("Enter 2nd number:\n");
if(scanf("%d",&n2)!=1)
{
printf("Please enter an integer value.\n");
continue;
}
switch(ch)
{
case 'a':
{ printf(" %d + %d = %d\n",n1,n2,n1+n2);
break;
}
case 's':
{
printf(" %d - %d = %d\n",n1,n2,n1-n2);
break;
}
case 'm':
{
printf(" %d * %d = %d\n",n1,n2,n1*n2);
break;
}
case 'd':
{
if(n2!=0)
{
printf(" %d / %d = %f\n",n1,n2,(float)n1/n2);
break;
}
else
{
printf("Enter a non-zero number for n2\n");
continue;
}
break;
}
}
printf("Enter the operation of your choice\n");
printf("a. add\ts. subtact\nm. multiply\td. divide\nq. quit\n");
}
printf("Bye.");
}
OUTPUT:
Enter the operation of your choice
a. add s. subtact
m. multiply d. divide
q. quit
a
Enter 1st number:
50
Enter 2nd number:
25
50 + 25 = 75
Enter the operation of your choice
a. add s. subtact
m. multiply d. divide
q. quit
Enter 1st number:
your getchar reads the newline and other spaces you enter when you give the value read by the scanf, you need to bypass these spaces
just replace
while((ch=getchar())!='q')
by
while ((scanf(" %c", &ch) == 1) && (ch != 'q'))
notice the space before '%', this is thank to it the spaces including newline are bypassed

Repeat the Program Prompt

The current problem is with the Evaluate another interval (Y/N)? prompt. Let's say I run the program 4 times; in order to end it, it requires me to type N 4 times.
int main() {
int trap, test;
double low, hi;
char repeat, c;
//Gather End Points
do {
printf("Enter endpoints of interval to be integrated (low hi): ");
test = scanf("%lf %lf", &low, &hi);
if (test != 2) {
printf("Error: Improperly formatted input\n");
while((c = getchar()) != '\n' && c != EOF); //Discard extra characters
} else
if (low > hi)
printf("Error: low must be < hi\n");
} while ((test != 2 || low > hi));
//Gather amount of triangles
do {
printf("Enter number of trapezoids to be used: ");
test = scanf("%d", &trap);
if (test != 1) {
printf("Error: Improperly formated input\n");
while((c = getchar()) != '\n' && c != EOF); //Discard extra characters
} else
if (trap < 1)
printf("Error: numT must be >= 1\n");
} while ((trap < 1 || test != 1));
//Output integrate
printf("Using %d trapezoids, integral between %lf and %lf is %lf",
trap, low, hi, integrate(low, hi, trap));
//Prompt user for another time
while (1) {
printf("\nEvaluate another interval (Y/N)? ");
scanf(" %c", &repeat);
switch (repeat) {
case 'Y':
main();
case 'y':
main();
case 'N':
return 0;
case 'n':
return 0;
default:
printf("Error: must enter Y or N");
}
}
return 0;
}
I expect it so that no matter what run of the program I'm on it will close when I type one N.
There are many ways to achieve what you want but calling main recursively is not a good idea.
A pretty simple way to change your program is to add an additional while(1) level. Something like:
int main(void)
{
char repeat;
while(1){ // Outer while to keep the program running
printf("running program\n");
// Put your program here
printf("program done\n");
repeat = '?';
while(repeat != 'y' && repeat != 'Y'){ // Repeat until input is 'Y' or 'y'
printf("\nEvaluate another interval (Y/N)? ");
scanf(" %c", &repeat);
switch (repeat){
case 'Y':
case 'y':
break;
case 'N':
case 'n':
return 0; // Stop if input is 'n' or 'N'
default:
printf("Error: must enter Y or N");
}
}
}
return 0; // This will never be reached
}
Another way (a simpler way, IMO) is to put the code where you ask the user into a function that you call from main. Like:
int continueProg()
{
char repeat = '?';
while(1){
printf("\nEvaluate another interval (Y/N)? ");
scanf(" %c", &repeat);
switch (repeat){
case 'Y':
case 'y':
return 1;;
case 'N':
case 'n':
return 0;
default:
printf("Error: must enter Y or N");
}
}
}
int main(void)
{
do {
printf("running program\n");
// Put your program here
printf("program done\n");
} while(continueProg());
return 0;
}
BTW: Take a look at getchar instead of using scanf
There are multiple problems in your program:
You test the return value of scanf() when reading the user's answer to the prompts, and you clear the pending input correctly, but you do not handle the potential end of file, leading to endless loops.
c must be defined as int to accommodate for all values returned by getchar(): 256 values of type unsigned char and the special value EOF.
You can main() recursively to repeat the program's action requiring multiple N answers. You should instead add an outer loop and exit from it upon a N answer or an end of file condition.
Here is a modified version:
#include <stdio.h>
double integrate(double low, double hi, int trap) {
...
}
int flush_line(void) {
// Consume the pending input and return `'\n`` or `EOF`
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
int main() {
// Main program loop
for (;;) {
int trap, test;
double low, hi;
char repeat;
//Gather End Points
for (;;) {
printf("Enter endpoints of interval to be integrated (low hi): ");
test = scanf("%lf %lf", &low, &hi);
if (test == EOF)
return 1;
if (test != 2) {
printf("Error: Improperly formatted input\n");
if (flush_line() == EOF)
return 1;
continue; // ask again
}
if (low > hi) {
printf("Error: low must be < hi\n");
continue;
}
break; // input is valid
}
//Gather amount of triangles
for (;;) {
printf("Enter number of trapezoids to be used: ");
test = scanf("%d", &trap);
if (test == EOF)
return 1;
if (test != 1) {
printf("Error: Improperly formated input\n");
if (flush_line() == EOF)
return 1;
continue;
}
if (trap < 1) {
printf("Error: numT must be >= 1\n");
continue;
}
break;
}
//Output integrate
printf("Using %d trapezoids, integral between %lf and %lf is %lf\n",
trap, low, hi, integrate(low, hi, trap));
//Prompt user for another time
for (;;) {
printf("\nEvaluate another interval (Y/N)? ");
if (scanf(" %c", &repeat) != 1)
return 1; // unexpected end of file
switch (repeat) {
case 'Y':
case 'y':
break;
case 'N':
case 'n':
return 0;
default:
printf("Error: must enter Y or N\n");
if (flush_line() == EOF)
return 1;
continue;
}
break;
}
}
}

Eliminating the <ENTER> required to continue the loop

In the code below, if the user enters 1 or 2, everything proceeds smoothly.
But if I enter anything else besides 1 or 2, the loop runs, but an additional is required to continue the loop.
How do I eliminate the need for this ?
#include <stdio.h>
#include <ctype.h>
#include <math.h>
void clearKeyboardBuffer() {
int ch;
while ((ch = getchar() != '\n') && (ch != EOF));
}
void entry1(){
char chArr[BUFSIZ];
char choice, ch;
int choiceint, rating;
do{
printf("1.\tZoo\n2.\tMall\n3.\tExit\n\n");
printf("Choose a place by entering its numerical value: ");
fgets(chArr,sizeof(chArr),stdin);
sscanf(chArr, " %c", &choice);
// converts scanned char to int
choiceint = choice - '0';
if(!isdigit(choice) || choiceint > 3){
printf("You did not enter an accepted digit.\n");
}
else if(choiceint != 3){
switch(choiceint){
case 1:
printf("You chose the Zoo.\n");
printf("your rating : ");
scanf("%d", &rating);
break;
case 2:
printf("You chose the Mall.\n");
printf("your rating : ");
scanf("%d", &rating);
break;
}// end of switch
}// end of else if
else{
}// end of else
clearKeyboardBuffer();
}// end of do
while(choiceint !=3);
}
just move the call to clearKeyboardBuffer() right after //end of switch as in
char chArr[BUFSIZ];
char choice, ch;
int choiceint, rating;
do{
printf("1.\tZoo\n2.\tMall\n3.\tExit\n\n");
printf("Choose a place by entering its numerical value: ");
fgets(chArr,sizeof(chArr),stdin);
sscanf(chArr, " %c", &choice);
// converts scanned char to int
choiceint = choice - '0';
if(!isdigit(choice) || choiceint > 3){
printf("You did not enter an accepted digit.\n");
}
else if(choiceint != 3){
switch(choiceint){
case 1:
printf("You chose the Zoo.\n");
printf("your rating : ");
scanf("%d", &rating);
break;
case 2:
printf("You chose the Mall.\n");
printf("your rating : ");
scanf("%d", &rating);
break;
}// end of switch
clearKeyboardBuffer();
}// end of else if
else{
}// end of else
}// end of do
while(choiceint !=3);
You've got a problem with your if else loop. If the choice is not a digit or >3 you want to re-ask the user
#include <stdio.h>
#include <ctype.h>
#include <math.h>
void clearKeyboardBuffer() {
int ch;
while ((ch = getchar() != '\n') && (ch != EOF));
}
void entry1(){
char chArr[BUFSIZ];
char choice, ch;
int choiceint, rating;
do{
printf("1.\tZoo\n2.\tMall\n3.\tExit\n\n");
printf("Choose a place by entering its numerical value: ");
fgets(chArr,sizeof(chArr),stdin);
sscanf(chArr, " %c", &choice);
// converts scanned char to int
choiceint = choice - '0';
if(!isdigit(choice) || choiceint < 1 || choiceint > 3){
printf("You did not enter an accepted digit.\n");
}
// If 0 > choice > 3
else {
switch(choiceint){
case 1:
printf("You chose the Zoo.\n");
printf("your rating : ");
scanf("%d", &rating);
break;
case 2:
printf("You chose the Mall.\n");
printf("your rating : ");
scanf("%d", &rating);
break;
case 3:
break;
default:
break;
}// end of switch
}// end of else
clearKeyboardBuffer();
}// end of do
while(choiceint !=3);
}

While,switch, case statement

I'm using a while, switch, case statement for my menu and when it runs it keeps saying enter choice, I know while(1) creates an infinite loop but is there a way to avoid this?
while(1)
{
printf("\nEnter Choice \n");
scanf("%d",&i);
switch(i)
{
case 1:
{
printf("Enter value to add to beginning: ");
scanf("%c",&value);
begin(value);
display();
break;
}
case 2:
{
printf("Enter value to add last: ");
scanf("%c",&value);
end(value);
display();
break;
}
case 3:
{
printf("Value to enter before\n");
scanf("%c",&loc);
printf("Enter value to add before\n");
scanf("%c",&value);
before(value,loc);
display();
break;
}
case 4 :
{
display();
break;
}
}
}
Any help would be appreciated.
While(1) is ok. But you have to have some conditions to finish the loop. Like :
while(1){
.........
if(i == 0)
break;
............
}
Add a space at the beginning of every "%d" and "%c",because scanf always leaves a newline characters in buffer:
"%d"->" %d"
"%c"->" %c"
Alternative solution,
int i = !SOME_VALUE;
while(i != SOME_VALUE)
{
printf("\n\nEnter Choice ");
scanf("%d",&i);
switch(i)
{
case SOME_VALUE: break;
.
.
.
// the rest of the switch cases
}
}
SOME_VALUE is any integer number notify to stop loop.
Alternatively, you may want to put a condition in the loop that relates to the input, e.g.
do
{
printf("\n\nEnter Choice ");
scanf("%d",&i);
// the rest of the switch is after this
} while (i != SOME_VALUE);
Note the use of the do loop, which tests the condition at the end, after a value has been read into i.
I would probably write a function that can be called in the loop:
while ((i = prompt_for("Enter choice")) != EOF)
{
switch (i)
{
case ...
}
}
And the prompt_for() function might be:
int prompt_for(const char *prompt)
{
int choice;
printf("%s: ", prompt);
if (scanf("%d", &choice) != 1)
return EOF;
// Other validation? Non-negative? Is zero allowed? Retries?
return choice;
}
You can also find relevant discussion at:
scanf() validation.
What is the reason for error while returning a structure in this C program?
Common macro to read input data and check its validity

Resources