Why does my code skip over input from users? [closed] - c

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
So this is some code I have written, I am barley beginning on c so bear with me, my code makes sense to me but its not working properly, when am trying to say no to stop playing and display average it repeats the playing function.
Basically my program guesses the users number from 1-100 whatever number the user came up with. Here's some output that is wrong, just to give you an idea. The play game function is working fine but not the main.
Playing guess my number game
is your number 50 ?=
Great!
Play again? (y for yes n for no): is your number 50 ?=
Great!
Play again? (y for yes n for no): is your number 50 ?n
and so on i cant find where i went wrong any advice?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
int playgame(void);
main() {
int numberofplays = 0;
float average = 0;
int numberguesses = 0;
printf("Playing guess my number game\n");
printf("-------------------------------\n");
bool play = true;
int xtry = 0;
int totaltries = 0;
char answer;
do {
xtry = playgame();
numberofplays++;
totaltries = totaltries + xtry;
printf("Play again? (y for yes n for no): ");
answer = getchar();
if(answer =='n')
play = false;
} while(play==true);
average = (float)(totaltries/numberofplays);
printf("average is %f tries per game\n",average);
return 0;
}
int playgame(void) {
int guessnumber = 50;
int xnumber = 25;
int count=0;
char x;
bool stillguessing = true;
while(stillguessing == true) {
printf("is your number %d ?", guessnumber);
x = getchar();
if(x=='=') {
count++;
printf("Great!\n");
stillguessing=false;
return count;
}
else if(x == '<') {
guessnumber = guessnumber - xnumber;
xnumber = xnumber/2;
if(xnumber<1) xnumber = 1;
count++;
}
else if (x == '>') {
guessnumber = guessnumber +xnumber;
xnumber = xnumber/2;
if(xnumber<1) xnumber = 1;
count++;
}
}
}

The function getchar pulls a character from the stream stdin.
The stream stdin contains everything that you have entered into the Standard Input device; in your case, this is the keyboard.
Now, when you respond to the computer's guess, you press two keys. You press = and then Enter.
Your code in playgame handles the =, but it leaves the Enter on stdin... thus, your next call to getchar pulls that.
What you need to do is to flush the stdin stream. You can't use fflush(stdin) for this, as fflush is for output streams.
Instead, you can use something like
void flushSTDIN() {
while ((ch = getchar()) != '\n' && ch != EOF);
}
to clear out any old newlines in the buffer, before you ask your question.
You should do this before all calls to getchar in your program.
So:
flushSTDIN();
printf("is your number %d ?", guessnumber);
x = getchar();

Your problem is that getchar() is consuming a single character from the input. However, the input stream always contains at least two characters when you enter a response: the character you enter (such as '=') and the newline (or enter) character that follows it.
This does not matter so much in the playgame() function (although all of the prompts are printed twice), but when you get to
answer = getchar();
this call to getchar() gets the newline that was left over from the previous character you typed.
How you fix this is a question of how you want to handle user input - whether you want to validate it, whether you want to be able to enter longer strings, etc.
In your case, the simplest solution is to replace your calls to getchar() with a loop that will discard whitespace.
I suggest doing the following:
Add the following line at (or near) the start of your program:
#include <ctype.h>
This provides the isspace() function that cleanly and portably checks if a character is whitespace.
Replace the line:
answer = getchar();
with:
while (isspace(answer = getchar()))
;
And similarly, replace
x = getchar();
with:
while (isspace(x = getchar()))
;
The single semicolon is a null statement - something (in this case nothing) has to go in the body of the loop.
Assigning to x/answer within a condition would often be frowned upon, but in this particular case it is the most idiomatic way of writing this.
Note that incorrect macro implementations of isspace() could cause issues by evaluating the call to getchar() multiple times

Related

Query user to continue printing in C

I am writing a program that starts printing at 0.
It prints up to 15 and asks the user a y/n question.
if y that program prints next 15.
if n program stops.
The program I wrote does not work.
Help solving this.
int main()
{
int i=0,k=1;
char ans;
while(k=1)
{
i++;
printf("\n%d",i);
if(i%15==0)
{
printf("\nDo you want to continue?(y/n): ");
scanf("%c",ans);
ans = toupper(ans);
if(ans=='Y') {
continue;
}
else if(ans=='N') {
k=0;
}
}
}
}
----------------------------------EDIT-------------------------------------
changed the code as #Programmer400. Also 15-->3. Now my computer prints
1
2
3
Do you want to continue?(y/n): y
4
5
6
Do you want to continue?(y/n):
7
8
9
Do you want to continue?(y/n): y
First it prints till 3 and asks. After Y, it prints till 6 and asks and then without any input prints till 9 and asks. Note the missing y in the 2nd question.
I have provided a working C program below that performs the tasks you specified in your question.
I have taken an effort to stay true to the functions that you used in your original code sample and I have also taken care to only make additions (not remove code).
In the comments, I have explained lines of code that I have added that were not in your original code sample.
#include <stdio.h>
int main(void)
{
int i = 0, k = 1;
char user_input;
char ans;
while(k == 1)
{
i++;
printf("%d\n", i);
if (i % 15 == 0)
{
printf("Do you want to continue? (y/n/Y/N): ");
scanf(" %c",&user_input); // Keep the whitespace in front of the %c format specifier -- it's important!
getchar(); // Consume the newline character left in the buffer by scanf()
// Check if user input is already capitalized
if (user_input >= 65 && user_input <= 90)
// If it is, keep it capitalized
ans = user_input;
else
// If it isn't, capitalize it
ans = toupper(user_input);
if (ans=='Y')
{
// Allow the loop to continue
continue;
}
else if (ans == 'N')
{
// Inform the user that execution is ending
printf("Exiting loop... ending program.\n");
// Consider removing 'k' entirely, just use a 'break' statement
k = 0;
}
else
{
// Inform the user that the input was not recognized (if not y/n/Y/N...)
printf("User input not recognized... please provide input again.\n");
// Decrement 'i' so that the user is forced to provide input again...
i--;
// Allow the loop to continue
continue;
}
}
}
}
Helpful notes:
scanf leaves a newline character in the buffer when you are reading user input with character formatters. Namely...
%c, %n, and %[] are the 3 specified expectations that do not consume leading whitespace
-- From a comment on this StackOverflow answer.
Keep in mind that if you would like to exit your while loop, you could simply insert a break statement. This way, you don't have to change the value of k (which is rather ambiguous) to end the loop and the code is more readable because an explicit break statement is harder to misinterpret. In this simple case, the use of k is easily understood (so don't worry about it too much, for now).
If you ever intend to read string input from a user (i.e., an array of characters), then I would recommend that you use fgets() instead of scanf(). A discussion of the merits of fgets() in comparison to scanf() is provided in this StackOverflow answer. Further, it is important to recognize that even though you can use gets() to perform a similar operation it is highly dangerous and never advised. Check out the explanations provided by the top two answers to this StackOverflow question.
I tried changing your code so that it doesn't generate warnings, now it seems to "work" (but maybe it can be even more correct).
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
int main()
{
int i=0,k=1;;
char c;
char ans[] = "";
while(k==1)
{
i++;
printf("\n%d",i);
if(i%15==0)
{
printf("\nDo you want to continue?(y/n): ");
scanf(" %c",ans);
ans[0] = (char) toupper(ans[0]);
if(ans[0]=='Y') {
continue;
}
else if(ans[0]=='N') {
k=0;
}
}
}
}

skipped trouble with getchar and scanf [duplicate]

This question already has answers here:
scanf getchar function is skipped
(3 answers)
Closed 6 years ago.
I recently started to program in C and im having trouble with this code:
#include <stdio.h>
#include <stdlib.h>
#define PI 3.1416
int main () {
float x;
int y;
x = PI;
printf("Enter y: ");
scanf(" %i", &y);
printf("The new value of y is: %i.\n\n",y);
x = x * y;
printf("The new value of x is: %f.\n\n",x);
getchar();
return 0;
}
the problem appears with the getchar() at the end, the program shutdown and doesnt wait for the input. I have found a solution i dont like at all and is by adding 2 times getchar(). Is there any way around it?, im using ubuntu so system("pause") is not an option
The scanf command does not consume the Enter key that you pressed after entering y. So the getchar() happily consumes it.
One solution is to consume the rest of the input line after reading y; the code for that looks like:
int ch; while ( (ch = getchar()) != '\n' && ch != EOF ) {}
Although there are other options for pausing at the end of a program, this is probably a good idea anyway because it will be necessary if you later expand your program to expect string or character input.
A good general solution to this problem is to read input from the user using fgets, and then scan it with sscanf:
char ln[1024];
printf("Enter y: ");
fgets(ln, 1024, stdin);
sscanf(ln, "%d", &y);
You will still need to check the return values of fgets and sscanf for error conditions, but it is easier to handle line-oriented input this way.

Need help understanding while loops

Let's say that we have a very simple code that begins like:
#include <stdio.h>
int main() {
char c;
int x;
printf("Num here: ");
c = getchar();
x = 0;
while (c!=EOF) {
x = c - 48; //to convert x from ASCII
In this program, I'm trying to get the user to type a number (ex. 42) and am trying to add the ones digit to the tens (and to the hundreds, etc.); I'm having a lot of trouble understanding how you can get the while loop to go back to the loop until the end of the number.
So, I need a lot of help understanding how I can get the loop to read until the end of the character, read the char input the user puts in as a number (42), and then, treat the numbers individually using just getchar().
Normally, you'd use:
int c; // Because getchar() returns an int, not a char
int x = 0;
while ((c = getchar()) != EOF)
{
if (isdigit(c))
x = x * 10 + (c - '0');
else
...
}
This reads a character each time it reaches the top of the loop. You get the loop to go back by running into the brace at the end of the loop (or, occasionally, by using a continue statement). You might exit the loop with a break, for example if you read some character that can't be part of a number.
If the user types 42 (followed by Enter), then you first read c == '4' and then c == '2' and then you read newline '\n'. For every digit from '0' to '9', digit - '0' yields the number corresponding to the digit. The newline can't be part of the number, so you either put it back with ungetc(c, stdin) or break the loop when you've read it.
Beware of overflow if the user types 43219876543 where you expected just 42 (and int is a 32-bit quantity).
You could write the loop condition as:
while ((c = getchar()) != EOF && isdigit(c))
or even:
while (isdigit(c = getchar()))
I'd be extremely reluctant to actually put the latter into production code but it is, in theory, safe.
How could I treat each number individually so that I can use the entirety of the numbers later on? So that if the user types 10 20 30, I can multiply 10 by 20, then (10*20) by 30?
Wheels within wheels — or loops within loops. You'll need to specify your criteria a bit. If the user types 1 you want the answer 1; if they type 1 2, you want 2; if they type 1 2 3, you want 6; and so on (where these are all the numbers on a single line of input). You'll need an outer loop that skips over blanks and tabs, then uses the inner loop to read a number, and then multiplies the current product (initial value 1) by the new number, and after the outer loop, you'll print the product. This will print 1 for an empty line; maybe that doesn't matter (and maybe it does).
Here's some code that approximates what is appropriate:
#include <ctype.h>
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
{
int product = 1;
while (c != EOF && c != '\n')
{
while (isspace(c))
c = getchar();
int number = 0;
while (isdigit(c))
{
number = number * 10 + (c - '0');
c = getchar();
}
printf("Number: %d\n", number);
product *= number;
}
printf("Product: %d\n", product);
}
return 0;
}
I also tried a version with a slightly different 'skip' loop:
while (c != EOF && c != '\n' && !isdigit(c))
c = getchar();
Both work OK on sane inputs. Empty lines are treated as end of input; lines containing blanks are not. If you input 1a2b3c with the second condition, you will get the output 0; with the first, you get an infinite loop. There is no overflow protection; don't try doing factorial 20 and expect the correct answer (with 32-bit int). Tweak to your heart's content.
Your code :
#include <stdio.h>
#include<ctype.h>
int main() {
int c;//getchar() returns integer
int x;
printf("Num here: ");
x=0;
//As #Jonathan Leffler suggested ,
//usage of while loop like this is very helpful the moment you press Enter loop breaks.
while (isdigit(c = getchar())) //isdigit is a function from ctype.h checks for Entered character is digit or not
x = x*10 + c - 48; //here '0'==48
printf("%d",x);
}
when you enter 42
loop rotates two times for c==4 and c==2
c==4
x=0*10+'4'-48 //here '4'==52 ==> x=0+52-48 ==>x=4
c==2
x=4*10+'2'-48 //here '2'==50 ==> x=40+50-48 ==>x=42
to add ones digits to tens and then hundreds ... if you want to add digits in input number use this below while loop
int sum=0,num;
//read num
while(num>0)
{
sum=sum+num%10; //get the last digit and add to sum
num=num/10; //reduce last digit of num
}
Read in character by character and convert that to a numeral using the while loop in Jonathan's answer. Every time you read a numeral, simply multiple your current sum by 10, and add the number. That way by the time you read the last numeral and add it in, you'll have the correct number.
Sometimes the way we think a problem should be solved, can be solved in a different method when all of the languages capabilities are considered.
#include <stdio.h>
int main() {
int x;
printf("Num here: ");
scanf("%d", x);
}
implements the same functionality as your program.

Why does my program loop without receiving any new input?

I am trying to make is so that my program will start over once the answer is given. It just won't function again once I run it once. I want to make it functional to where the user doesn't have to start the program up again. Thanks!
#include <stdio.h>
#include <math.h>
int main()
{
float firstnum, secondnum, answer;
char function;
printf("\nHello and welcome to my calculator!\n"); //Intro
start: //Area to loop to when program completes
printf("\nPlease input the function you would like to use. These include +, -, *, /.\n"); //Asking for function input
scanf("%c", &function); //Receiving Function Input
printf("\nNow please input the two variables.\n"); //Asking for variables
scanf("%f", &firstnum);
scanf("%f", &secondnum); //Receiving Input for Variables
if (function == '+') //Doing calculation
{
answer = firstnum+secondnum;
}
else if (function == '-')
{
answer = firstnum-secondnum;
}
else if (function == '*')
{
answer = firstnum*secondnum;
}
else if (function == '/')
{
answer = firstnum/secondnum;
}
else
{
printf("Sorry that was an incorrect function. The correct inputs are +, -, *, /."); //If they don't follow the directions
}
printf("Your answer is %f \n", answer); //Answer
goto start; //Loop
return 0;
}
It's the [enter] key. Your first scanf is reading the enter key you pressed to terminate the previous iteration.
So you need to add another scanf("%c", &function); or getchar(); just before the goto to eat the newline.
When reading in numbers, scanf will eat any initial whitespace; but when reading characters, it won't. It gives you the very next byte in the stream.
A better way, perhaps, would be to tell `scanf` where to expect all the newlines. This way you don't need that *weird* mystery line that doesn't appear to do anything but isn't commented (!); because that's gonna cause problems when you play with this code again months from now.
//scanf("%c\n", &function); /* read a character followed by newline DOESN'T WORK */
...
//scanf("%f\n", &secondnum); /* read a number followed by newline DOESN'T WORK */
This way, trailing newlines are consumed. Which is, I think, the more intuitive behavior (from the User side).
Nope. Doesn't work. Wish it did, cause I'd look less foolish.
I'm not upset by the goto. It's nice to see an old friend. This is an appropriate use of it if ever there was one. It is exactly equivalent to the while form. So you should certainly be aware that most people will prefer to see while(1) because it tells you more about what's going on than label:. But for an infinite loop in a function smaller than a screen, why not? Have fun. No baby seals will be harmed. :)
This is why you use loops. (And try not to use goto for this).
#include <stdio.h>
#include <math.h>
int main() {
float firstnum, secondnum, answer;
char function, buffer[2];
while(1) {
printf("\nHello and welcome to my calculator!\n");
printf("\nPlease input the function you would like to use. These include +, -, *, /.\n");
scanf("%s", &buffer);
function = buffer[0];
printf("\nNow please input the two variables.\n");
scanf("%f", &firstnum);
scanf("%f", &secondnum);
if (function == '+') answer = firstnum+secondnum;
else if (function == '-') answer = firstnum-secondnum;
else if (function == '*') answer = firstnum*secondnum;
else if (function == '/') answer = firstnum/secondnum;
else printf("Sorry that was an incorrect function. The correct inputs are +, -, *, /.");
printf("Your answer is %f \n", answer);
}
return 0;
}
This should go in an infinite loop, so use an input from the user to break; the loop to exit the program
Note : I have replaced the scanf %c with %s indicating an input of a string & used a buffer.
scanf("%s",&buffer); function = buffer[0];
(Updated as per discussion in comments)
One "best practise" regarding scanf is to check it's return value. In regards to the return value of scanf, I suggest reading this scanf manual carefully and answering the following questions:
int x = scanf("%d", &foo); What do you suppose x will be if I enter "fubar\n" as input?
Where do you suppose the 'f' from "fubar\n" will go?
If it remains in stdin, would you expect a second scanf("%d", &foo); to be successful?
int x = scanf("%d", &foo); What do you suppose x will be if I run this code on Windows and press CTRL+Z to send EOF to stdin?
Would it be safe to use foo if x is less than 1? Why not?
int x = scanf("%d %d", &foo, &bar); What would you expect x to be if I enter "123 456\n" as input?
Do you suppose the '\n' will still be on stdin? What value would char_variable hold following scanf("%c", &char_variable);?
EOF can be sent through stdin in Windows by CTRL+Z, and in Linux and friends by CTRL+D, in addition to using pipes and redirection to redirect input from other programs and files.
By using code like int function; for (function = getchar(); function >= 0 && isspace(function); function = getchar()); assert(function >= 0); or char function; assert(scanf("%*[ \n]%c", &function) == 1); you can discard leading whitespace before assigning to function.

stopping `scanf` when user enters "." DOT

I am messing around with the function below, I want to end input capture when user enters a DOT character. It seems that getche() is not doing what it is intentended to do:
void Encode(FILE *fp)
{
char chWord[100];
char *chP;
printf("Enter a word or a sentence, close it by a \".\"\r\n");
scanf("%s",chWord);
if (chWord != '.')
{
for (chP = chWord; *chP != '\0'; chP++) //to print each digit till end of string \0
{
printf("%d ",*chP+10);
fprintf(fp, "%d ",*chP+10);
}
}
}
UPDATE
It seems that I was not clear enough. What I am trying to do is when user enters a DOT it should act like pressing ENTER key so the program goes to next step. Some sort of simulating ENTER key.
if (chWord != '.')
should be
if (*chWord != '.')
you are comparing a char pointer to a char instead of a char to another char.
be aware that the way this code is written the input ".123" will skip the printing segment. not sure if this is desireable to you or not.
The scanf family of function accept a (negative)character set as a format specifier.
You can do scanf("%[abc]", chWord); to accept only strings composed of the letters abc.
And you can also specify which characters not to accept. So scanf ("%[^.]", chWord); will accept a string composed of anything but a dot.
Edit
I forgot to mention, that the dot will remain in the input stream buffer, so to read and ignore it during the scanf itself (rather than flush the buffer or do a getchar), just add it to the end of the format string. I.e.:
scanf ("%[^.].", chWord);
OK, backing out that whole Answer based on your update...
The answer is no, there is no way to do what you want to do with scanf, or anything in standard C for that matter. What you're trying to do is platform (and possibly compiler) specific.
If you want to treat the '.' as a enter key press you have to do the magic yourself. So, since you didn't mention if you were using any specific OS or compiler I'll give you the first example that comes to mind.
This works with Windows MS VS:
#include <Windows.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
char key = 0;
int counter = 0;
char chWord[100] = {0};
while(counter < 100) {
while(!_kbhit()) { //While no key has been hit
Sleep(1); //Sleep for 1 ms
}
key = _getch(); //Get the value of the key that was hit
if(key == '.') //if it was a .
break; //act as if it were an "enter" key and leave
else
chWord[counter] = key;
counter++;
}
chWord[99] = '\0';
printf("The string was %s\n", chWord);
return 0;
}

Resources