【问题标题】:scanf_s() dosen't return every input [duplicate]scanf_s() 不会返回每个输入[重复]
【发布时间】:2017-10-12 14:06:45
【问题描述】:

我写了一些 C 代码来读取两个数字和一个运算符:

int Numberone = 0, Numbertwo = 0;
char Op;
scanf_s("%d %c %d", &Numberone, &Op, &Numbertwo);

用户输入他的 Input (5 + 2) 后,变量的值如下:Numberone = 5, Op = + 和 Numbertwo = 0。但这是错误的。第二个应该是 2。我怎样才能改进我的代码?为什么我的代码错了?

【问题讨论】:

  • 您的输入究竟是什么,您的实际输出是_究竟是什么,您的预期输出是究竟是什么。请edit您的问题。
  • scanf_s()(微软的)需要%c的缓冲区大小。只是不要使用它,使用scanf()
  • scanf_s("%d %c %d", &Numberone, &Op, &Numbertwo); --> scanf_s("%d %c %d", &Numberone, &Op, 1, &Numbertwo);。见scanf_s
  • 顺便说一句,对于实际的用户输入,scanf() 和朋友无论如何都是错误的选择(但 sscanf() 在您从 fgets() 获得的输入行上可能很好)。请参阅我的beginners' guide away from scanf() 了解一些信息。

标签: c console-application


【解决方案1】:

您正在使用scanf_s(注意_s),它需要%s%c 类型的每个参数的最大长度参数(例如,参见cppreference.com 上的scanf_s):

scanf_s:与scanf 相同,除了%c%s%[ 每个转换说明符都需要两个参数(通常的指针和 rsize_t 类型的值,表示接收数组的大小, 使用%c 读取单个字符时可能是1

所以你的%c格式的参数太少了,应该是这样的:

scanf_s("%d %c %d", &Numberone, &Op, (rsize_t) 1, &Numbertwo);

【讨论】:

  • 这描述了scanf_s()的标准版本,而我的水晶球表明OP正在使用MS功能......(非常相似但不幸的是不完全相同)
【解决方案2】:

首先,您不应该使用scanf_s()。 Microsoft 的编译器告诉您使用它,但最好忽略它。虽然scanf_s() 旨在通过要求cs[ 转换的缓冲区大小来“更安全”,但它是一个专有的Microsoft 扩展,所以使用它,你会锁定 到 Microsoft 编译器。您的实际问题是您没有在调用中传递缓冲区大小,scanf_s() 假定 &Numbertwo 是缓冲区长度。

情况更糟,因为 C 标准还包含scanf_s()。标准版本期望缓冲区大小以 element count 形式给出,例如 rsize_t,而 Microsoft 版本期望 byte count 形式为 unsigned,因此它们是微妙的不相容!恕我直言,这整个函数无论如何都是不必要的,只需使用字段宽度就可以让您使用纯 scanf() 编写安全代码。

因为scanf() 不适合从解析错误中恢复,所以您不应该直接将它用于交互式输入,而是读取整行并解析它(例如使用sscanf())。您的代码可能如下所示:

int Numberone = 0, Numbertwo = 0;
char Op;
char line[512];
if (!fgets(line, sizeof line, stdin))
{
    // error reading ...
}
if (sscanf(line, "%d %c %d", &Numberone, &Op, &Numbertwo) != 3)
{
    // error parsing ...
}

相应地处理错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-12
    • 2017-10-07
    • 2020-07-03
    • 1970-01-01
    • 2015-12-31
    • 2021-10-05
    • 1970-01-01
    • 2023-04-08
    相关资源
    最近更新 更多