I realised that if the input is a word starting with 'y' or 'n', it will escape the loop. How can I restrict the loop such that it will continue looping unless the input is a single character?
do
{
printf("Do you want to try again? (Y/N): ");
fflush(stdin);
scanf("%c", &repeat);
repeat = toupper(repeat);
if (repeat != 'Y' && repeat != 'N')
printf("Invalid answer. Please enter 'Y' or 'N'.\n\n");
} while (repeat != 'N' && repeat != 'Y');
like this:
#include <stdio.h>
#include <ctype.h>
int main(void){
char repeat[3] = {0};//3 : one character + one character + NUL
do{
printf("Do you want to try again? (Y/N): ");fflush(stdout);
if(EOF==scanf("%2s", repeat)){ *repeat = 'N'; break; }
*repeat = toupper(*repeat);
if (repeat[1] || *repeat != 'Y' && *repeat != 'N'){//repeat[1] != '\0'..
printf("Invalid answer. Please enter 'Y' or 'N'.\n\n");
scanf("%*[^\n]");scanf("%*c");//clear upto newline
*repeat = 0;
}
} while (*repeat != 'N' && *repeat != 'Y');
puts("Bye!");//try agein or see ya, bye
return 0;
}
First fflush(stdin); does not make sense except in Microsoft's world.
Then, the scanf family function returns a value which is the number of input token successfully decoded and that return value should always be controlled. And %c should be used with caution because it can return a blank character (space or newline) remaining in buffer while %s only return printable characters. With those remarks you code could become:
repeat = '\0';
do
{
char dummy[2], inp[2];
printf("Do you want to try again? (Y/N): ");
// fflush(stdin);
if (1 == scanf("%1s%1s", inp,dummy) repeat = toupper(inp[0]);
if (repeat != 'Y' && repeat != 'N')
printf("Invalid answer. Please enter 'Y' or 'N'.\n\n");
} while (repeat != 'N' && repeat != 'Y');
Alternatively to using scanf() one can use fgets() to read a line and then do the parsing one self:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char repeat = '\0';
do
{
int input_valid = 0; /* Be pessimistic. */
char line[3] = {0};
puts("Do you want to try again? (Y/N):");
do /* On-time loop, to break out on parsing error. */
{
if (NULL == fgets(line, sizeof line, stdin))
{
break; /* Either fgets() failed or EOF was read. Start over ... */
}
if (line[1] != '\0' && line[1] != '\n')
{
break; /* There was more then one character read. Start over ... */
}
line[0] = toupper(line[0]);
if (line[0] != 'Y' && line[0] != 'N')
{
break; /* Something else but Y or N was read. Start over ... */
}
input_valid = 1;
} while (0);
if (input_valid == 0)
{
int c;
do /* Flush rest of input. if any. */
{
c = getc(stdin);
} while (EOF != c && '\n' != c);
fprintf(stderr, "Invalid answer. Please enter 'Y' or 'N'.\n\n");
}
else
{
repeat = line[0];
}
} while ('\0' == repeat);
printf("The user entered: '%c'\n", repeat); /* Will only print either Y or N. */
return EXIT_SUCCESS;
}
Related
I have this program that I finally finished however I am trying to get it after finishing once to prompt the user "Do you wish to run again? Yes(Y), No(N)". But I also want it to ask for s2 again, and the ch again as well. Keeping s1 to be the same random string if that makes sense.
This is my code:
#include <stdio.h>
#include <stdlib.h>
void s1(char *random);
void s2(char *s2_input, int index);
void strfilter(char *random, char *s2_input, char replacement);
int main()
{
char run = 'Y';
while(run != 'N')
{
int s1_index = 41;
char s1_random[s1_index];
s1(s1_random);
printf("\ns1 = ");
puts(s1_random);
printf("s2 = ");
int s2_index = 21;
char s2_input[s2_index];
s2(s2_input, s2_index);
if(s2_input[1] == '\0')
{
printf("size too small");
exit(0);
}
printf("ch = ");
char replacement = getchar();
printf("\n");
int filter_index = 41;
strfilter(s1_random, s2_input, replacement);
printf("\ns1 filtered = ");
puts(s1_random);
printf("Do you wish to run again? Yes(Y), No(N) ");
scanf("%c", &run);
}
}
void s1(char *random)
{
int limit = 0;
char characters;
while((characters = (('A' + (rand() % 26))))) /* random generatro */
{
if(limit == 41)
{
*(random + 41 - 1) = '\0';
break;
}
*(random + limit) = characters;
limit++;
}
}
void s2(char *s2_input, int index)
{
char array[21] = "123456789012345678901"; /* populated array to make sure no random memory is made */
char input;
int count = 0;
int check = 0;
while((input = getchar() ))
{
if(input == '\n')
{
*(s2_input + count) = '\0';
break;
}
else if(input < 65 || input > 90)
{
printf("invalid input");
exit(0);
}
*(s2_input + count) = input;
count++;
}
index = count;
}
void strfilter(char *random, char *s2_input, char replacement) /* replacement function */
{
while(*s2_input)
{
char *temp = random;
while(*temp)
{
if(*temp == *s2_input)
*temp = replacement;
temp++;
}
s2_input++;
}
}
At first I tried a do-while loop within the main function. But it doesn't seem to work. It just messes up the output of my program and still doesn't prompt the user. Should I create a new function with the sole purpose of prompting the User? If so how would I? Thanks in advance.
To avoid running afoul of trailing data, call readchar() till you get a newline or EOF after each prompt:
for(;;)
{
int s1_index = 41;
char s1_random[s1_index];
s1(s1_random);
printf("\ns1 = ");
puts(s1_random);
printf("s2 = ");
int s2_index = 21;
char s2_input[s2_index];
s2(s2_input, s2_index);
if(s2_input[1] == '\0')
{
printf("size too small");
exit(0);
}
printf("ch = ");
int replacement = getchar();
if(replacement == EOF)
break;
while(getchar() != '\n');
printf("\n");
strfilter(s1_random, s2_input, replacement);
printf("\ns1 filtered = ");
puts(s1_random);
printf("Do you wish to run again? Yes(Y), No(N) ");
int run = getchar();
// or include ctype.h and do:
// run == EOF || toupper(run) == 'N'
if(run == EOF || run == 'N' || run == 'n')
break;
while(getchar() != '\n');
}
and example run:
s1 = NWLRBBMQBHCDARZOWKKYHIDDQSCDXRJMOWFRXSJY
s2 = NWLRBBMQBHCDARZOWKKYHIDDQSCDXRJMOWFRXSJY
ch = B
s1 filtered = BBBBBBBB
Do you wish to run again? Yes(Y), No(N) y
s1 = DBEFSARCBYNECDYGGXXPKLORELLNMPAPQFWKHOPK
s2 = NWLRBBMQBHCDARZOWKKYHIDDQSCDXRJMOWFRXSJY
ch = B
s1 filtered = BBBBBBBB
Do you wish to run again? Yes(Y), No(N) N
A very common mistake in C programs taking user input from stdin using getchar and scanf is to forget that these functions may leave newlines (or other characters) in the input stream.
In this case the line
scanf("%c", &run);
will leave (at least) a newline in the stream. That newline will be read by the next getchar and thereby make the program have unexpected behavior.
So your code should remove that newline just after the scanf. Actually it should remove all characters until it sees a newline.
Further, I would also remove any white space present in the stream before scanning for the user input. That can be done simply by putting a space before %c
Finally, your prompt suggests that you expect the user to input either Y or N but your program continues on any input not being an N
Something like this should fix the above mentioned problems:
char run = 'Y';
while(run != 'N')
{
// ... do your stuff
while(1)
{
// notice the space before %c to remove initial white spaces
if (scanf(" %c", &run) != 1) exit(1); // Input error
// Empty the input stream until a newline is found
while (1)
{
int temp = getchar();
if (temp == '\n') break; // Found end-of-line so break this while-loop
if (temp == EOF) exit(1); // Input error
}
if (run == 'Y' || run == 'N') break; // Valid input so break this while-loop
}
}
I am trying to get this yes no programme to work in a loop. I've checked the other users messages and there's only one which is poorly written and doesn't work properly.
So if the user types y or Y it installs and if they type n or N it exits out of the program. Also if they type w, m or any other letter that isn't y or n it goes back to the start and asks them again.
Not sure if its a while loop or a do while loop. The programme below works but doesn't have any loops.
#include <stdio.h>
int main() {
char yn;
printf("Do you want to install this programme? y/n: ");
scanf("%c", &yn);
if(yn == 'y' || yn == 'Y') {
printf("Installing...\n");
}
else if(yn == 'n' || yn == 'N') {
printf("Exiting programme!\n");
}
else {
// Go back to the start/top of the programme!
}
return 0;
}
You can wrap your code into a while-loop.
Something like:
while(1)
{
printf("Do you want to install this programme? y/n: ");
scanf("%c", &yn);
if(yn == 'y' || yn == 'Y') {
printf("Installing...\n");
break; // Stop the while-loop to end the program
}
else if(yn == 'n' || yn == 'N') {
printf("Exiting programme!\n");
break; // Stop the while-loop to end the program
}
}
The type of loop that makes most sense in this scenario is a do/while loop since getting a response from a user is something that should happen at least once and be tested for until a desired response is obtained from the user.
Also, using tolower or toupper on yn when checking for equality can eliminate the need to check both upper and lowercase.
do
{
printf("Do you want to install this program? y/n: ");
scanf(" %c", &yn);
}
while(tolower(yn) != 'n' && tolower(yn) != 'y');
if(tolower(yn) == 'n')
{
printf("Exiting program\n");
}
else
{
printf("Installing ...\n");
}
fgets can be used to capture the input. It has an advantage of being able to clear the input stream in case of too many characters or incorrect characters.
#include <stdio.h>
#include <string.h>
int main ( void) {
char input[3] = "";//can hold one char a newline and a '\0'
printf("Do you want to install this programme? y/n: ");
do {
printf ( "\nenter y or n\n:");
if ( fgets ( input, sizeof input, stdin)) {
if ( !strchr ( input, '\n')) {//is there a newline?
while ( !strchr ( input, '\n')) {//call until newline is found to clear input
if ( !fgets ( input, sizeof input, stdin)) {
fprintf ( stderr, "\nEOF problem\n");
return 1;
}
}
input[0] = 0;
printf ( "\ntoo many characters. try again.");
}
}
else {
fprintf ( stderr, "\nEOF problem\n");
return 1;
}
if ( input[0] == 'y' || input[0] == 'Y') {
printf("Installing...\n");
}
if ( input[0] == 'n' || input[0] == 'N') {
printf("Exiting programme!\n");
}
} while ( input[0] != 'y' && input[0] != 'n' && input[0] != 'Y' && input[0] != 'N');
return 0;
}
Solved!
This is the code that works. Thanks to #govindparmar.
#include <stdio.h>
int main() {
char yn;
do {
printf("Do you want to install this programme? y/n: ");
scanf(" %c", &yn);
}
while(yn != 'n' && yn != 'N' && yn != 'y' && yn != 'Y');
if(yn == 'n' || yn == 'N') {
printf("Exiting programe!\n");
}
else {
printf("Installing...\n");
}
printf("It works!\n");
return 0;
}
I've encountered a problem when validating a single-char scanf input in C and I cannot find an existing solution that works...
The scenario is: a method is taking a single letter 'char' type input and then validating this input, if the criteria is not met, then pops an error message and re-enter, otherwise return this character value.
my code is:
char GetStuff(void)
{
char c;
scanf("%c", &c);
while(c != 'A' || c != 'P')
{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &dtChar);
}
return c;
}
however, i got the infinite loop of error message no matter what input I type in. I read some other posts and guess it's the problem that %c specifier does no automatically get rid of the newline when I hit enter, and so far I have tried:
putting a white space before/after %c like:
scanf(" %c", &c);
write a separate method or include in this GetStuff method to clean the newline like:
void cleanBuffer(){
int n;
while((n = getchar()) != EOF && n != '\n' );
}
Can anyone help me with this problem please? Thank you in advance.
Please consider the following snippet:
#include <stdio.h>
#include <ctype.h>
char GetStuff(void)
{
char c;
do {
printf("Please enter A for AM or P for PM: ");
scanf ("%c", &c);
// clean input buffer (till the end of line)
while(getchar()!='\n');
} while(toupper(c) != 'A' && toupper(c) != 'P');
return c;
}
int main(void)
{
printf("Your input is'%c'\n", GetStuff());
return 0;
}
Note the points:
condition while(c != 'A' || c != 'P') will be always true (just because one character cannot be 'A' and 'P' at the same time), so use while(c != 'A' && c != 'P') instead
No need for two scanf if you use do..while loop
After entering a char with scanf it is recommended to clean all characters from buffer, e.g. with while(getchar()!='\n'); (this will clean all input including incorrect and redundant characters)
use toupper to avoid making 4 comparison (actually single c=toupper(c) inside loop can minimize your while as while(c != 'A' && c != 'P') )
UPDATE:
To add message "Invalid input" and adding some other useful improvement subjected befor... new code is as:
#include <stdio.h>
#include <ctype.h>
void CleanBuffer(){
int n;
while((n = getchar()) != EOF && n != '\n' );
}
char GetStuff(void)
{
char c;
do {
printf("Please enter A for AM or P for PM: ");
scanf (" %c", &c);
c = toupper(c); // here letter become uppercase
CleanBuffer();
} while( (c != 'A' && c != 'P')?printf("Invalid input! "):0 );
return c;
}
int main(void)
{
printf("You have entered: %c\n", GetStuff());
return 0;
}
Note: function will return 'A' or 'P' in uppercase, so if this is not needed change the code as in example before update (use two toupper and do not change c after scanf). Also you can use tolower as an option (of course with comparing to 'a' and 'p').
#include <stdio.h>
char GetStuff(void) {
char c;
scanf("%c", &c);
getchar();
while ((c != 'A') && (c != 'a') && (c != 'P') && (c != 'p')) {
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &c);
getchar();
}
return c;
}
int main(void) {
printf("Calling GetStuff()...\n");
char x = GetStuff();
printf("User entered %c\n", x);
return 0;
}
You are using while (c != 'A' || c != 'P') as your loop conditional, but this will always return true. What you meant to use is the && "and" operator, instead of the || "or" operator.
Also, call getchar() after your scanf statements, to capture the newline. This should work the way you want it to.
Inside loop you are taking input in dtChar but your loop condition checks variable c which is not updated in the loop, that is causing infinite loop
Also you would change your condition
while(c != 'A' || c != 'P')
to
while(c != 'A' && c != 'P')
If you want user to enter either 'A' or 'P'
Another possible solution. As others mentioned the condition was to be done with &&. Anyway the big problem is how to remove what's left on the console input line. Since the console works by lines, we remove everything up to the next '\n'. If the user already left something on the input line before calling GetStuff(), it would be useful to add a call to SkipRestOfTheLine() before the while loop.
In general I suggest to start with a while(1) loop, before making it nicer (such as in the cleanBuffer() you posted).
#include <stdlib.h>
#include <stdio.h>
void SkipRestOfTheLine(void)
{
while (1) {
int c = fgetc(stdin);
if (c == EOF || c == '\n')
break;
}
}
char GetStuff(void)
{
while (1) {
int c = fgetc(stdin);
if (c == EOF)
exit(EXIT_FAILURE); // Deal with this case in an appropriate way
if (c == 'A' || c == 'P')
return c;
printf("invalid input, enter again (A for AM or P for PM): ");
SkipRestOfTheLine();
}
}
int main(void)
{
char c = GetStuff();
return 0;
}
try this,
char GetStuff(void)
{
char c;
scanf("%c", &c);
while (((c != 'A') || (c != 'a')) && ((c != 'P') || (c != 'p'))==1)
{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &dtChar);
}
return c;
}
I hope this works, some time because of not given proper bracket it is stuck in the loop.
#include <stdio.h>
int main(){
char c;
do{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%s", &c);
}while ((c != 'A') && (c != 'P'));
return 0;
}
I'm just a beginner and I'm trying to use whatever I know to make a simple program that:
Asks the user to input the letter 'S' or 's'. The program loops if 's' is not input. If the user does input 's', the program then
Asks the user to input a number, 1 or 2. The program loops if the incorrect number is input.
The problem I'm having is that after 's' is successfully input and the user is asked to enter a number, if an incorrect number is input (not 1 or 2) the program asks the user to input a letter again from the beginning which is incorrect. The program loops from the very beginning and doesn't work anymore. Can anyone help me fix this please?
#include <stdio.h>
#include <ctype.h>
int function(int num);
int main()
{
char input,ch,temp,c[64],exit;
int i,invalid,num,index,flag,day;
invalid = 0;
num = 0;
size_t length = 0;
index = 0;
flag = 0;
do
{
puts("Enter the letter S to start the program:");
scanf("%c", &input);
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
{
if(isalpha(input)==0)
{
printf("Invalid input. Please input something.\n");
continue;
}
if(input == 'S' || input == 's')
{
printf("\nProgram start.");
while( sscanf(c, "%d", &num) != 1)
{
length = 0;
flag = 0;
num = 0;
printf("\nEnter 1 for Module A. Enter 2 for Module B. Enter here: ");
fgets(c, 63, stdin);
length = strlen(c);
for(index = 0; index < length; ++index)
{
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
}
if( flag)
{
printf("\nInvalid character\n");
continue;
}
if( sscanf(c, "%d", &num) != 1)
{
printf("\nNo input detected.");
continue;
}
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
}
}
else
{
printf("\nInvalid input.");
continue;
}
}
}
while(1);
}
Make the scanf into like this.
scanf(" %c",&input);
Then While getting the input from the user using fgets It will place the new line character into that buffer. So this will lead to fails this condition.
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
So make the this condition into like this.
length=strlen(c)-1;// to skip the new line character
Or else to like this.
length=strlen(c);
if ( c[length] == '\n' )
c[length]='\0';
Output After placing this,
Enter the letter S to start the program:
S
Program start.
Enter 1 for Module A. Enter 2 for Module B. Enter here: 1
Module A Selected.
Make this in you code.
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
else if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
else
{
printf("\nInvalid option\n");
c[0]='\0'; // It is for satisfy the second while loop condition.
continue;
}
Note that the loop:
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
is limited to the one line by the semicolon at the end. The following code is not the body of the loop, despite indentation trying to pretend that it is.
Also note that getchar() returns an int, not a char; you cannot reliably assign the result to a char and then test it for EOF. Depending on the platform, you will either never detect EOF at all or you will misdetect EOF when some other character (often ΓΏ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) is typed. You must use int ch;.
Here. I fixed the problem using the following code. This way the code does the following:
Scans letters 'S' or 's'. Keeps looping if these are not entered.
Scans either number 1 or 2. Keeps looping until either number is entered and then exits.
The program does not loop from the very beginning (by outputting "Enter 'S' to start program), if any number other than 1 or 2 in entered in part 2 of the program. This was the problem originally.
The following is the correct code:
#include <stdio.h>
#include <ctype.h>
int function();
char input,temp,c[64],ch,exit;
int i,invalid,num,index,flag,start;
start = 0;
invalid = 0;
num = 0;
size_t length = 0;
index = 0;
flag = 0;
int main()
{
do
{
puts("Enter the letter S to start the program: ");
scanf("%c", &input);
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
{
if(isalpha(input)==0)
{
printf("Invalid input. Please input something.\n");
continue;
}
if(input == 'S' || input == 's')
{
printf("\nProgram start.");
start = 1;
if(start == 1)
{
function();
return(0);
}
}
else
{
printf("\nInvalid input.");
continue;
}
}
}
while(1);
}
int function()
{
while( sscanf(c, "%d", &num) != 1)
{
length = 0;
flag = 0;
num = 0;
printf("\nEnter 1 for Module A. Enter 2 for Module B. Enter here: ");
fgets(c, 63, stdin);
length = strlen(c);
length --;
for(index = 0; index < length; ++index)
{
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
}
if( flag)
{
printf("\nInvalid character\n");
continue;
}
if( sscanf(c, "%d", &num) != 1)
{
printf("\nNo input detected.");
continue;
}
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
else if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
else
{
printf("\nInvalid option\n");
c[0]='\0'; // It is for satisfy the second while loop condition.
continue;
}
}
}
I'm developing a chess game in C just for practicing. At the beginning of the game, the user can type 4 things:
ROW<whitespace>COL (i.e. 2 2)
'h' for help
'q' to quit
How can I use a scanf to expect 2 integers or 1 char?
Seems like it would be most sensible to read a whole line, and then decide what it contains. This will not include using scanf, since it would consume the contents stdin stream.
Try something like this :
char input[128] = {0};
unsigned int row, col;
if(fgets(input, sizeof(input), stdin))
{
if(input[0] == 'h' && input[1] == '\n' && input[2] == '\0')
{
// help
}
else if(input[0] == 'q' && input[1] == '\n' && input[2] == '\0')
{
// quit
}
else if((sscanf(input, "%u %u\n", &row, &col) == 2))
{
// row and column
}
else
{
// error
}
}
It's better to avoid using scanf at all. It usually causes more trouble than what it solves.
One possible solution is to use fgets to get the whole line and then use strcmp to see if the user typed 'h' or 'q'. If not, use sscanf to get row and column.
This one is just using scanf
#include <stdio.h>
int main()
{
char c;
int row, col;
scanf("%c", &c);
if (c == 'h')
return 0;
if (c == 'q')
return 0;
if (isdigit(c)) {
row = c - '0';
scanf("%d", &col);
printf("row %d col %d", row, col);
}
return 0;
}
int row, col;
char cmd;
char *s = NULL;
int slen = 0;
if (getline(&s, &slen, stdin) != -1) {
if (sscanf(s, "%d %d", &row, &col) == 2) {
free(s);
// use row and col
}
else if (sscanf(s, "%c", &cmd) == 1) {
free(s);
// use cmd
}
else {
// error
}
}
P.S.: those who did not read and understand my answer carefully, please respect yourself, DO NOT VOTE-DOWN AT WILL!
Beside "get the whole line and then use sscanf", read char by char until '\n' was entered is also a better way. If the program encountered 'h' or 'q', it could do the relevant action immediately, meanwhile you cloud also provide a realtime analysis for the input stream.
example:
#define ROW_IDX 0
#define COL_IDX 1
int c;
int buffer[2] = {0,0};
int buff_pos;
while( (c = getchar())) {
if (c == '\n') {
//a line was finished
/*
row = buffer[ROW_IDX];
col = buffer[COL_IDX];
*/
buff_pos = 0;
memset(buffer , 0 , sizeof(buffer));//clear the buffer after do sth...
} else if (c == 'h') {
//help
} else if (c == 'q') {
//quit
} else {
//assume the input is valid number, u'd better verify whether input is between '0' and '9'
if (c == ' ') {
//meet whitespace, switch the buffer from 'row' to 'col'
++buff_pos;
} else {
buffer[buff_pos%2] *= 10;
buffer[buff_pos%2] += c - '0';
}
}
}