how to stop this code from hanging at wrong inputs? - c

I am learning C from ' programming in C' by Stephen Kochan. I am working on exercise no 4 of chapter 6 , writing a code that acts as a simple accumulator calculator. code is following. it works fine as long as inputs are provided in the right manner order.
#include<stdio.h>
int main(void)
{
float num, accum = 0;
char operator;
while(1)
{
printf("Enter the number and the operator ");
scanf("%f %c",&num, &operator);
if (operator == 'E') break;
switch (operator){
case 'S':
accum = num;
printf("= %g\n",accum);
break;
case '+':
accum = accum + num;
printf("= %g\n",accum);
break;
case '-':
accum = accum - num;
printf("= %g\n",accum);
break;
case '*':
accum = accum * num;
printf("= %g\n",accum);
break;
case '/':
accum = accum / num;
printf("= %g\n",accum);
break;
}
}
printf("= %g\n",accum);
printf("End of Calculation\n");
return 0;
}
but it hangs on the wrong inputs. what can be done to check such behaviour?

The short version is "don't use scanf()."
The problem is that scanf() provides only a limited indication of error, and leaves the erroneous data unread tp be picked up by the next call; especially if you're not bothering to do error checking, it's just going to spin forever on the bad data.
Always check the return code, so you know if it worked or not.
If you're doing line oriented input, use fgets() or similar to read an entire line, and sscanf() to parse from the line.
Do something sensible if the input isn't what you expected, instead of just barreling on through. (Your existing code just assumes it's always valid.)

Dont use scanf. Thats the first sight suggestion for this program. Use something like getchar like shown here They are dealing with the same problem as yours.

Check that scanf() returns 2, indicating that it has populated both arguments
Provide a default case in the switch statement that reports an error.
For increased robustness, you might want to read the whole line using fgets() (don't use gets() because it is vulnerable to buffer overflow) and parse the result using sscanf(). This is only necessary if you want to provide recovery from bad inputs. Otherwise, just stick with scanf() and exit(1) (and an error message) if anything goes wrong.

Related

Got an segment error and not sure what causes it

#include <stdio.h>
int main () {
int vIn_a, vIn_b, vIn_c;
char vOperator;
printf("Please enter a number\n");
scanf("%d", vIn_a);
printf("Please enter a number\n");
scanf("%d", vIn_b);
printf("Please enter a Operator\n");
scanf("%c", vOperator);
switch(vOperator){
case '+':
vIn_c = (vIn_a + vIn_b);
break;
case '-':
vIn_c = (vIn_a - vIn_b);
break;
case '/':
vIn_c = (vIn_a / vIn_b);
break;
case '*':
vIn_c = (vIn_a * vIn_b);
break;
}
printf("Result: %d %c %d = %d", vIn_a, vOperator, vIn_b, vIn_c);
return 0;
}
Just trying to figure this out, i ran gdb. But not sure what my debugger is telling me at this point. Maybe im overlooking it?
Debugger: Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7c60d36 in ?? () from /usr/lib/libc.so.6
So what is causing this segmentation fault guys? Im learning C and im lost.
Thanks in advance.
When you use scanf(), you don't pass the variable into which you want to store the value, you pass a pointer to the variable.
So, for instance, instead of scanf("%d", vIn_a);, you need scanf("%d", &vIn_a); - note the '&'!
The effect of the scanf() calls, as you wrote them, was to pass an arbitrary number (whatever random content was in the uninitialised vIn_a and vIn_b) into scanf(). It treated those random(ish) integer values as pointers. So when it wrote the user-contributed value into the "pointer" it has been passed, it had the effect of:
*(int *)vIn_a = user_entered_value;
If you know your way around pointers, you'll know this is a recipe for disaster!
There are two more gotchas:
Your '/' operator doesn't check whether its divisor (vIn_b) is zero, so it would be easy to crash with a divide-by-zero error if the user selected zero for vIn_b and '/' for the operator.
You don't have a default: clause in your switch statement, so if the user types something other than the operator characters you're checking for, vIn_c will contain random rubbish as it's uninitialised by the time it's printed.
You can use scanf function with &. For example; scanf("%d", &vIn_a);
For documentation : https://cplusplus.com/reference/cstdio/scanf/

Switch Statement Not Executing Cases (c)

I made a switch statement, however, it only works with constants already set. If I try to use it with user input, only one of the cases work, every other one doesn't. Now no matter what I enter, it always uses the default case. I tried adding another getchar() to clear the \n character from the buffer but this isn't making a difference. Ill post the entire switch statement here :
char option=' ';
option=getchar();
switch(option){
//Parallel resistance calculations
case 'p':
CLEAR
//PResistance();
printf("RESISTANCE");
getchar();
break;
//Ohm's Law calculations
case 'o':
CLEAR
printf("OHM");
//Ohm();
break;
//Exits program
case 'q':
printf("Good bye! Stay safe in the laboratory! :)\nPress any key to exit");
getchar();
exit(0);
break;
//Error checking
default :
printf("Invalid input, Try again");
break;
}
}
while (option!='q');
I commented out the functions so I could use the print statements to test if its working.
Whenever you input a character or string from stdin in C, always make sure there is no \n in the input buffer. To do this, always getchar() after taking integer or float inputs.
In your case, maybe you've inputted an integer before inputting the character. So try to write a getchar() before taking the character input.

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.

gets() inside switch being ignored

Can someone tell me why the gets in the case 1 is being completely ignored?
// #define M 50 is at the top
char product[M] = {0};
int choice = -1;
printf("Command: ");
scanf("%d", &choice);
switch(choice){
case 0:
break;
case 1:
printf("Product: ");
gets(product);
insert_product(warehouse, price, product);
break;
case 2:
// print_all();
break;
default:
printf("Scelta non valida\n");
break;
}
The gets might be skipped by an ending char from a previous input. Try adding a getchar() before the gets to see if that is the problem.
The problem is that the newline you input when reading choice:
scanf("%d", &choice);
is being taken as input for the next gets(product); and so it reads an empty string. Try to add an artificial getchar after scanf to absorb the newline:
scanf("%d", &choice);
getchar();
Should work now.
First, the important bit...
NEVER NEVER NEVER NEVER NEVER use gets. Ever. Even for practice code. Even if someone else tells you to. It's like the movie Highlander II; it's just best to pretend it never existed. It was deprecated in C99 and has been completely removed from C2011. Don't use it. Don't try to justify using it by claiming this is just practice code. If someone else demands you use it, push back and tell them you'll use fgets instead. If they give you grief, send them to me and I'll straighten them out. With a baseball bat if necessary.
Okay, now that I've cleared that up...
gets is picking up the trailing newline from the input you entered for the previous scanf call. You have several choices:
Use another scanf call instead of gets, this time with the %s conversion specifier (along with a field width); unlike gets, it will skip over any leading newline characters;
Call getchar() (or equivalent) to consume the newline before calling gets;
Instead of reading choice as an integer using scanf, read it as text using fgets and convert it to an integer using strtol.
Option 3 is the best IMO. Mixing calls to scanf/fscanf and fgets is usually a recipe for heartburn, precisely because of the trailing newline issue. Better to stick with one or the other for everything. The advantage of using fgets to read everything as text is that it makes input validation easier, especially for numeric input.
// #define M 50 is at the top
char product[M] = {0};
int choice = -1;
printf("Command: ");
scanf("%d", &choice);
switch(choice){
case 0:
break;
case 1:
printf("Product: ");
getchar();
gets(product);
insert_product(warehouse, price, product);
break;
case 2:
// print_all();
break;
default:
printf("Scelta non valida\n");
break;
}
Use fflush(stdin) before using gets as input as the gets is taking newline character as input after the use of scanf("%d", &choice);
fflush(stdin) clears the output buffer and moves the buffered data to console.

Why is the following program stuck in a loop?

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.

Resources