【问题标题】:scanf error handling Cscanf 错误处理 C
【发布时间】:2011-05-11 18:46:18
【问题描述】:

说如果我想要一个输入是

[Name] [Name]

如何检测

[Name] [Name] [Name] 

并返回错误?

这是我目前所拥有的,

char in[20];
char out[20];
scanf(" %s %s", out, in);

【问题讨论】:

  • “不要使用scanf”是一个可以接受的答案吗(当然,如果我们详细说明的话)?
  • 另外,Names 是否保证不包含混淆%s 格式字符串的空格/括号/疯狂字符? "[Bruce Wayne]" 有效吗?
  • 是的,没有空格保证,空格将代表下一个元素
  • 将是名称名称,然后是下一行名称名称,然后是下一行名称名称等

标签: c error-handling


【解决方案1】:

scanf 返回有效转换参数的数量。因此,在第一种情况下,返回值为 2,在后一种情况下为 3。

要检查正确数量的参数,这可能会有所帮助:

char in[20];
char out[20];
char error[20];
int check;

check = scanf(" %s %s %s", out, in, error);
if(check != 2)
{
    // TODO: error handling
}

编辑:现在它应该可以工作了,见下面的 cmets。

当然,正如其他发帖者所说:scanf 被认为不是一个非常安全的函数,因为可能会发生缓冲区溢出,您应该避免使用它。最好使用fgets() 将输入读取到缓冲区并尝试解析所需的参数。

【讨论】:

  • 这不起作用,因为如果有第三个参数,scanf 会很乐意让它在流中等待,只扫描前两个名称,然后返回 2。这没有任何检查可能存在第三个名字。
  • 我必须承认你是对的 :/ 似乎我还没有充分考虑这一点。
  • 一个愚蠢的问题,fgets() 会给我同样的功能吗?
  • 不,很遗憾没有。 fgets() 允许您从缓冲区中读取,例如用于输入的标准输入缓冲区。 “fgets(buf,100,stdin);”从标准输入读取 100 个字符到缓冲区 buf。之后,可以使用 sscanf 等安全函数读取缓冲区。例如:sscanf(buf, "%20s %20s %20s", out, in, error);
  • 因为在我的例子中,它的 那么可能会有 的新行。错误可能只是被读取为下一行不会吗?
【解决方案2】:

这是家庭作业,因此您可能需要在某些(任意)限制下工作。但是,“scanf 错误处理”这句话在 C 编程语言中有点矛盾。

最好的方法是读入一行/其他合适的块并用 C 字符串函数解析它。你可以在scanf 的一行中做到这一点,但有很多缺点:

  1. 您可以防止缓冲区溢出,但如果缓冲区不够大,您将无法恢复。
  2. 您可以为您的字符串指定特定的字符范围,但它开始看起来有点正则表达式,并且scanf"%[" 格式的行为在标准中不是强制性的。
  3. 您可以检查第三个名称,但代码看起来不直观 - 看起来您不只需要两个名称,看起来您需要三个。 scanf 也让您几乎无法控制如何处理空白。

编辑:我最初从您的问题中认为名称包含在括号中(a la "[Bruce] [Wayne]"),但现在看来这只是您表示占位符的约定。

不管怎样,尽管我非常不喜欢scanf,但它还是有它的用途。最大的杀手(对我来说)是无法区分行尾和简单的空格分隔。要解决这个问题,您可以调用 fgets 将数据读入缓冲区,然后在缓冲区上调用 sscanf。这为您提供了 a) 更安全的读取(scanf 与其他更直接的函数从缓冲区读取的能力相混淆)和 b) scanf 格式的好处。

如果你必须使用scanf,你的格式基本上是这样的:

" %s %s %s"

第三个是不可取的。正如@Constantinius 的回答所示,您需要将数据读入三个缓冲区,并检查第三个缓冲区是否通过。但是,如果您正在读取此数据的多个连续行,则下一行的第一个条目将满足第三个插槽,从而错误地给您一个错误。在这种情况下,我强烈建议使用 fgetssscanf 或放弃 sscanf 以获得更精确的手动解析。

如果你错过了我之前偷偷溜进来的那个,这里是fgets man page 的链接。如果你决定放弃sscanf,这里有一些其他的函数可以查看:strchr(或strspn,或strcspn)来查找名称的长度,strcpymemcpy(但请不是strncpy,不是你想的那样)将数据复制到缓冲区中。

【讨论】:

  • 抱歉,它的 [Name Name]\n ... 可能还有更多 [Name Name]\n
  • 名称是否用括号分隔?输入是"[Clark] [Kent]\n" 还是只是"Clark Kent\n"
  • 克拉克肯特\n ...可能更多。那么我最好先阅读整行然后根据空格将其分解吗?我在java中做到了,但我不知道如何在C中做到这一点
  • 所有好的建议,但我会更进一步。抛弃 fscanf 支持 getline(不是 c 标准,而是 POSIX 的一部分)或许多可以读取任意长度行而不会冒缓冲区溢出风险的等效库之一。
  • @dmckee - 或者使用 GNU readline(或 BSD editline)以获得更多功能。即使你没有这些库,编写一个getline(或精简的readline)函数也不是很困难,而且一旦编写它肯定会节省很多时间。然而,这只是家庭作业,所以我愿意接受教授可能不希望人们试图弄清楚malloc
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-29
  • 2011-06-07
  • 2014-05-11
  • 2011-11-19
  • 2013-08-29
  • 1970-01-01
相关资源
最近更新 更多