关于C#:Scanf发生错误时返回1而不是0

Scanf returns 1 instead of 0 when an error occurres

我已经读到,返回的值scanf指示它是否能够读取和转换值。
我已经使用返回值来检测输入是否为整数,但是如果输入为4.5 scanf返回1,而输入为g scanf返回0。
她是我的代码:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int x;
    int ReturnedValue=scanf("%d",&x);
    printf("Scanf Returned:%d",ReturnedValue);
    return 0;
}

在多篇不同的文章中,您建议使用返回的scanf值检测整数,但是为什么现在不起作用?


返回值不表示成功或失败。它是成功转换的值的数量。

这就是为什么您在" 4.5"上以" "%d""格式获得" 1"的原因," 4"被转换了。

您可以通过阅读scanf()的文档找到它。


问题是scanf(或atoi)解析整数不是真正可靠。

在您的情况下,scanf找到4并对此感到满意,它说明了1返回码。

最安全的方法是使用strtolstrtoul ..基元,以确保该单词作为整数有效(有关更多详细信息,请参见"仅扫描整数"),答案是"不要使用" BTW :))

在您的特定情况下(卡在scanf上),可以通过先扫描为float来使输入更健壮(在float变量上使用%f)。并检查浮点值是否为整数。

1
2
3
4
5
6
7
8
9
10
float xf;
if (scanf("%f",&xf) == 1)
{
     // one integer or float was scanned
     x = (int)xf;
     if (x==xf)
     {
        // scanned value is an integer: valid
     }
}

但是像4XXXX这样的输入仍然会被错误地接受。如果必须使用scanf,则必须承担一定程度的风险。


Scanf returns 1 instead of 0 when an error occurs

输入未发生错误。 第一个字符"4"可以很好地转换为4。 代码需要检查其余部分。

I am forced to use scanf in collage

这样的编码约束是不幸的。 fgets()/strtol()会更好。

how could I detect if it's integer or not in simple fast way without destroying my whole code in c?

扫描整数并查找结尾的垃圾。

1
2
3
4
5
6
7
char endchar;  
int cnt = scanf("%d%c",&x, &endchar);
if (cnt == EOF) puts("End-of-file occurred");
else if (cnt == 1 || (cnt == 2 && endchar == '\
'
)) printf("Success %d\
"
, x);
else puts("Non-integer input");

当数据为非整数输入时,某些有问题的字符可能会保留在stdin中。 因为此任务仅读取一个int,所以可以。

生产代码更可能读取一行然后对其进行解析。


我最初不想写答案,而后留下评论。我想要
扩展Jean-Fran?ois Fabre的答案。

scanf家庭的问题是他们不做大多数人的事
相信他们会这样做,然后就为何会这样做"奇怪"感到困惑。实际上,他们根据格式扫描输入并为
变量(通过指针传递)。当他们遇到错误时,即某事
与格式不匹配,则它们停止。

使用格式"%d"时,您只是说要读取一个整数。格式不
说"读一个整数,只有一个整数"。为此,您还需要
排除其他所有内容,如果我没有记错的话,那将是
这个"%d[^0-9]*"(我还没有测试它是否正确)。
这就是为什么用户输入4.5
scanf。请注意,scanf的操作不正确,您正在指定它
错误地,因为您假设"%d"的意思是"以及整数和整数
只要"。

如您所见,很难找到一种可以捕捉的格式
一切,并告诉您用户何时出错。用户输入又名什么
用户输入的内容是随机的,可能包含(无意间)错误,请
格式等。因此,您最终会得到非常复杂的格式,只能确定
用户在末尾添加了一个点,如果这样做则失败。

这就是为什么我的建议是通过fgets读取while输入,然后使用更好的东西
如果格式良好,则可以解析strtol甚至sscanf之类的输入。

这是strtol用法的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *entries[] = {"4.5","4","some random text" };
    char *ptr;

    int i;
    for(i = 0; i < sizeof entries / sizeof *entries; ++i)
    {
        long int res = strtol(entries[i], &ptr, 0);

        if(*ptr != '\\0') {
            printf("The input '%s' is not an integer. The non-integer is '%s'\
"
, entries[i], ptr);
        } else {
            printf("The input '%s' is an integer: %ld\
"
, entries[i], res);
        }
    }

    return 0;
}

哪个返回

1
2
3
The input '4.5' is not an integer. The non-integer is '.5'
The input '4' is an integer: 4
The input 'some random text' is not an integer. The non-integer is 'some random text'

这是检查整个输入是否为整数的更精确的方法。


I have using the returned value to detect if the input is an integer or not but if the input was 4.5 scanf returns 1 while if the input was g scanf returns 0.

在这种情况下,这实际上是有道理的。

int ReturnedValue = scanf("%d",&x);

请记住,scanf返回值是正确解析的项目数。

  • 如果输入4.5,它将仅读取第一个数字4并正确解释int值。它将丢弃输入中所有剩余的无效字符。

  • 如果输入d,则scanf完全失败(它无法解析任何int),因此返回0。

请参阅scanf手册-查看为什么将4.5解析为整数4:

Reading of characters stops either when this maximum
is reached or when a nonmatching character is found, whichever
happens first.

http://man7.org/linux/man-pages/man3/scanf.3.html