I was trying a simple C code and found out strange error. Here is the code. As soon as the first
scanf()
function is encountered, the compiler automatically skips it and move ahead. Why is that so?
#include<stdio.h>
#include<stdlib.h>
void main()
{
float base_cost, refresh_cost;
int ticket;
char coupon, refresh, circle;
printf("Enter number of tickets: ");
scanf("%d", &ticket);
if(ticket<5 ||ticket>40)
{
printf("Minimum of 5 and Maximum of 40 Tickets");
exit(0);
}
printf("Do you want refreshment?(Y/N): "); //Here compiler skips
scanf("%c", &refresh);
printf("Do you have coupon?(Y/N): ");
scanf("%c", &coupon);
printf("Enter circle: ");
scanf("%c", &circle);
if(circle!='k'||circle!='q' || circle!='K' || circle!='Q')
{
printf("Invalid Input");
exit(0);
}
else if(circle == 'k' || circle == 'K')
{
if(ticket > 20)
base_cost = (ticket*75.00) - 0.1*(ticket*75.00);
else if(coupon == 'y' || coupon == 'Y')
base_cost = (ticket*75.00) - 0.02*(ticket*75.00);
else
base_cost = ticket*75.00;
}
else if (circle == 'q' || circle == 'Q')
{
if(ticket > 20)
base_cost = (ticket*150.00) - 0.1*(ticket*150.00);
else if(coupon == 'y' || coupon == 'Y')
base_cost = (ticket*150.00) - 0.02*(ticket*150.00);
else
base_cost = ticket*150.00;
}
if (refresh == 'y' || refresh == 'Y')
{
refresh_cost = ticket * 50.00;
}
else
refresh_cost = 0.00;
printf("\nTotal cost: %0.2f", base_cost + refresh_cost);
}
I used the variable refresh in order to allow the user to have a choice, whether or not to insert elements i.e. Y or N.
Also, it looks like other scanf function with char as input are also been skipped.
But the compiler basically skips the third scanf function, the one that accepts the char, along with the while loop.
Unlike %d and %s, the %c conversion specifier does not skip over leading whitespace. What's happening is you have a stray newline in the input stream after the first scanf call to get the ticket number; that newline is read by the next scanf call and assigned to refresh.
To avoid this, put a blank space in front of the %c specifier:
scanf( " %c", &refresh );
That blank space tells scanf to skip over any leading whitespace. Do this for every %c that is meant to read a non-whitespace cparacter.
Related
I'm having a problem with multiple characters while using a while loop. I'm writing a code that would direct the user to a new function based on the input of either "y" or "n". When I scanf for one character it works fine; however, when the user types in multiple characters the while loop repeats.
#include <stdio.h>
int main()
{
char x;
printf("type in letter n or y\n");
scanf("%c", &x);
while (x!= 'Y' && x!='N' && x!= 'n' && x!='y')
{
printf("Invalid, please type Y/N to continue: \n");
scanf(" %c", &x);
}
if (x== 'Y' || x == 'y')
{
printf("y works");
}
if (x =='N' || x =='n')
{
printf("n works");
}
}
For example, if I type in hoyp, it would say "Invalid, ..." 2 times and then the "y works" would be written on the third line. How can the code be changed so that the invalid would only be said once, and the user must input again to allow the program to continue?
This is how scanf behaves. It keeps reading in all the characters you've entered. You can accept a string as input first using fgets and extract and check only its first character. fgets allows you to specify the exact number of characters to be read. I have first declared a char array of size 4096. This will work when the input is up to 4095 characters. You can adjust the size as per your needs.
#include <stdio.h>
int main()
{
char x, buffer[4096];
printf("type in letter n or y\n");
fgets(buffer, 4096, stdin);
x = buffer[0];
while (x!= 'Y' && x!='N' && x!= 'n' && x!='y')
{
printf("Invalid, please type Y/N to continue: \n");
fgets(buffer, 4096, stdin);
x = buffer[0];
}
if (x== 'Y' || x == 'y')
{
printf("y works");
}
if (x =='N' || x =='n')
{
printf("n works");
}
}
Here is my approach to the problem:
I have used fgets() instead of scanf(). See why
here.
I have used the suggestion by users jamesdlin and M.M in this question to solve the repeated printing issue when the input is more than one character or if the input is empty. I encourage you to read the whole thread to know more about this issue.
(Optional) Used some extra headers for better code readability in the loop conditions. I think the fgets() could be used in the condition of the while() but I got used to the pattern I have written below.
Edit: added a condition to reject inputs with length > 1. Previously, inputs that starts with 'y' or 'n' will be accepted (and are interpreted as 'y' or 'n' respectively) regardless of their length.
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
void clearInput();
int main()
{
// allocate space for 'Y' or 'N' + '\n' + the terminator '\0'
// only single inputs will be accepted
char _inputbuff[3];
char choice;
bool isValidInput = false;
while(!isValidInput) {
printf("Please enter your input[y/n]: ");
// use fgets() instead of scanf
// this only stores the first 2 characters of the input
fgets(_inputbuff, sizeof(_inputbuff), stdin);
// don't accept empty input to prevent hanging input
if(_inputbuff[0] == '\n') {
printf("Empty input\n");
// go back to the top of the loop
continue;
}
// input is non-empty
// if the allocated space for the newline does not
// contain '\n', reject the input
if(_inputbuff[1] != '\n') {
printf("Input is more than one char.\n");
clearInput();
continue;
}
choice = _inputbuff[0];
// printf("The input is %c\n", choice);
// convert the input to uppercase for a 'cleaner' code
// during input validation
choice = toupper(choice);
// the input is not 'Y' or 'N'
if(choice != 'Y' && choice != 'N') {
printf("Please choose from Y or N only.\n");
// go back to the top of the loop
continue;
}
// the input is 'Y' or 'N', terminate the loop
isValidInput = true;
}
// conditions for 'Y' or 'N'
if(choice == 'Y') {
printf("The input is Yes.\n");
return 0;
}
if(choice == 'N') {
printf("The input is No.\n");
return 0;
}
}
void clearInput() {
int _clear;
// clear input stream to prevent repeated printing of invalid inputs
while ((_clear = getchar()) != '\n' && _clear != EOF ) { }
}
(This is my first time answering a question and it has been a while since I have used C so feel free to give suggestions/corrections regarding my answer. Thanks!)
I'm creating a conversion project for letters/numbers ASCII table. My code is supposed to be 'interactive', so the user would type 'y' or 'n' to answer questions on the screen. However, it doesn't want to do this twice...
I have tried:
Just trying numbers instead of characters, but it's not exactly what I want
The %[\n]*c, and %[\n]c, and %[\n]*s ... technique but it doesn't help ;-;
Testing in a different project, but the only way I am able to do it is for multiple scanf()s to be in a row.
Here is the code:
printf("Would you like to convert a number today? \n");
printf("Please press Y or N \n");
scanf("%c", &input);
if (input == 'y' || input == 'Y') { //compare input if they said 'yes'
printf("\nThank you! \nWhat number?\n");
scanf("%d", &number);
flag = test(number);
if (flag == 0) { //if there is an equivalent letter
letter = conversion(number); //find the equivalent letter
printf("\nYour Number \t ASCII letter\n");
printf("%d\t %c\n", number, letter);
}
}
else if (input == 'n' || input == 'N') {
printf("\nWould you like to convert a letter instead? This time enter 0 or 1\!\n\n"); //problem here!!
printf("I wish I could say it was to \' Spice things up \' ...but it\'s not ;-; \n\n");
scanf("%d", &input2);
if (input2 == 0) { //this needs to be checking whether the user input Y/y
printf("Great choice adventurer!\n");
printf("What letter will it be today?\n\n");
//..I would go to a different funtion here ie: test2(letter)...
scanf("%d", &number); //I showed that it worked with multiple numbers, but I can't get this to work with multiple letters
printf("%d", number);
}
if (input2 == 1) { //this needs to be checking whether the user input N/n
printf("Difficult to please, I see...\n\n");
printf("I suggest you move on with that attitude!\n\n");
printf("Bye bye then\n");
}
}
else { //if they tried to break the code
printf("Sorry I did not recognise your command...please retry\n");
printf("Press Y or N next time!\n");
}
The first check works perfectly, I just want the second check to be like the first!
Some 'solutions' caused a overflow, which I don't want if possible
Even if someone could explain why this isn't working the way I intended would be very helpful!
I'm not sure what confuses you.
Use
char foo;
scanf(" %c", &foo);
for single characters, eg. letters and
int bar;
scanf("%d", &bar);
for numbers, integers. If you type a letter instead, scanf() will fail.
%[...] is for strings.
scanf() returns the number of successful conversions (or EOF), so for
int height;
int width;
scanf("%d %d", &height, &width);
it returns 2 if successful. It might return 1 if only height could be read.
So to check for errors on user input you should do:
int height;
int width;
if (scanf("%d %d", &height, &width) != 2) {
// handle the error, maybe exit the program.
}
Your code could look like that (without error handling):
#define _CRT_SECURE_NO_WARNINGS // you said Visual Studio? Without it you should get
// warnings about some functions being insecure.
#include <ctype.h> // isalpha() returns true if the value is a letter
#include <stdlib.h> // EXIT_SUCCESS
#include <stdio.h> // puts(), printf(), scanf()
int main(void)
{
for(;;) { // for-ever ... endless loop since the user exits by answering
// 'n' or 'N' two times
puts("Would you like to convert a number today?\nPlease press Y or N:");
char input;
if (scanf(" %c", &input) != 1) // We reached EOF ... end of file
break; // that's improbable for stdin,
// but input could be redirected to
// read from a file instead.
if (input == 'y' || input == 'Y') {
puts("\nThank you!\nWhat number?");
int number;
scanf("%d", &number);
if (isalpha((char unsigned)number)) // *)
printf("\nYour Number \t ASCII letter\n%d\t %c\n\n", number, number);
else
puts("Sorry, but that's not the ASCII code of a letter :(\n");
}
else if (input == 'n' || input == 'N') {
puts("\nWould you like to convert a letter instead?\nPlease press Y or N:");
scanf(" %c", &input);
if (input == 'y' || input == 'Y') {
puts("\nGreat choice adventurer!\nWhat letter will it be today?");
char letter;
scanf(" %c", &letter);
if (isalpha(letter))
printf("\nYour letter \t ASCII code\n%d\t %c\n\n", letter, letter);
else
puts("Sorry, but that's not a letter :(\n");
}
else if (input == 'n' || input == 'N') {
puts("\nDifficult to please, I see...\n\nI suggest you move on with that attitude!\n");
puts("Bye bye then.");
return EXIT_SUCCESS;
}
}
else {
puts("Sorry I did not recognize your command... Please retry.");
puts("Press Y or N next time!\n");
}
}
}
*) isalpha() (and the other functions in <ctype.h>) expects a value that fits in a unsigned char or the value EOF. It has undefined behaviour for other values. Since we read user input into an int we cannot be sure that's the case so we have to cast the value to unsigned char before passing it to isalpha() (and friends).
Next time you ask a question please include your full code, including variable declarations, functions like test() and conversion() and #includes. But please, post an example that focuses on your problem at hand. All that dialog you included would not have been necessary.
I need to write a program in C that let's the user choose to draw a rectangle square or print the board he made but everytime after the first input of a shape the program acts as if he entered an invalid character.
printf("please make you decision R-rectangle, S-square, E-end\n");
scanf("%c", &decision);
do
{
if (decision == 'R') {
printf("you chose rectangle! please enter the X start position, Y start position, hieght and width\n");
scanf("%d %d %d %d", &rectMat[0][rectCounter], &rectMat[1][rectCounter], &rectMat[2][rectCounter], &rectMat[3][rectCounter]);
if (rectCounter + 1 < MAX_RECT)
{
if (checkRECT(rectMat[0][rectCounter], rectMat[1][rectCounter], rectMat[2][rectCounter], rectMat[3][rectCounter], areaMat) == 1)
{
drawRECT(rectMat[0][rectCounter], rectMat[1][rectCounter], rectMat[2][rectCounter], rectMat[3][rectCounter], areaMat);
rectCounter++;
}
else
{
printf("we couldn't fit you rectangle\n");
}
}
else
{
printf("you have too many rectangles\n");
}
}
if (decision == 'S')
{
printf("you chose square! please enter the X start position, Y start position and size of the side\n");
scanf("%d %d %d", &sqrMat[0][rectCounter], &sqrMat[1][rectCounter], &sqrMat[2][rectCounter]);
if (sqrCounter<MAX_SQR)
{
if (checkSQR(sqrMat[0][rectCounter], sqrMat[1][rectCounter], sqrMat[2][rectCounter],areaMat)==1)
{
drawSQR(sqrMat[0][rectCounter], sqrMat[1][rectCounter], sqrMat[2][rectCounter], areaMat);
sqrCounter++;
}
else
{
printf("we couldn't fit your square\n");
}
}
else
{
printf("you have too many sqaures\n");
}
}
if (decision == 'P')
{
printArea(areaMat);
}
if (decision != 'E'&& decision != 'P'&& decision != 'S'&& decision != 'R')
{
printf("invalid entry\n");
}
printf("please make you decision R-rectangle, S-square, E-end\n");
scanf("%c", &decision);
} while (decision != 'E');
When you read characters using the "%c" format, it will read the next character in the input buffer, it will not skip any white-space. And when using scanf to read anything, the newline you enter to send the input to the program will also be sent, and added as a white-space character after the end of your input. Most formats do skip leading white-space (like for example the "%d" format), but the "%c" and "%[" formats do not.
When reading character it's almost always advisable to skip leading white-space, which is done by adding a space before the format, like e.g.
scanf(" %c", &decision);
// ^
// |
// Note space here
Also note that there is a difference between upper- and lower-case letters. 'R' != 'r'. Either check for both upper- and lower-case letters, or use toupper (or tolower) to convert.
you better off using getc() instad of scanf() since you're expecting a single char anyway
I'm trying to do a conditional and if-else loop
on this problem however, my main function isn't executing the steps in the order I had intended.
#include<stdio.h>
void draft(int, char);
void main()
{
int age = 0;
char sex;
printf("How old are you?");
scanf_s("%d", &age);
printf("Please enter your sex.(M or F)");
scanf_s("%c", &sex);
draft(age,sex);
system("pause");
return;
}
void draft(int age,char sex)
{
if (age>= 21 && sex=="M")
{
printf("Congratulations son, You will be going off to Syria to fight for your country.\n");
}
else if (age >= 18 && sex == "M")
{
printf("Congratulations son, You will be going off to Vietnam to fight for your country.\n");
}
else if (age < 18 && sex == "M")
{
printf("Sorry Son you're still too young.\n");
}
else if (age >= 21 && sex == "F")
{
printf("Sorry,miss, only men can serve.\n");
}
else if (age >= 18 && sex == "F")
{
printf("Sorry,little lady, only men can serve.\n");
}
else if (age < 18 && sex == "F")
{
printf("Sorry,little girl, only men can serve.\n");
}
else
{
printf("Please enter age and sex.");
}
return;
}
The user is prompted for his age but after that is entered it will go directly to the last ELSE statement of the "draft" function without giving the user the opportunity to enter the sex.
The problem is that you are using scanf to parse input from stdin. However this just treats it as a stream. Your program actually works if you enter something like 32F at the first input.
[Edit for clarity: You program is not actually jumping oddly, what is happening is that the second scanf returns immediately with data from stdin which wasn't read with the first one. In this case it is the return character from when user pressed enter key. So it returns immediately with a value that is not your 'M' or 'F', hence it runs the final else. There is no "out of order" happening]
Note: There is a second problem in your draft() function. You use "M" and "F" which are strings (character arrays), whereas you actually need to use 'M' and 'F' which are single characters.
What you are wanting is to read a single line and parse it at a time. So I suggest the following change. I have replaced the scanfs with a fgets which will read a single line. Then use sscanf to parse that line.
#include<stdio.h>
void draft(int, char);
int main()
{
int age = 0;
char sex;
char line[100] = {0};
printf("How old are you?");
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &age);
printf("Please enter your sex.(M or F)");
fgets(line, sizeof(line), stdin);
sscanf(line, "%c", &sex);
draft(age,sex);
return 0;
}
void draft(int age,char sex)
{
if (age>= 21 && sex=='M')
{
printf("Congratulations son, You will be going off to Syria to fight for your country.\n");
}
else if (age >= 18 && sex == 'M')
{
printf("Congratulations son, You will be going off to Vietnam to fight for your country.\n");
}
else if (age < 18 && sex == 'M')
{
printf("Sorry Son you're still too young.\n");
}
else if (age >= 21 && sex == 'F')
{
printf("Sorry,miss, only men can serve.\n");
}
else if (age >= 18 && sex == 'F')
{
printf("Sorry,little lady, only men can serve.\n");
}
else if (age < 18 && sex == 'F')
{
printf("Sorry,little girl, only men can serve.\n");
}
else
{
printf("Please enter age and sex.");
}
return;
}
Two issues:
After the first call scanf_s, a newline is left in the buffer. That newline is immediately picked up by the second scanf_s. You need to change the pattern to match and discard any newlines by putting a space before %d and %c. Also, you should check the return value to ensure that a value matching the pattern was read:
printf("How old are you?");
if (scanf_s(" %d", &age) != 1) {
printf("You must enter a value age.\n");
exit(1);
}
printf("Please enter your sex.(M or F)");
if (scanf_s(" %c", &sex) != 1) {
printf("You must enter a value age.\n");
exit(1);
}
In draft, you're using double quotes instead of single quotes for a character literal:
if (age>= 21 && sex=="M")
Here, "M" is a string containing one character plus a NULL terminator. What you want is 'M', which is the character M. So change the above line to:
if (age>= 21 && sex=='M')
And make a similar fix to the five other lines with the same issue.
Well, this is a problem:
scanf_s("%c", &sex);
Unlike conversion specifiers like %s and %d, the %c specifier does not cause scanf (and, I'm assuming, scanf_s) to skip over any leading whitespace in the input stream. So it immediately picks up the newline character after your first input, hence why it doesn't wait for you to enter the sex.
To fix that, put a blank space before the conversion specifier:
scanf_s(" %c", &sex );
Another problem is your comparisons sex == "M" and sex == "F"; sex is a single char, but "M" and "F" are character strings. Use the comparisons sex == 'M' and sex == 'F' (single quotes, not double quotes).
char player_select(void){
char player = 'n';
while(player == 'n'){
printf("Select your player (X or O): ");
scanf("%c\n", &player);
if(player != 'X' && player != 'O'){
printf("Invalid input. Try again.\n");
player = 'n';
}
}
printf("Your character input is: %c\n", player);
exit(0);
return player;
}
I am getting some weird output here:
Select your player (X or O): X
Invalid input. Try again.
Select your player (X or O): i
Your character input is: X
Incorrect use of scanf()
// scanf("%c\n", &player);
scanf(" %c", &player);
The '\n' in "%c\n" does not do what you think. '\n' tells scanf() to consume white-space like '\n' and ' ' until non-white-space occurs. You input was not as described.
Since stdin is buffered, text by itself, will not typically get read until a '\n' follows.
It gets complicated to explain in detail why things failed. So briefly, use " %c" instead of "%c\n". Or better yet, use fgets().
buffer player[10];
fgets(ch, sizeof ch, stdin);
if(player[0] != 'X' && player[0] != 'O') { ...
I hope this will work for you.
I have removed the \n inside the scanf and i have added while(getchar()!='\n'); for emptying stdin.
char player_select(void){
char player = 'n';
while(player == 'n'){
printf("Select your player (X or O): ");
scanf("%c", &player);
if(player != 'X' && player != 'O'){
printf("Invalid input. Try again.\n");
player = 'n';
}
while(getchar()!='\n');
}
This is the output:
Select your player (X or O): A
Invalid input. Try again.
Select your player (X or O): X
Your character input is: X
Try:
if (scanf("%c\n", &player) == 1 && player != 'X' && player != 'O'){
printf("Invalid input. Try again.\n");
player = 'n';
}
Bring scanf into the if, removing from your above code, and check its return value == 1.
You can try removing the \n from scanf mask if this won't suffice.