#include <stdio.h>
#include <rpcndr.h>
int main() {
boolean playAgain=1;
char playInput;
float num1,num2,answer;
char operator;
while (playAgain){
printf("Enter First Number, operator, second number:");
scanf("%f%c%f",&num1,&operator,&num2);
switch (operator) {
case '*':
answer=(num1*num2);
break;
case '/':
answer=(num1/num2);
break;
case ' ':
answer=num1 num2;
break;
case '-':
answer=num1-num2;
break;
default:break;
}
printf("%f\n",answer);
printf("Do You Want To Try It Again(y/n)?");
scanf("%c",&playInput);
if(playInput=='n'){
playAgain=0;
}
}
}
Do while can do this code. But I want to why this method gets an error. And there is a problem with Scanf() function. Error says : Clang-Tidy: 'scanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtof' instead
CodePudding user response:
There are some issues.
The first scanf
won't check for syntax errors in the numbers and may leave a newline in the stream and confuse the second scanf
The second scanf
may not strip the newline from the stream, so on the second loop iteration, the first scanf
may have a problem.
While it might be possible to fix/contort scanf
into doing what you want, I'd follow clang's warning and use strtof
.
Here's the code refactored to use fgets
and strtof
. It is annotated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <rpcndr.h>
// lineget -- get a line from user with prompt
// RETURNS: pointer to buffer (NULL means EOF)
char *
lineget(char *buf,size_t len,const char *prompt)
{
char *cp;
// output prompt to user
puts(prompt);
fflush(stdout);
do {
// get an input line
cp = fgets(buf,len,stdin);
// got EOF
if (cp == NULL)
break;
// strip newline
buf[strcspn(buf,"\n")] = 0;
} while (0);
return cp;
}
int
main(void)
{
float num1, num2, answer;
char *cp;
char buf[1000];
int err;
char operator;
while (1) {
cp = lineget(buf,sizeof(buf),
"Enter First Number, operator, second number:");
if (cp == NULL)
break;
// get the first number
num1 = strtof(cp,&cp);
// get the operator
// NOTE: this could be a syntax error for the first number -- we'll
// check that below in the switch
operator = *cp;
if (operator != 0)
cp;
// get second number and check for syntax error
num2 = strtof(cp,&cp);
if (*cp != 0) {
printf("ERROR trailing '%s'\n",cp);
continue;
}
err = 0;
switch (operator) {
case '*':
answer = (num1 * num2);
break;
case '/':
answer = (num1 / num2);
break;
case ' ':
answer = num1 num2;
break;
case '-':
answer = num1 - num2;
break;
default:
err = 1;
break;
}
// we got a bad operator (or syntax error in first number)
if (err) {
printf("ERROR unknown operator '%c'\n",operator);
continue;
}
printf("%f\n", answer);
cp = lineget(buf,sizeof(buf),"Do You Want To Try It Again(y/n)?");
if (cp == NULL)
break;
if (buf[0] == 'n')
break;
}
return 0;
}
UPDATE:
The above code will detect most errors. Here's an enhanced version that does even more explicit checking:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <rpcndr.h>
// lineget -- get a line from user with prompt
// RETURNS: pointer to buffer (NULL means EOF)
char *
lineget(char *buf,size_t len,const char *prompt)
{
char *cp;
// output prompt to user
puts(prompt);
fflush(stdout);
do {
// get an input line
cp = fgets(buf,len,stdin);
// got EOF
if (cp == NULL)
break;
// strip newline
buf[strcspn(buf,"\n")] = 0;
} while (0);
return cp;
}
int
main(void)
{
float num1, num2, answer;
char *cp;
char *bp;
char buf[1000];
int err;
char operator;
while (1) {
bp = lineget(buf,sizeof(buf),
"Enter First Number, operator, second number:");
if (bp == NULL)
break;
// get the first number
num1 = strtof(bp,&cp);
// ensure we got at least a digit
// NOTE: this will detect:
// ""
// "j"
if (cp == bp) {
printf("ERROR no first number specified\n");
continue;
}
// get the operator
// NOTE: this could be a syntax error for the first number -- we'll
// check that below in the switch
operator = *cp;
// no operator specified
if (operator == 0) {
printf("ERROR no operator specified\n");
continue;
}
// skip over the operator
bp = cp;
// get second number and check for syntax error
num2 = strtof(bp,&cp);
if (*cp != 0) {
printf("ERROR trailing '%s'\n",cp);
continue;
}
// we need at least one digit (e.g.):
// we want to reject: 23 and ensure we have [at least] 23 0
// this will detect 23 k
if (cp == bp) {
printf("ERROR no second number specified\n");
continue;
}
err = 0;
switch (operator) {
case '*':
answer = (num1 * num2);
break;
case '/':
answer = (num1 / num2);
break;
case ' ':
answer = num1 num2;
break;
case '-':
answer = num1 - num2;
break;
default:
err = 1;
break;
}
// we got a bad operator (or syntax error in first number)
if (err) {
printf("ERROR unknown operator '%c'\n",operator);
continue;
}
printf("%f\n", answer);
cp = lineget(buf,sizeof(buf),"Do You Want To Try It Again(y/n)?");
if (cp == NULL)
break;
if (buf[0] == 'n')
break;
}
return 0;
}
CodePudding user response:
You should use fflush(stdin) function to clear all the leftover data in the stdin buffer (or clear it another way), otherwise scanf will read an extra \n at the end causing it to skip the rest of the data in the buffer
#include <stdio.h>
int main() {
_Bool playAgain=1;
char playInput;
float num1,num2,answer;
char operator;
while (playAgain){
printf("Enter First Number, operator, second number:");
scanf("%f%c%f",&num1,&operator,&num2);
fflush(stdin);
switch (operator) {
case '*':
answer=(num1*num2);
break;
case '/':
answer=(num1/num2);
break;
case ' ':
answer=num1 num2;
break;
case '-':
answer=num1-num2;
break;
default:break;
}
printf("%f\n",answer);
printf("Do You Want To Try It Again(y/n)?");
scanf("%c",&playInput);
fflush(stdin);
if(playInput=='n'){
playAgain=0;
}
}
}