【问题标题】:How would I reject a non numeric input using a C code?如何使用 C 代码拒绝非数字输入?
【发布时间】:2015-12-07 19:01:25
【问题描述】:

我使用 cs50.io (c) 编写了一个代码。唯一的问题是,每当我在终端中检查 50 时,我都会收到一条错误消息,指出拒绝非数字输入 + 预期输入...这是我的代码,下面是终端中的错误。任何帮助将不胜感激。

#include <stdio.h>

int main() {
    float celsius, fahrenheit;

    printf("\nEnter temp in Celsius : ");
    scanf("%f", &celsius);

    fahrenheit = (1.8 * celsius) + 32;
    printf("F: %.1f\n", fahrenheit);

    return (0);     
}

https://sandbox.cs50.net/checks/ef786d6473b2409381a7161c725f8776

【问题讨论】:

  • 类似while (scanf("%f", &amp;celsius) != 1) printf("\nEnter temp in Celsius : "); ??
  • a) 检查来自scanf 的返回值和b) 多读一个字符并检查它是newline
  • 请注意,CS50 课程附带的库包含在源文件cs50.ccs50.h 中,其中定义的两个函数是GetFloat()GetDouble(),它们处理这些问题。

标签: c cs50


【解决方案1】:

可以查看scanf()的返回值Read the manual scanf(3)

float value;
if (scanf("%f", &value) != 1)
    fprintf(stderr, "non numeric input rejected.\n");
else
    fprintf(stderr, "good the input is a number `%f'.\n", value);

缺点是,后续输入通常难以使​​用scanf() 处理,因为它会忽略空格字符,您需要手动将它们从stdin 中删除。

我喜欢的方式是,

char buffer[100];
float value;
char *endptr;
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
    return -1; // Something went wrong (Ctrl+Z/Ctrl+D -> EOF) perhaps
// Check if non numeric characters are present.
value = strtod(buffer, &endptr);
if (((isspace(*endptr) != 0) && (*endptr != '\0')) || (buffer == endptr))
    fprintf(stderr, "non numeric input rejected.\n"); // ^ no conversion happened
else
    fprintf(stderr, "good the input is a number `%f'.\n", value);

但这也不完美,因为"123.456 example" 将被视为一个数值。严格处理它是可能的,但需要更多的工作。但我想你明白了这些例子的意义。

【讨论】:

  • 这将在代码中的什么位置?我有点困惑
  • @SamuelNazaroff 你可以创建一个函数,这真的取决于你想在哪里使用它。根据您的示例代码,这可以在 main() 中。
【解决方案2】:

简单地检查scanf("%f",...); 的返回值的问题在于,您不会捕获跟随 否则为有效字符的无效字符。此解决方案比其他解决方案更简单,并且可以在数字输入之前、中间或之后捕获无效字符:

已编辑:每个@WeatherVane'scomment

char baddet; // a dummy var used merely for detecting bad scanf() conversions

.
.
.

if (scanf("%f%c", &celcius, &baddet) != 2 || baddet != '\n')
{
   printf("Invalid numeric conversion (non-numeric characters in the input).\n");
   exit(1);
}

如果任何非数字字符跟在其他有效数字字符之后,则第一个此类字符将在baddet 中捕获。在您的情况下,您应该捕获换行符;在其他情况下(例如处理命令行参数),您可能希望数字字符后面根本没有空格;在这种情况下,scanf() 的返回值应该是 1,而baddet 中的值实际上并不重要(尽管无论如何将其地址传递给scanf() 很重要,以防有任何非数字字符后面的数字输入字符)。

【讨论】:

  • 这是错误的"%c" 将捕获下一个空白字符,您认为将空白字符视为无效是正确的吗?使用scanf()总是太难了。
  • 不应该是if (scanf("%f%c", &amp;celcius, &amp;baddet) != 2 || baddet != '\n')吗?
  • @iharob - 我认为你可能是对的;我实际上并没有尝试使用 OP 的代码。我通常在处理命令行参数时使用这种技术,其中没有空格来限制参数(除非调用者用包含的空格巧妙地引用它们的命令行参数)。我认为 Weather Vane 的修改将适用于 OP 的情况。
  • @WeatherVane - 我想你已经解决了我的疏忽。谢谢!
【解决方案3】:

编辑:在您发布的代码中,没有检查 scanf 是否确实有效。当我输入foo 时,代码继续,没有从文本转换为float celsius。然而celsius 从未被初始化,所以行为是未定义的。在我的例子中,打印代码32.0 因为celsius 恰好 具有0.0 的值。

您应该检查scanf 是否按预期执行,在您的示例中它应该返回值1。您还可以通过扫描以下字符来检查终止将文本转换为float 的字符是否是您预期的字符,如下所示。

#include <stdio.h>

int main(void) {
    float celsius, fahrenheit;
    char nextch;

    printf("\nEnter temp in Celsius : ");
    if (scanf("%f%c", &celsius, &nextch) != 2 || nextch != '\n') {
        printf("Bad entry\n");
    }
    else
    {
        fahrenheit = 1.8 * celsius + 32;
        printf("F: %.1f\n", fahrenheit);
    }
    return 0;     
}

函数scanf现在有2个格式说明符,所以它的返回值应该是2,并且下面的字符被检查为newline

【讨论】:

  • 如果你想让这个失败尝试123 \nscanf() 真的没用。但是你让我想到了"%f%*[ \t]%c",它可能会起作用。
  • @iharob 他们为什么要输入那个?我的回答要求严格的单行(而且不是太难)条目。但你是对的 - scanf 很笨拙,我永远不会尝试你推荐的语法。
  • @WeatherVane 你能向我解释一下这应该放在代码中的什么位置吗?我对这一切都很陌生,而且我并不像你看到的那样聪明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-18
  • 2022-12-08
  • 2023-03-03
相关资源
最近更新 更多