【问题标题】:Dangers of using %*c to clear the scanf buffer使用 %*c 清除 scanf 缓冲区的危险
【发布时间】:2012-11-19 07:38:11
【问题描述】:

在 scanf() 中使用 %*c 在必要时清除缓冲区有什么危险吗?

例如:

char c;
for (int i = 0; i < 5; i++) {
  scanf("%c%*c", &c);
}

或者

char* str;
char c;
int i;
scanf("%s", str);
scanf("%d%*c", &i);
scanf("%c%*c", &c);

是否应该担心缓冲区溢出或其他安全问题? 对于 C (EDIT 这不是真的),似乎没有正式的文档来说明如何在 scanf 中使用星号(EDIT 这不是真的),所以我很难找出额外的字符会发生什么被输入。 有没有更好的方法来清除 C 中的 scanf 缓冲区?

【问题讨论】:

  • @melpomene,我在 StackOverflow 上见过的最好的评论
  • @melpomene 我的错误,我猜“官方”是指官方 C 文档,但我刚刚意识到它实际上并不像 JavaDocs for Java 那样存在。我仍然想知道被压制的角色会发生什么?它是否写入 Linux 机器上的 /dev/null 之类的东西?
  • 你从来没有说过“官方”。如果你想要官方(不付钱),open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 是你最好的选择(它是 C99 标准加上一些技术勘误)。
  • 被抑制的字符被简单地忽略;读取后被覆盖或以其他方式丢失。

标签: c security io buffer


【解决方案1】:

如果您将尝试完成的任务概念化为“我如何阅读和丢弃用户可能在我关心的内容之后键入的任何垃圾”,您会更幸运,这将引导您构建诸如

int c;
while ((c = getchar()) != EOF && c != '\n') ;  /* discard till end of line or EOF */

而且,你可以避免整个问题,首先不要使用scanf,即a good idea for several other reasons。如果你有 getlinefgets 如果你没有,请阅读整行,然后手动解析它们。

【讨论】:

  • 标准 C 中没有 getline()
  • @Aniket 这就是为什么我说如果你有它。好的 C 库可以。
  • @melpomene 告诉写这个的人:en.wikibooks.org/wiki/C_Programming/…
  • 好的,“库”的不同含义。 C 标准库是一个抽象规范。您在程序中实际使用的是该规范的具体实现(例如 glibc),其中大部分提供的功能超出了 C 标准中描述的功能。
  • 那你的意思是甚至没有标准 C 语言(和编译器)?因为它只是一个抽象规范(ANSI C?)
【解决方案2】:

如果要清除scanf缓冲区,这里是

char c;
for(int i = 0; i < 5; i++) {
    scanf("%c", &c);
    while(getchar() != '\n')
        continue;
}

或者

char c;
for(int i = 0; i < 5; i++) {
    scanf("%c", &c);
    fflush(stdin);
}

但是,您的代码很危险...

【讨论】:

  • 你能告诉我为什么这样做会很危险吗?另外,我使用的是 C 而不是 C++,所以 fflush(stdin) 仍然可以工作吗?
  • 如果您输入一个字符,当您按 Enter 键时。 scanf 接受你输入的字符也会产生一个换行符 '\n' 回车将被送入缓冲区,下次调用 scanf 时,换行符 '\n' 被赋值给字符变量 c
  • @hesson scanf 不保留字符,stdin 保留(甚至可能不是 stdin,而是程序之外的东西)。我不明白你的意思是“这只是语义,还是 scanf 实际上没有缓冲区?”。你认为“语义”是什么意思?
  • @melpomene:如果您阅读 fflush() 上的 MSDN,您会发现:fflush 函数会刷新流。如果与流关联的文件已打开以供输出,fflush 会将与流关联的缓冲区的内容写入该文件。如果流对输入打开,fflush 会清除缓冲区的内容。 这与 C 标准和 Unix 系统不同,在这些系统中,fflush() 对输入流的行为是未定义的。对于迁移到 Unix 的 Windows 程序员来说,这似乎是一个常见的混淆原因。
  • 当EOF条件出现时,while(getchar() != '\n') continue;是一个无限循环。最好使用int c; ... while(getchar() != '\n' &amp;&amp; c != EOF);
【解决方案3】:

没有scanf 缓冲区,但有一个“输入”缓冲区。清除它的最佳方法是使用rewind(stdin)。但是如果输入已经被重定向,这种方法就会出现问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    相关资源
    最近更新 更多