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.
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!)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
int valid=0, running=1;
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%d", &c);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
scanf(" %c", retry);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(choice==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
Here the user should enter either 1 or 2. If the user enters any other number or character then I want to ask the user to input again. The program works fine if the user enters any other number like 5/6/7 etc. But if the user enters a character the program goes into an infinite loop. I can break the loop with a scanf status check but then the program stops. Instead, I want to prompt the user to input again if he enters anything except 1 or 2.
scanf returns the number of successful input assignments, or EOF on end of file or error. You should get in the habit of checking this return value. In this case of scanf( "%d", &c ), you should expect a return value of 1 on a successful input.
The %d conversion specifier tells scanf to skip over any leading whitespace, then read characters up to the first character that isn't a decimal digit, leaving that character in the input stream.
Example - suppose you enter "12.3" as an input. scanf( "%d", &c ) will read, convert, and assign the "12" portion of the input to c and return 1. The ".3" portion of the input is left in the input stream.
If you call scanf( "%d", &c ) again, the first thing it sees is that '.' character, so it immediately stops reading (you have a matching failure).
Since no input was actually read, nothing gets assigned to c and scanf returns 0. This will keep happening until you remove that '.' character with some other input operation like getchar() or scanf( "%*c" ), etc.
You should always check the result of scanf to make sure you read as many items as you expect:
int r = 0;
do
{
r = scanf( "%d", &c );
if ( r == EOF )
{
// end of file or error signaled on the input stream; in this case we
// just exit the program
exit( 0 );
}
else if ( r == 0 )
{
// matching failure - there's a bad character in the input stream
// remove it with getchar and try again
getchar();
}
} while( r != 1 );
// at this point we either have good input or have already exited the program
Apparently, using scanf with %d, but input characters causes buffer issues. See code below for one way to avoid the problem:
#include <stdio.h>
#include <stdlib.h>
void generate(){
printf("generate\n");
}
void retrieve(){
printf("retrieve\n");
}
int main(){
int valid=0, running=1, idx=0, c=-100;
char retry;
char s[25];
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%s", s);
c = atoi(s);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
while(scanf(" %c", &retry)==0);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(c==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
return(0);
}
One possible execution is shown below:
1. Generate
2. Retrieve
Enter choice> Bad
Invalid input. Try again
Enter choice> Worse
Invalid input. Try again
Enter choice> 1
generate
Press Y to generate again. Press N to retrieve> Y
generate
Press Y to generate again. Press N to retrieve> n
retrieve
So my code does the following:
Ask what's the option
If option is 1: Scan some numbers
If option is 2: Print those numbers
After each option, ask if user wanted to continue choosing (Y/N)
This is my main code
while(yesnocheck==1)
{
printf("What's your option?: ");
scanf("%d",&b);
switch(b){
case 1:
printf("How many numbers?: ");
scanf(" %d",&n);
a=(struct sv*)malloc(n*sizeof(struct sv));
for(int i=0;i<n;i++)
scanf("%d",&((a+i)->num));
break;
case 2:
for(int i=0;i<n;i++)
printf("%d\n",(a+i)->num);
break;
}
yesnocheck==yesnochecker();
}
And this is the yesnochecker function:
int yesnochecker()
{
char yesorno;
printf("Do you want to continue? (Y/N)");
while(scanf("%s",&yesorno))
{
if(yesorno=='Y')
return 1;
if(yesorno='N')
return 0;
printf("*Wrong input. Please reenter (Y/N): ");
}
}
So on dev C++, my code won't run correctly. After it's done option 1, when I enter "Y" then choose option 2, case 2 will display some weird numbers. However it works well on online C compilers.
And then, when I change the char yesorno in yesnochecker() function to char yesorno[2] and treat it as a string, the code does work.
Can someone shed some light?
It is a bad idea to read a char c with scanf("%s", &c);. "%s" requires a buffer to store a string. The only string which fits into a char is an empty string (consisting only of a terminator '\0' – not very useful). Every string with 1 character requires 2 chars of storage – 1 for the character, 1 for the terminator ('\0'). Providing a char for storage is Undefined Behavior.
So, the first hint was to use the proper formatter instead – "%c".
This is better as it removes the Undefined Behavior. However, it doesn't solve another problem as the following sample shows:
#include <stdio.h>
int cont()
{
char c; do {
printf("Continue (y/n): ");
scanf("%c", &c);
printf("Input %c\n", c);
} while (c != 'y' && c != 'n');
return c == 'y';
}
int main()
{
int i = 0;
do {
printf("Loop iteration %d.\n", ++i);
} while (cont());
/* done */
return 0;
}
Output:
Loop iteration 1.
Continue (y/n): y↵
Input 'y'
Loop iteration 2.
Continue (y/n):
Input '
'
Continue (y/n): n↵
Input 'n'
Live Demo on ideone
WTH?
The scanf("%c") consumes one character from input. The other character (inserted for the ENTER key) stays in input buffer until next call of any input function.
Too bad, without ENTER it is hard to confirm input on console.
A possible solution is to read characters until the ENTER key is received (or input fails for any reasons). (And, btw., getc() or fgetc() can be used as well to read a single character.):
#include <stdio.h>
int cont()
{
int c;
do {
int d;
printf("Continue (y/n): ");
if ((c = fgetc(stdin)) < 0) {
fprintf(stderr, "Input failed!\n"); return 0;
}
printf("Input '%c'\n", c);
for (d = c; d != '\n';) {
if ((d = fgetc(stdin)) < 0) {
fprintf(stderr, "Input failed!\n"); return 0;
}
}
} while (c != 'y' && c != 'n');
return c == 'y';
}
int main()
{
int i = 0;
do {
printf("Loop iteration %d.\n", ++i);
} while (cont());
/* done */
return 0;
}
Output:
Loop iteration 1.
Continue (y/n): y↵
Input 'y'
Loop iteration 2.
Continue (y/n): Hello↵
Input 'H'
Continue (y/n): n↵
Input 'n'
Live Demo on ideone
Please, note, that I changed the type for the read character to int. This is because getc()/fgetc() return an int which is capable to store any of the 256 possible char values as well as -1 which is returned in case of failing.
However, it isn't any problem to compare an int with a character constant (e.g. 'y'). In C, the type of character constants is just int (SO: Type of character constant).
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
This question already has answers here:
Scanf skips every other while loop in C
(10 answers)
Closed 6 years ago.
I thought of making a calculator, just a simple one with loops and the basic operations, but the weird thing is that the scanf of character in between my scanf for number is being ignored. It works fine if I put it on top of the scanf of integer but it wouldn't look anything like a calculator. Is there any way to solve this issue? It's not yet finished; got an error up to here, so wondering what's wrong.
#include <stdio.h>
#include <stdlib.h>
int main(){
int number1,number2,total;
char a;
printf("This is your personal calculator:(End with ""="")\n");
scanf("%d",&number1);
scanf("%c",&a);
scanf("%d",&number2);
if (a == 'x' || a == 'X' || a == '*'){
total=number1*number2;
printf("%d",total);
} else if (a == '/'){
total=number1/number2;
printf("%d",total);
} else if (a == '+'){
total=number1+number2;
printf("%d",total);
} else if (a == '-'){
total=number1-number2;
printf("%d",total);
} else {
printf("error");
}
system("pause");
return 0;
}
You should test that you get a value from scanf(), every time.
The %c character reads the blank or newline after the first number; use " %c" with a leading space to skip over optional white space before reading the character.
if (scanf("%d", &number1) == 1 &&
scanf(" %c", &a) == 1 &&
scanf("%d", &number2) == 1)
{
...process possibly valid input...
}
else
{
...diagnostics...
}
It will probably be easier to give good diagnostics if you read whole lines with fgets() and parse them with sscanf().
Recommendation 1: show an example of what you type as input and what you get as output. This makes it easier for people to help you (they can tell whether the program is producing the same output for them).
Recommendation 2: echo your input so you can see what the program got. This allows you to tell whether the program got the input you expected. You'd probably find that number2 was not containing what you expected, for example.
Recommendation 3: initialize number1 and number2 to -1 so you can see when the scanf() failed (since you aren't yet checking whether scanf() succeeded).
The problem is because of the newline char \n left over by the scanf. This could be avoided by placing a space before format specifier %c.
Try this
scanf(" %c", &a);
^ An space
this will help you to eat up \n char left over by first scanf
int main()
{
int number1,number2,total;
char a;
printf("This is your personal calculator:(End with ""="")\n");
scanf("%d",&number1);
fflush(stdin); // SIMPLE WAY FLUSH THE INPUT STREAM, INPUT BUFFER IS USUALLY CLEARED.
scanf("%c",&a);
scanf("%d",&number2);
if (a == 'x' || a == 'X' || a == '*'){
total=number1*number2;
printf("%d",total);
} else if (a == '/'){
total=number1/number2;
printf("%d",total);
} else if (a == '+'){
total=number1+number2;
printf("%d",total);
} else if (a == '-'){
total=number1-number2;
printf("%d",total);
} else {
printf("error");
}
system("pause");
return 0;
}