Why is the following program stuck in a loop? - c

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.

Related

Switch function directly goes to default. What's the issue?

I am new to C and am writing a simple code of converting temperatures. The code is still incomplete but still should give me some output
#include<stdio.h>
void main()
{
float temp;
char choice;
printf("\n 1. Celcius to Farenhite\n 2. Farenhite to Celcius\n What do you want to convert from? : ");
scanf("%c", &choice);
switch (choice)
{
case 1:
printf("Enter temperature in Celcius: ", temp );
scanf("%f", &temp);
break;
case 2:
printf("Enter temperature in Farenhite: ", temp);
scanf("%f", &temp);
break;
default:
printf("Invalid Choice");
break;
}
}
When I run this it asks "what do you want to convert from?" and shows the options. But when I enter 1 or 2, it directly prints and shows "Invalid Choice".
Pls tell me what's wrong :(
1 is 'int' and not a char.
1 and '1' are different.
This is the edited code
#include<stdio.h>
void main()
{
float temp;
char choice;
printf("\n 1. Celcius to Farenhite\n 2. Farenhite to Celcius\n What do you want to convert from? : ");
scanf("%c", &choice);
switch (choice)
{
case '1':
printf("Enter temperature in Celcius: ", temp );
scanf("%f", &temp);
break;
case '2':
printf("Enter temperature in Farenhite: ", temp);
scanf("%f", &temp);
break;
default:
printf("Invalid Choice");
break;
}
}
The number one is not the same as the digit "1". You are entering the character "1" and your switch statement is checking for the number one.
The number one is how many hearts I have. It can be written with the digit '1' but any number of other ways.
The digit '1' is a character. It is sometimes use to represent the number one but can also be used for other things. A variable of type char can hold the digit 1 since digits are characters.
Your switch statement is checking for the number one. You want to check for the character 1.
'1' is a character, whereas 1 is an integer. Your switch statement can't find a case to match with, hence it goes to default.
Is that the complete code? You're not converting anything here, you're only asking the user for the temperature and storing it in a variable.
OT: Indent properly, your code is messy and difficult to read. And do not use scanf for taking input. You may want to check out this link http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html.
This is a common misunderstanding for novices and occasional typo for experienced programmers(*).
1 means "the integer value one" (it is the integer literal for the value of 1).
Assuming your on an ASCII compatible platform(**) that is the character with ASCII code 1 (the non-printing character called Start of Header - SOH).
The ASCII Code for the character 1 is actually 49. But you should write:
case '1':
Because those apostrophes identify the 1 as the character representing 1 not the numeric value of 1.
The compiler will interpret '1' as actually meaning character of 1 meaning the (codepoint) value of 49.
In C char has a deeply dual role as a numeric type and as the smallest unit of text and accidental mixing of those roles causes endless confusion.
Arguably char has 3 roles. The smallest arithmetic type, the smallest unit of text (a character) and the unit of addressable memory (byte).
There are historical reasons why those roles are conflated in C.
(*) But I can't find a good answer for it even though there should be thousands of times this has been asked.
(**) C does not specify a character set but if you working on a platform that isn't ASCII compatible you will know about it. Unless you've found something in your Grandparent's basement and they're sadly not around to explain it. This footnote exists for the likely comments to the effect that C doesn't specify a character set.
Your program reads a byte from stdin and compares that to the values 1 and 2. It is unlikely the user can type these byte values as they correspond to control characters CtrlA and CtrlB1. The byte values representing the digits 1 and 2 typed by the user are noted in C as '1' and '2'. These are called character constants and are int values for the encoding of the corresponding characters.
Furthermore, you should:
indent your code more consistently.
define main with a return type int
test the return value of scanf()
fix the spelling of Fahrenheit, named after German physicist Daniel Gabriel Fahrenheit and Celsius, named after Swedish astronomer Anders Celsius.
1: From a unix terminal, one can actually enter these byte values by hitting CtrlV CtrlA and CtrlV CtrlB, respectively, followed by Enter.
Here is a modified version:
#include <stdio.h>
int main() {
float temp;
char choice;
printf(" 1. Celsius to Fahrenheit\n"
" 2. Fahrenheit to Celsius\n"
" What do you want to convert from? ");
if (scanf(" %c", &choice) != 1)
return 1;
switch (choice) {
case '1':
printf("Enter temperature in Celsius: ", temp);
if (scanf("%f", &temp) != 1)
return 1;
printf("%g degrees Celsius is %g degrees Fahrenheit\n",
temp, 32 + temp * 9 / 5);
break;
case '2':
printf("Enter temperature in Fahrenheit: ", temp);
if (scanf("%f", &temp) != 1)
return 1;
printf("%g degrees Fahrenheit is %g degrees Celsius\n",
temp, (temp - 32) * 5 / 9);
break;
default:
printf("Invalid choice\n");
break;
}
return 0;
}

Why is my program not working when I change the order of inputs? [duplicate]

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed last year.
I started learning C and tried to code this math program using switch statements. The program runs and works just fine when I scan the operator first and then scan the numbers. But if I switch the order of the scanf functions to take the numbers first and then the operators, the program takes the number but after that it does not take the second input (the operator) and just prints the default value (invalid input). Why is this happening?
I have provided the code (if I run this code, the problem occurs with the program just taking the numbers and not taking the operators. But of the order is flipped, it works).
#include <stdio.h>
int main()
{
float a, b, result;
char operator;
printf("Enter 2 numbers:");
scanf("%f %f", &a, &b);
printf("Choose a math operator (+, -, *, /):");
scanf("%c", &operator);
switch (operator)
{
case '+':
result = a + b;
break;
case '-':
result = a - b;
break;
case '*':
result = a * b;
break;
case '/':
result = a / b;
break;
default:
printf("\nInvalid operator");
return -1;
}
printf("%f", result);
return 0;
}
The format string "%c" will read the newline character from the first line of input. What you want instead is " %c" which will skip leading whitespace, so replace the line
scanf("%c", &operator);
with
scanf(" %c", &operator);
See also https://pubs.opengroup.org/onlinepubs/9699919799/
A directive composed of one or more white-space characters shall be
executed by reading input until no more valid input can be read, or up
to the first byte which is not a white-space character, which remains
unread.
you need to change
scanf("%c", &operator);
to
scanf("%s", &operator);
it will run.

C calculator program keeps giving error when I input "sine"?

Hi I am new to programming and have been working on a calculator for a while now. I am trying to add some trig functions in and I am having trouble with sine. The other functions work (+, -, *, /) but when I put in "sine" it skips to the part of the code where it says it is an incorrect function. Please help out with my code. Thanks!
#include <stdio.h>
#include <math.h>
int main()
{
float firstnum, secondnum, angle, answer, pi;
char function, sine;
pi = atan(1.0)*4;
printf("\nHello and welcome to my calculator!\n");
while(1)
{
printf("\nPlease input the function you would like to use. These include +, -, *, /, sine.\n");
scanf("%s", &function);
switch(function)
{
case '+':
printf("\nNow please input the two variables.\n");
scanf("%f", &firstnum);
scanf("%f", &secondnum);
answer = firstnum+secondnum;
break;
case '-':
printf("\nNow please input the two variables.\n");
scanf("%f", &firstnum);
scanf("%f", &secondnum);
answer = firstnum-secondnum;
break;
case '*':
printf("\nNow please input the two variables.\n");
scanf("%f", &firstnum);
scanf("%f", &secondnum);
answer = firstnum*secondnum;
break;
case '/':
printf("\nNow please input the two variables.\n");
scanf("%f", &firstnum);
scanf("%f", &secondnum);
answer = firstnum/secondnum;
break;
case 'sine':
printf("\nPlease enter the angle.\n");
scanf("%f", &angle);
answer = sin(angle);
break;
default: printf("Sorry, that is an incorrect function. The only available choices are +, -, *, /, sine.");
break;
}
printf("Your answer is %f \n", answer);
printf("\nWhen you are ready to quit, simply press Ctrl + C or just hit the X button in the top right.\n");
}
return 0;
}
'sine'
That is a multi-character literal. function is a single character. It's integral value is checked in the switch statement. You will likely never be able to consume a single character from the user which matches sine in the way that you are attempting to do so. Read a string (a char*) instead.
From the standard:
C99 6.4.4.4p10: "The value of an integer character constant containing more than one character (e.g., 'ab'), or containing a character or escape sequence that does not map to a single-byte execution character, is implementation-defined."
C does not have a first class string type. This means that you cannot use a switch statement for strings, you will need to use functions such as strlcmp for string comparison.
Depending on your objective (either making a calculator, or learning C) it might be wise to either switch to a different language with higher abstraction levels, or start with lower level exercises from a good C textbook.
Also, please be aware that working with strings and user input correctly in C, that is without security holes, is much more difficult than it would seem at first. If your objective is learning a language perhaps learning C++ is a better bet where you have std::string to handle your comparisons and iostreams to handle your input and output.

Program pauses at loop

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.

getchar not working in switch case (c)

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

Resources