【问题标题】:Calculator in C should only accept float/int numbersC 中的计算器应该只接受浮点数/整数
【发布时间】:2021-01-06 22:41:15
【问题描述】:

我正在开发一个只有基本运算符的小计算器。它真的很好用,就像我想要的那样。但是有一个小问题。 我的程序在一个循环中,所以理论上用户可以在每次计算后再次使用它。 但我也希望程序能够区分 float 类型的数字和其他所有元素,因此它只接受浮点数或整数。

问题来了: 如果我输入一个字母字符,问题就会变得混乱并且无法正确循环。 您可以在输入一些随机字母而不是预期的两个数字时自己尝试一下。

#include <stdio.h>
#include <unistd.h>
#include <ctype.h>

int main()
{
    float num1, num2, result = 0;
    int menu;

    while (1)       //so that the program basically never stops
    {
        printf("--- Taschenrechner ---\n\n"
               "1. Addition\n"
               "2. Subtraktion\n"
               "3. Multiplikation\n"
               "4. Division\n"
               "5. Beenden\n"
               "Wählen Sie Ihren gewünschten Operator aus (oder auch nicht): ");
        // it is like the calculators menu, distinguishing between
        // addition, subtraction, multiplication, division and exit
        scanf("%d", &menu);
        if (menu >= 5 || menu < 1)
        {
            printf("\nDas Programm wurde beendet, schade. Bis zum nächsten Mal!");      //if the given integer is 5 or not part of the menu, the program should stop
            break;
        }
        printf("\n\nGeben Sie nun zwei Zahlen ein:\n");     //user should provide two numbers
        scanf("%f", &num1);
        printf("\n");
        scanf("%f", &num2);
        if ((isalpha(num1) || isalpha(num2)) == 0)      //if the given elements are no numbers at all, in this case part of the alphabet, the program should stop
        {
            printf("Gut!");
        } else
        {
            printf("Break");
            break;
        }
        switch (menu)
        {
        case 1:
            result = num1 + num2;
            break;
        case 2:
            result = num1 - num2;
            break;
        case 3:
            result = num1 * num2;
            break;
        case 4:
            result = num1 / num2;
            break;
        default:
            printf("\n\nUps, da ist wohl etwas mit den Operatoren schief gelaufen. Versuchen Sie es erneut!");      //here again, if something went wrong within the switch case, program should stop
            break;
        }
        printf("\n\nPerfekt, das hat geklappt!");
        sleep(1);       //this is just for delaying the result 
        printf("\n\nIhr Ergebnis wird berechnet\nErgebnis: %.2f\n\n\n", result);
        sleep(3);
    }
    return 0;
} 

我真的不知道如何解决这个问题,试了几天。解决方案可能真的很简单,但我就是不明白。 一点帮助会非常好。 :)

而且也不介意程序是德语的。我已经将一些东西解释为 cmets。

【问题讨论】:

  • 查看scanf的返回值。这至少会告诉你输入是否可以被解析。但是如果它失败了,你仍然需要消耗无效的输入。建议修改代码使用fgets读取/消费一行输入,然后sscanf解析输入。
  • 将浮点数传递给isalpha 不会验证您的输入。

标签: c loops while-loop calculator


【解决方案1】:

为确保用户输入有效输入,您应验证scanf() 操作成功,并在输入无效数据时要求用户重新输入。 scanf() 返回成功转换的次数。如果输入无效,您应该读取并丢弃当前输入行的其余部分。

还要注意if ((isalpha(num1) || isalpha(num2)) == 0) 是不正确的:它测试num1num2 是否是ASCII 字母的代码。如果使用类型为6597,这将错误地检测到无效输入...

这是修改后的版本:

#include <stdio.h>
#include <unistd.h>

int main() {
    float num1, num2, result = 0;
    int menu;

    while (1) {       //so that the program basically never stops
        printf("--- Taschenrechner ---\n\n"
               "1. Addition\n"
               "2. Subtraktion\n"
               "3. Multiplikation\n"
               "4. Division\n"
               "5. Beenden\n"
               "Wählen Sie Ihren gewünschten Operator aus (oder auch nicht): ");
        // it is like the calculators menu, distinguishing between
        // addition, subtraction, multiplication, division and exit

        if (scanf("%d", &menu) != 1 ||  // invalid menu entry, bail out
            menu >= 5 || menu < 1) {
            printf("\nDas Programm wurde beendet, schade. Bis zum nächsten Mal!");      //if the given integer is 5 or not part of the menu, the program should stop
            break;
        }
        for (;;) {
            printf("\n\nGeben Sie nun zwei Zahlen ein:\n");     //user should provide two numbers
            if (scanf("%f%f", &num1, &num2) == 2)
                break;
            printf("\nUngültige Eingabe\n");
            if (scanf("%*[^\n]") == EOF)    // discard the rest of the input line
                return 1;
        }
        switch (menu) {
          case 1:
            result = num1 + num2;
            break;
          case 2:
            result = num1 - num2;
            break;
          case 3:
            result = num1 * num2;
            break;
          case 4:
            result = num1 / num2;
            break;
          default:
            printf("\n\nUps, da ist wohl etwas mit den Operatoren schief gelaufen. Versuchen Sie es erneut!\n");
            //here again, if something went wrong within the switch case, program should stop
            return 1;
        }
        printf("\n\nPerfekt, das hat geklappt!");
        sleep(1);       //this is just for delaying the result 
        printf("\n\nIhr Ergebnis wird berechnet\nErgebnis: %.2f\n\n\n", result);
        sleep(3);
    }
    return 0;
} 

注意事项:

  • scanf() 无法转换 2 个浮点数有 2 个原因:

    • 文件过早结束,
    • 流中不能作为数字开头的违规字符,例如A%
  • 要刷新用户输入的行的剩余部分,可以使用循环:

    int c;
    while ((c = getchar()) != EOF && c != '\n')
        continue;
    if (c == EOF) {
        /* no more characters available from stdin: bail out */
        return 1;
    }
    

或者可以使用scanf() 转换格式,它将读取并丢弃所有字符,直到换行符:

  if (scanf("%*[^\n]") == EOF)    // discard the rest of the input line
      return 1;

解释如下:

  • % 之后的 * 阻止存储转换后的值,转换说明符不需要指针。
  • [...] 指定 scanset,一组接受或拒绝的字符。 [abcx-z] 接受 abcxz 以及 xz 之间的任何字符的任何非空组合(ASCII 字符集中的y) . [^\n] 接受任何不同于 \n 的非空字符序列,因此输入行的其余部分(如果有)。
  • 用户键入的无法与行的其余部分一起转换的字符将被读取并丢弃,使换行符处于待处理状态。
  • 如果在换行符之前没有此类字符可用,scanf() 将返回 0,并且换行符仍等待下一次 %f 转换;
  • 如果流立即到达文件末尾,scanf() 返回EOF,这将导致程序退出。

【讨论】:

  • 你能解释一下表达式 if (scanf("%*[^\n]") == EOF) 吗?尤其是 scanf 和 EOF 之间的部分
  • @sam3004:我修改了答案,并解释了丢弃无效输入行
【解决方案2】:

您应该检查scanf 返回的值。例如:if( scanf("%d", &amp;menu) == 1 ) { ... }。如果输入流的下一个字符不是有效整数的一部分,则上面的scanf 将返回 0。

一般来说,你应该总是检查scanf返回的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-12
    • 2018-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多