【问题标题】:c++ function returns nan instead of doublec ++函数返回nan而不是double
【发布时间】:2017-06-09 02:31:43
【问题描述】:

已解决“输入正确值后循环后错过返回”

我使用 scanf_s 从控制台获取输入。我写了一个函数来检查输入,如果错误,它会请求再次输入。

如果我第一次输入正确的值,一切都很好。如果我必须在函数内再次输入该值,一切都很好,但返回该值的函数返回 NaN。为什么只有两次使用 scanf_s 才会返回双精度值?

如果我调用 input 并输入正确的值,则返回 double。如果我输入一个小于或等于 0 的值,我必须再次输入该值,但这次返回 NaN。在调试时我可以看到 eingabe 仍然是一个 double。

double input() {
    int n = -1;
    double eingabe = 0.0;

    scanf_s("%lf", &eingabe);

    clearBuffer();
    if (eingabe <= 0.0)
    {
        do
        {
            printf("Invald input");
            printf("Try again: ");

            n = scanf_s("%lf", eingabe);
            clearBuffer();
        } while (eingabe <= 0.0);
    }
    else
    {
        return eingabe;
    }
}

void clearBuffer() {
    //alles aus dem Buffer lesen bis man bei EOF (END OF FILE) ankommt
    int c;
        while ((c = getchar()) != EOF) {
            if (c == '\n')
                break;
        }
}

【问题讨论】:

  • 如果你编译为 C++,为什么不用std::cin 代替scanf_s,用std::cout 代替printf
  • 你的调试器告诉你发生了什么?您是否看到它按预期到达了您的退货声明?
  • 跟进 - 你的编译器是否给你任何关于你的 input() 函数的警告?
  • 为什么忽略scanf_s的返回值? I/O 意味着与环境交互,您无法控制,因此您必须始终检查所有内容。
  • 您对scanf_s 的第二次调用使用eingabe 而不是&amp;eingabe!虽然您的代码作为一个整体有一些很好的答案,但这可能就是除了第一次尝试之外返回 NaN 的原因。

标签: c++ scanf nan cin


【解决方案1】:

您不会返回 if (eingabe &lt;= 0.0) 中的值。

你必须重写你的代码,所以 eingabe 总是会被返回。

像这样:

if (eingabe <= 0.0)
{
    do
    {
        printf("Invald input");
        printf("Try again: ");

        n = scanf_s("%lf", &eingabe);
        clearBuffer();
    } while (eingabe <= 0.0);
}
return eingabe;

或者像这样:

if (eingabe <= 0.0)
{
    do
    {
        printf("Invald input");
        printf("Try again: ");

        n = scanf_s("%lf", &eingabe);
        clearBuffer();
    } while (eingabe <= 0.0);
    return eingabe;
}
else
{
    return eingabe;
}

在我看来,第一种情况更好。

编辑

在这里,我对您的代码进行了一些重构。不是每个人都会喜欢它,因为while(true) 的东西和continuereturn 不在函数的末尾。但至少它是用 C++ 编写的,而且在我看来它很自然,而且读起来很清楚。

#include <iostream>
#include <limits>

double input() {
    double eingabe;

    while (true) {
        std::cout << "Enter a positive real number: ";
        std::cin >> eingabe;

        if (std::cin.fail()) {
            std::cout << "Number expected." << std::endl;
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            continue;
        }

        if (eingabe <= 0) {
            std::cout << "Positive number expected." << std::endl;
            continue;
        }

        return eingabe;
    }
}

【讨论】:

  • 另外,if(x) do { ... } while (x) 等价于 while (x) { ... } 并且更具可读性。
  • 因为我们没有对 n 做任何事情,我们可以删除它
  • 总结一下——这个bug的原因是因为违反了“不要重复自己”的规则,重复的时候出错了。
  • @Exagon 或最好,检查与环境相关的 I/O 函数的返回值... 甚至最好,使用 C++ std::cin 代替 ::scanf_s()
  • @YSC,伙计们,是的,但它更像是codereview 问题。代码应该用 C++ 编写,因为这是 C++。使用 std::cin 和 std::cout。等等……
【解决方案2】:

我认为您的解决方案中有一些问题需要讨论。

首先,并不是所有的控制路径都会返回一个值,这可能会导致函数input产生不希望的结果;你的编译器应该警告过你。

其次,您的错误条件基于用户输入的双精度值,即负数或0 被视为错误。如果您还想输入负数或 0,则必须重新设计此方法。您应该使用scanf的返回值,它可以指示指定的格式是否已成功读取。

第三,您使用scanf_s,即scanf 的“安全”版本,因为scanf_s 可以限制写入缓冲区的字符;这在这里没有意义,原因有两个:(a) 您没有为缓冲区提供限制作为附加参数,以及 (b) 扫描%lf 无论如何都受到数据类型double 的限制。例如,将scanf_s-reference 授予msdn

与 scanf 和 wscanf 不同,scanf_s 和 wscanf_s 需要缓冲区大小 为 c、C、s、S 或字符串类型的所有输入参数指定 包含在 [] 中的控制集。以字符为单位的缓冲区大小作为附加参数传递,紧跟在指向缓冲区或变量的指针之后

第四,构造可能有点复杂,例如,double eingabe = 0.0 后跟 if (eingabe &lt;= 0.0) 的语句没有多大意义。

所以让我为函数input提出一个“更短”的解决方案:

double input() {

    double eingabe = 0.0;
    int validInput = 0;
    do {
        if (scanf("%lf", &eingabe) == 1 && eingabe > 0)
            validInput = 1;
        else {
          printf("Invald input\n"
                "Try again:");
          scanf("%*[^\n]\n");
        }
    }
    while (!validInput);
    return eingabe;
}

请注意,scanf("%*[^\n]\n") 语句在下一个 \n 之前使用任何字符,包括 \n,而不会将其写入任何缓冲区(在格式中由 * 表示)。

【讨论】:

    猜你喜欢
    • 2013-08-19
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 2012-12-02
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 2023-02-16
    相关资源
    最近更新 更多