I've got a simple C program, which loops to get an indefinite amount of numbers from the user (it's a CAS of sorts). I'm working on the program in multiple languages, and while the C++ version works perfectly, the C version stalls at the end of the loop, when the program asks for another user operation, requiring the user to input the operation twice. Here's how the program should work:
Enter an operation
4+2
6
6+2 // User adds 2 to the previous answer
8+x // User can continue adding like this indefinitely
Instead, here's what happens:
Enter an operation
4+2
6+2
// nothing happens until user enters "+2" again
+2
8+x
+x
[sum of 8+x]
and so on.
I initially thought this pause was caused by the program asking for user input twice, once at the start of the loop, and then at the end before looping. I put an iteration counter in the loop to determine what kind of input the program should get (either &num1,&op,&num2 or &op,&num2). For some reason, that didn't make a difference. Here's the relevant part of the code:
int opnubmer;
opnumber = 0;
printf("Enter an operation\n");
while(op != '=')
{
if (opnumber == 0)
{
scanf("%d%c%d",&num1,&op,&num2);
}
else if (opnumber != 0)
{
scanf("%s%d",&op,&num2);
}
switch(op)
{
case '+':
num2 += num1;
break;
case '-':
num2 -= num1;
break;
case '*':
num2 *= num1;
break;
case '/':
num2 /= num1;
break;
default:
printf("%s%c%s", "Unknown op: ", op, "\n");
exit(1);
}
printf("Solution: ");
printf("%d",num2);
opnumber++;
num1=num2;
}
Can anyone help me out?
It looks like you made a typo in the second scanf call, where you used %s instead of %c to read the op.
Furthermore, when using scanf to read input, you have to be very careful with whitespace. Trailing whitespace (including newlines) is left on the input stream, so the next time you read from the input stream, the whitespace is the first thing it'll see.
Instead of using scanf, use fgets to read the input one line at a time into a buffer, and then parse what you need out of that buffer. Eg. :
char line[256];
fgets(line, sizeof(line), stdin);
sscanf(line, "%d%c%d", &num1, &op, &num2);
It behaves absolutely fine, when you are not in the first iteration, you are looking for a string, even if you fix it with a change to %c your program expects only a character and a number not a number character number sequence.
Related
I have to finnish a college project, and a part of my code is acting strangely.
The goal of that part is to get an user input of an integer and store it in a variable so that i can use it later, however if the user inputs a character I have to ask for the number again.
I used the scanf function to get the user input and put it inside a while loop to continuously ask for the input in case it's invalid.
The problem is that when a user inputs a character, the code freaks out and starts running the while loop without stopping in the scanf to get the user input.
It makes sense that the loop condition is always true but the strange part is that it doesn't stop to read new inputs.
I deconstructed my code in order to replicate the problem to make it easier to debug.
I know that there are some useless variables but in my original code they are useful, I just kept them there to make it look similar to the original.
I can only use scanf to get user input, despite knowing them, in this project I am only allowed to use scanf. I can't use scanf's format to get characters, only numerical types are allowed in this project.
C11 is the version of the standart we are using in classes.
I'm sory if the solution for this is a dumb thing, I'm not good at C and I'm having some difficultlies this semester...
Thanks in advance.
while (!verification) {
printf(">>>"); //write values in here
check = scanf("\n%d", &var); //input a number and store the number of valid inputs
if (check) verification = 1; //if the input is a number then the while condition should turn to false with this statement
printf("var = %d, check = %d, verification = %d\n", var, check, verification); //printing all variables
}
If the user does not input an integer there are characters left in the input stream after the call to scanf. Therefor you need to read to end of line before making the next attempt to read an integer. Otherwise scanf will try to read the same non-integer characters again and again. Here is an example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ch, i, n;
n = scanf("%d", &i);
while (n == 0) {
fprintf(stderr, "wrong input, integer expected\n");
do {
ch = getchar();
} while ((ch != EOF) && (ch != '\n'));
n = scanf("%d", &i);
}
if (n == 1) {
printf("%d\n", i);
} else { /*n == EOF*/
fprintf(stderr, "reading input failed\n");
exit(EXIT_FAILURE);
}
return 0;
}
Don't use scanf() to read input from the user.
It's really only meant for reading data that's known to be in a particular format, and input from a user... often isn't.
While you do correctly check the return value of scanf("%d"), and could fix the case where the input isn't a number, you'll still have problems if the input is either an empty line, or a number followed by something else (123 foobar).
In the case of an empty line scanf() will continue waiting for non-whitespace characters. This is probably confusing, since users will expect hitting enter to do something.
In the case there's trailing stuff after the number, that stuff stays in the input buffer, and the next time you read something, it gets read. This is again probably confusing, since users seldom expect their input to one question to also act as input to another.
Instead, read a full line with fgets() or getline(), then run sscanf() or strtol() on that. This is much more intuitive, and avoids the disconnect caused by scanf() consuming input lines only partially (or consuming more than one line). See also e.g. scanf() leaves the new line char in the buffer
Here, using getline() (POSIX, even if not in standard C. Use fgets() instead if getline() is not available):
#include <stdio.h>
int main(void)
{
char *line = NULL;
size_t len = 0;
int result;
printf("Please enter a number: ");
while (1) {
if (getline(&line, &len, stdin) == -1) {
/* eof or error, do whatever is sensible in your case */
return 1;
}
if (sscanf(line, "%d", &result) != 1) {
printf("That didn't seem like number, please try again: ");
continue;
}
break;
}
printf("You entered the number %d\n", result);
}
The problem is you must discard offending input when the conversion fails.
Here is a simple solution using only scanf() as instructed:
#include <stdio.h>
int main() {
int n;
for (;;) {
printf("Enter an number: ");
switch (scanf("%d", &n)) {
case 1:
/* successful conversion */
printf("The number is %d\n", n);
return 0;
case 0:
/* conversion failure: discard the rest of the line */
scanf("*[^\n]"); // discard characters before the newline if any
scanf("*1[\n]"); // optional: discard the newline if present
printf("Invalid input. Try again\n");
continue;
case EOF:
/* input failure */
printf("Premature end of file\n");
return 1;
}
}
}
I've got a program here which contains a do-while loop within a specified void method. I'm trying to exit the loop within the function, so that the do-while loop actually works as it is supposed to. Except after I run the program and one of the cases occurs, the program continues to run despite my while statement stating that it should only work while(userInput != 1).
I cannot use global variables to solve this problem, as my assignment limits me on using such techniques, thus any help would be much appreciated!
Here is a snippet of my code:
void functionTest()
{
int gameOver = 0;
int userInput;
do
{
printf("please enter a number 1-3");
scanf("%d",&userInput);
switch(userInput)
{
case 1:
printf("You entered %d",userInput);
gameOver = 1;
break;
case 2:
printf("You entered %d",userInput);
gameOver = 1;
break;
case 3:
printf("You entered %d",userInput);
gameOver = 1;
break;
}
}
while(gameOver!= 1);
}
}
The problem probably lies when you use scanf(). Something that you're inputting before hitting enter is not 1, 2 or 3. Could you tell us exactly what you type when it asks you to enter a choice?
Sometimes, the standard output needs to be flushed before using a fresh scanf(). Try fflush(stdout) before the scanf line.
See older question 1 and older question 2.
EDIT:
I can reproduce the problem easily enough if I enter anything apart from "1","2" or "3"...
I would suggest, you do the following before executing the switch statement:
Add fflush(stdout) before scanf()
Accept the input as a string (%s) instead of a number. (char [] needed)
Trim the string of trailing and leading white spaces.
Convert to number using a library function
Then switch-case based on that number
The problem is that if other characters (that aren't part of an integer) are present in the input stream before an integer can be read, scanf() fails and unusable data is never cleared out... which leads to an infinite loop (where scanf() repeatedly fails to read the same characters as an integer, over and over).
So you need to read off the invalid characters when scanf() fails, or as part of the format.
A simple fix would be to change your scanf from:
scanf("%d",&userInput);
to:
scanf("%*[^0-9]%d",&userInput);
to read (and discard) any characters in the input stream that aren't digits 0-9 before reading your integer... but that still doesn't check whether scanf fails for any other reason (like a closed input stream).
You could replace it with something like this:
int scanfRes,c;
do {
scanfRes = scanf("%d",&userInput); /* try to read userInput */
/* ..then discard remainder of line */
do {
if ((c = fgetc(stdin)) == EOF)
return; /* ..return on error or EOF */
} while (c != '\n');
} while (scanfRes != 1); /* ..retry until userInput is assigned */
..which will retry scanf() until the field is assigned, discarding the remainder of the line after each attempt, and exiting the function if fgetc() encounters an error or EOF when doing so.
I'm writing code that, when called from the command line, is redirected a file. The lines of the file (which are sent over stdin) are parsed and read. I want to be able to call a function and have it scan an int, but it seems that there are issues with residual data in scanf (I don't actually know if that's the issue, but that's all I can think of). Here is my code:
dataSetAnalysis(data, experiments);
int selection;
while(1){ //always true. The loop only breaks when the user inputs 4.
printf("DATA SET ANALYSIS\n"
"1. Show all the data.\n"
"2. Calculate the average for an experiment.\n
"3. Calculate the average across all experiments.\n
"4. Quit.\n"
"Selection:__");
switch(selection){
case 1:
displayAll(d,e);
break;
case 2:
individualAverage(d,e);
break;
case 3:
allAverage(d);
break;
case 4:
exit(0);
}
scanf("%d", &selection);
}
And this is the second half of the main method.
while(fgets(currentLine, 20, ifp) != NULL){ //while there is still data in stdin to be read
experiments[i] = currentLine; //experiment[i] points to the same value as current line. Each value in experiments[] should contain pointers to different positions in the allocated buffer array.
currentLine += 20; //currentLine points 20 characters forward in the buffer array.
int j = 0; //counter for the inner while loop
while(j<10){ //while j is less than 10. We know that there are 10 data points for each experiment
scanf("%d ", &intBuffer[j]);
data[i][j] = intBuffer[j];
j++;
}
numExperiments++; //each path through this loop represents one experiment. Here we increment its value.
i++;
}
The program loops infinitely when reaching the while loop in dataSetAnalysis() and continues printing "DATA SET ANALYSIS...." without ever stopping to accept more input over stdin. Is the problem with scanning to the selection variable?
The problem is that your stdin is not clear, You have to clear your input buffer by iterating till you find an '\n' or an enter hit.
Try use this
while('\n' != getchar())
{ }
just before you scanf , it will get rid of the infinite loop
something like
while('\n' != getchar())
{}
scanf("%d", selection);
The first and fundamental rule is 'always check the return value from an input function' (such as scanf()). They always return some indication of whether they were successful or not, and if they're unsuccessful, you should not use the values that would have been set had the function call been successful.
With scanf() et al, the correct way to use the function is to test that you got the expected number of values converted:
if (scanf("%d", &intBuffer[j]) != 1)
…handle error…
You also have the format string: "%d " in the code. That doesn't stop until you type a non-white space character after the number. This is confusing, but any white space (blank, tab, newline) in a format string means read optional white space, but the function only knows when it has finished reading white space when a non-white space character is entered.
Using a very simple calculator program that prompts a user for an operation to perform, followed by a prompt for two integers on which to perform this operation. The program is supposed to loop after these operations, except in the case where the user enters the character 'q', at which point the program is supposed to quit.
#include <stdio.h>
int main (void)
{
char c;
int number[2], num1, num2, result;
double num1d, num2d, resultd;
int done=1;
while(done)
{
printf("\t What sort of operation would you like to perform? \n \t Type + - * / accordingly. \n");
c = getchar();
printf("\tplease enter a number \n");
scanf("%d",&number[0]);
printf("\tplease enter another number \n");
scanf("%d",&number[1]);
num1 = number[0];
num2 = number[1];
switch(c)
{
case('-'):
result = num1-num2;
printf("\nThe first number you entered subtracted by the second number is %d.\n", result);
break;
case('+'):
result = num1+num2;
printf("The first number you entered added to the second number is %d.\n", result);
break;
case('*'):
result = num1*num2;
printf("The first number you entered multiplied with the second number is %d.\n", result);
break;
case('/'):
num1d = (double) num1;
num2d = (double) num2;
resultd = num1d/num2d;
printf("The first number you entered divided by the second number is %g.\n", resultd);;
break;
case('q'):
printf(" Now Exiting...\n");
done=0;
break;
default:
puts("Invalid key pressed. Press q to exit");
break;
}
}
return 0;
}
Works correctly for a single calculation, but subsequently performs oddly; in particular it prints
printf("\t What sort of operation would you like to perform? \n \t Type + - * / accordingly. \n");
printf("\tplease enter a number \n");
altogether.
The standard method of clearing the input buffer while (getchar() != '\n'); doesn't fix this. One out of two times that this text displays incorrectly the user can still use the program as if the instructions were displaying as they should (so the user can type an operation such as +, carriage return, and then some integer and a carriage return, and the program will perform correctly from that point on) Every other time however the program will put "Invalid key pressed. Press q to exit" regardless of input.
What everyone else here is saying is true, getchar() returns an int but that's not your problem.
The problem is that getchar() leaves a newline character after you use it. If you're going to use getchar() you must always consume the newline char afterwards. This simple fix:
printf("\t What sort of operation would you like to perform? \n \t Type + - * / accordingly. \n");
c = getchar();
getchar(); //<-- here we do an extra getchar for the \n
printf("\tplease enter a number \n");
scanf("%d",&number[0]);
printf("\tplease enter another number \n");
scanf("%d",&number[1]);
and that will eliminate the problem. Every time you type <somechar><enter> it's really putting two characters on the buffer, for example if I hit + and enter I'm getting:
'+''\n' // [+][\n]
getchar() will only get the first of these, then when getchar() is called again it won't wait for your input it will just take that '\n' and move on to the scanf()
You shouldn't mix character-by-character with more high-level input functions such as scanf(). It's better to use scanf() to input the command character too, but of course then you will have to press enter after the command. I believe this it the root cause of your problems.
As an aside, note that getchar(), despite it's name, returns int, not char. This is because it can return EOF which is a special constant whose value is different from that of all characters.
Further, you should always check the return value of I/O functions like scanf(), they can fail if the input doesn't match the pattern string.
As a debugging hint, you can of course print the value of c before interpreting it, so you can easier see and understand the flow of the program.
I'm guessing it works the first time, but not the next time. This is because the scanf calls leaves the newline in the input buffer so the next time getchar is called in the loop it will return the newline character. Add a space after the format in the scanf calls
scanf("%d ",&number[0]);
and it will discard remaining whitespace from the buffer.
Use a debugger to step through the code and check the variables to verify.
Your getchar should return int. The reason is as below
getchar reads characters from the program's standard input
and returns an int value suitable for storing into a char.
The int value is for one reason only: not only does getchar
return all possible character values, but it also returns an
extra value to indicate that end-of-input has been seen.
The range of a char might not be enough to hold this extra value,
so the int has to be used.
So basically you need to change char c to int c in your code
I wrote a solution to an exercise that asks to write a program that acts as a simple "printing" calculator, and also detects division by zero and checks for unknown operators.
The program works as intended when expected operators are entered. For example:
"100 S" prints "= 100.000000"
"2 /" prints "= 50.000000"
"10 *" prints "= 500.000000"
It also detects division by zero and unknown operators.
However, when I enter operators in wrong order, like this:
"/ 2" or "* 10", the program is stuck in a loop.
How do I fix this bug so that when the operators are entered in wrong order, it just prints "Unknown operator"?
// Write a program that acts as a simple "printing" calculator
#include <stdio.h>
int main (void)
{
float acc, b;
char operator;
printf ("Begin Calculations\n");
while ( operator != 'E') {
scanf ("%f %c", &b, &operator);
switch (operator)
{
case 'S': // set accumulator
case 's':
acc = b;
printf ("= %f\n", acc);
break;
case 'E': // end program
case 'e':
printf ("= %f\nEnd of Calculations.\n", acc);
break;
case '+':
printf ("= %f\n", acc += b);
break;
case '-':
printf ("= %f\n", acc -= b);
break;
case '*':
printf ("= %f\n", acc *= b);
break;
case '/':
if ( b == 0 )
printf ("Can't divide by zero.\n");
else
printf ("= %f\n", acc /= b);
break;
default:
printf ("Unknown operator.\n");
break;
}
}
return 0;
}
Update: I've found a solution
while ( operator != 'E' && operator != 'e' ) {
if ( scanf ("%f %c", &b, &operator ) < 2 ) {
printf ("Error. You need to enter a number.\n");
break;
}
else {
switch (operator)...
The result of scanf is the number of fields assigned. If scanf returns 0, it will return 0 for the same format string every time you call it. Because scanf pushes back the last character it read that does not match the input sequence (%f), it will repeatedly try to convert the same string over and over.
That's why you loop infinitely. You might want to check the result of scanf. If it's less than 2, error out.
I think you would need to make your input routine more robust than scanf (apparently) is. For example, if you read your input in whole lines, you can parse them (say, using sscanf) to get the components w/o mucking up the input stream.
scanf is reading until it can parse a floating point number. Try using gets to read in a string and then parse that string from there.
http://www.cplusplus.com/reference/clibrary/cstdio/gets/
I guess that to exit you need to enter a float + 'E' (0.0 E) and not just 'E'. Would that be what you're asking about?
Ah! I see you mentioned placing things backward. Yes. scanf() is never going to detect that.
If you're under Linux, check out lex and yacc (or flex and bison to be precise.) To do things like these, it's a lot better and you can make things a lot better (support parenthesis, minus and plus operator, instead of just add and subtract, etc.)
It's not "stuck in a loop", it's waiting for the operator that this line:
scanf ("%f %c", &b, &operator);
promises. That line reads until it receives a floating-point number, and then it reads an operator. If you give it an operator first, it will simply ignore it.
(By the way, you should initialize operator to something specific before getting to the line while ( operator != 'E') {, because for all you know, operator might happen to start out as 'E'. Also, as Mysticial says, operator isn't a great name for a C identifier, because of its uses in C++.)
The problem is that scanf() is trying to read what you told it to, that is, a floating point number and a character. When you type the other way around scanf returns because its not the format you told it too, but unfortunately it WONT flush the buffer, so the while would go again and scanf tries to read again, and so on.
Drop scanf, although if this is only for a homework you may try doing:
if (!scanf ("%f %c", &b, &operator)) {
scanf ("%*[^\n]"); /* TRY to flush stdin */
printf("Incorrect input!");
incorrect_input++;
continue;
} else {
incorrect_input = 0;
}
if (incorrect_input > 5) {
break; /* Very simple measure to avoid getting stuck in the loop */
}
However, when I enter operators in wrong order, like this: "/ 2" or "* 10", the program is stuck in a loop.
How do I fix this bug so that when the operators are entered in wrong order, it just prints "Unknown operator"?
You might want to read the entire expression and then parse it for correctness. There are various expression notation methods (infix, postfix (also known as reverse polish notation) and prefix (otherwise known as polish notation)) which makes the task of validating and evaluating them easier.
Also if you have or can get hold of the "The C Programming Language" book written by Dennis Ritchie and Brian Kernighan, turn to chapter 4 and read the section that walks you through the design and implementation of a calculator program.