计算器练习中fgets()和sscanf()的问题

计算器练习中fgets()和sscanf()的问题,c,scanf,calculator,fgets,C,Scanf,Calculator,Fgets,我正在努力做一项必须做的运动。因此,我必须编写一个计算器。它只需要知道int和运算符,如+、-、/和*,我们需要使用fgets()和sscanf() 例如,如果我先输入5+6,它就完全可以工作。作为输出,我得到了正确的结果:5+6=11。如果我的第二个条目类似于“a”或“4”,它不会像应该的那样打印出“无效输入”。相反,它打印4+6=10,因此加号和6会自动相加。我认为这与fgets()及其内存有关,但我不知道如何解决这个问题。 这是我目前的代码: #include <stdio.h>

我正在努力做一项必须做的运动。因此,我必须编写一个计算器。它只需要知道int和运算符,如+、-、/和*,我们需要使用fgets()和sscanf()

例如,如果我先输入5+6,它就完全可以工作。作为输出,我得到了正确的结果:5+6=11。如果我的第二个条目类似于“a”或“4”,它不会像应该的那样打印出“无效输入”。相反,它打印4+6=10,因此加号和6会自动相加。我认为这与fgets()及其内存有关,但我不知道如何解决这个问题。 这是我目前的代码:

#include <stdio.h>

int main(int argc, char *argv[])
{

   /* First define the variables, which are needed. 
There are two numbers, type int, and one op for the operation. */
   int number1, number2;
   char operator;
   char entry[50];

   /* First Output, where numbers and Operation are added, after that the code has to scan, which numbers and which operator were choosen.*/

   while (1)
   {
      printf("Enter <int> <op> <int>, single '0' to exit:");
      
      fgets(entry, sizeof(entry), stdin);
      sscanf(entry, "%d %c %d", &number1, &operator, & number2);
   
      /* Different calculations regarding the operator*/

      if (operator== '+')
      {
         printf("%d + %d = %d", number1, number2, number1 + number2);
      }

      else if (operator== '-')
      {
         printf("%d - %d = %d", number1, number2, number1 - number2);
      }

      else if (operator== '*')
      {
         printf("%d * %d = %d", number1, number2, number1 * number2);
      }

      else if (operator== '/')
      {
         printf("%d / %d = %d", number1, number2, number1 / number2);
      }
      else if (number1 == 0)
      {
         printf("Goodbye");
         break;
      }
      else if (number2=="\0" && operator =="\0" ||operator=="\0" )
      {
         printf("invalid input");
      }
      else
      {
         printf("invalid input");
      }
      printf("\n");
   }
   return 0;
}
#包括
int main(int argc,char*argv[])
{
/*首先定义所需的变量。
操作有两个数字,输入int和一个op*/
整数1,整数2;
字符算子;
字符输入[50];
/*第一个输出,其中添加了数字和操作,之后代码必须扫描,选择了哪些数字和哪个运算符*/
而(1)
{
printf(“输入,单个“0”退出:”;
fgets(入口、入口尺寸、标准尺寸);
sscanf(条目“%d%c%d”、&number1、&operator、&number2);
/*关于操作员的不同计算*/
if(运算符=='+')
{
printf(“%d+%d=%d”,number1,number2,number1+number2);
}
else if(运算符=='-')
{
printf(“%d-%d=%d”,number1,number2,number1-number2);
}
else if(运算符=='*')
{
printf(“%d*%d=%d”,number1,number2,number1*number2);
}
else if(运算符=='/'))
{
printf(“%d/%d=%d”,number1,number2,number1/number2);
}
else if(number1==0)
{
printf(“再见”);
打破
}
else if(number2==“\0”&&operator==“\0”| | operator==“\0”)
{
printf(“无效输入”);
}
其他的
{
printf(“无效输入”);
}
printf(“\n”);
}
返回0;
}
谢谢你的帮助:)

例如:

输入,单个“0”退出:4+5 4+5=9

输入,单个“0”退出:f 4+5=9

输入,单个“0”退出:g 4+5=9

输入,单个“0”退出:6-4 6-4=2

输入,单个“0”退出:7 7-4=3

输入,单个“0”退出:gergevyd
7-4=3

正如@kaylum所指出的,您遇到的问题是,您没有验证转换的结果。代码中的验证与实现正确的逻辑一样重要(如果由于验证失败而导致未定义的行为,则更为重要)

您必须验证每个用户输入和每个转换。使用
fgets()
进行输入是正确的。使用面向行的函数进行用户输入可以防止出现大量问题,因为您一次消耗了整行输入。如果以后转换失败,则可以防止
stdin
中未读的任何错误字符。(您可以检查输入的
strlen()
,以及
'\n'
存储在
条目
缓冲区末尾的
'\n'
,以便进一步验证)

但是,您仍然需要检查
fgets()
的返回值,因为通过按Ctrl+D(或windows上的Ctrl+z)取消输入的用户是生成手动
EOF
的有效输入。因此,只需检查
fgets()
的返回值是否为
NULL
,这将指示
EOF
,例如

    ...
    if (!fgets(entry, sizeof(entry), stdin)) {      /* validate EVERY input */
        puts ("(user canceled input)");             /* handle manual EOF case */
        break;
    }
使用
sscanf()
,您必须检查每个有效转换是否成功,并且在第一次有效转换之前未遇到匹配失败(如输入整数的
'a'
)或输入失败,即达到
EOF
sscanf()
返回发生的成功转换数,因此只需计算转换说明符,然后确保返回值等于该数字,例如

    /* validate EVERY conversion */
    if (sscanf (entry, "%d %c %d", &number1, &operator, & number2) != 3) {
        fputs ("error: invalid integer input.\n", stderr);
        continue;                                   /* go get new input */
    }
    ...
注意:使用
继续;
失败时,您只需使程序放弃当前行并提示用户输入新行即可)


其他想法

关于您的登录,这里是我的一些进一步想法(包括以下内联评论)。当您需要一个常量时,请定义一个(或多个)。这样,您就可以在代码顶部找到一个方便的位置,以便在需要时进行更改,而不必通过声明或循环限制进行挑选。使用
sizeof
时,正确的语法是
sizeof object
sizeof(type)
。只有在请求
类型的大小时才需要括号(但在其他情况下不是错误)

每当你有一个单独的数字或字符来决定要取多个分支中的哪一个时,考虑使用<代码>开关()/<代码>语句,而不是一个<代码>的链。否则如果。。。否则如果。。。否则…

语句。方便多了

在进行除法时——始终防止
“被零除法”
(否则会发生不好的事情——尽管生成的代码通常会将其作为异常处理)

使用
fgets()
时,可以提供一种非常简单的方法来指示输入结束。由于
fgets()
(以及POSIX
getline()
)读取并存储
'\n'
,作为它们填充的缓冲区的一部分,因此只需检查
条目中的第一个字符是否
'\n'
要退出(这是一种方便的方式)。调用
fgets()
后,只需检查
*entry=='\n'
以确定用户是否完成。(
*entry==*(entry+0)=entry[0]
)指针的简单解引用是检查第一个字符(或第一个元素)的快速方法

考虑到这些,你可以考虑一些类似的事情:

#include <stdio.h>

#define MAXC 1024       /* if you need a constant, #define one (or more) */

int main (void) {       /* if no arguments are expected */

    int number1, number2;
    char entry[MAXC], operator;
    
    while (1)   /* loop continually */
    {   /* no special input to exit, break read-loop on blank line */
        fputs ("\n('Enter' to exit)\nEnter expression: int op int: ", stdout);
        
        /* while not EOF or blank line */
        if (!fgets (entry, sizeof entry, stdin) || *entry == '\n') {
            puts ("(user canceled input)");
            break;
        }
        
        /* validate EVERY conversion */
        if (sscanf (entry, "%d %c %d", &number1, &operator, & number2) != 3) {
            fputs ("  error: invalid integer input.\n", stderr);
            continue;                                   /* go get new input */
        }
        
        /* Different calculations regarding the operator*/
        switch (operator)
        {               /* just add \n to end of each format string */
            case '+':   printf ("%d + %d = %d\n", number1, number2, number1 + number2);
                        break;
            case '-':   printf ("%d - %d = %d\n", number1, number2, number1 - number2);
                        break;
            case '*':   printf ("%d * %d = %d\n", number1, number2, number1 * number2);
                        break;
            case '/':
                        if (number2 == 0)   /* handle divide by zero */
                            fputs ("  error: division by 0 exception.\n", stderr);
                        else
                            printf ("%d / %d = %d\n", number1, number2, number1 / number2);
                        break;
            default:    fprintf (stderr, "  error: invalid operator '%c'.\n", operator);
                        break;
        }
    }
}
$ ./bin/calculator

('Enter' to exit)
Enter expression: int op int: 1 + 1
1 + 1 = 2

('Enter' to exit)
Enter expression: int op int: 1 + z
  error: invalid integer input.

('Enter' to exit)
Enter expression: int op int: 4 | 8
  error: invalid operator '|'.

('Enter' to exit)
Enter expression: int op int: 10/1
10 / 1 = 10

('Enter' to exit)
Enter expression: int op int: 10/0
  error: division by 0 exception.

('Enter' to exit)
Enter expression: int op int: 25 - 13
25 - 13 = 12

('Enter' to exit)
Enter expression: int op int:
(user canceled input)