【问题标题】:scanf terminating standard inputscanf 终止标准输入
【发布时间】:2018-01-20 05:07:55
【问题描述】:
#include <stdio.h>
#include <stdlib.h>

int main(){

    char str[20];
    int number;
    while(2 == scanf("%s  %*d %*s  %*s    %d %*d %*s %*s %*s", str, &number)){
        printf("%s\n",str);
        printf("%d\n", number);

    }
}

我正在尝试从标准输入中读取多行,所有这些行都具有相同的格式。我当前的实现工作,但我似乎无法弄清楚一旦用户没有输入一行然后按回车键就终止输入。程序一直期待用户的输入。无论如何使用scanf 和我当前的实现来做到这一点?

注意:我正在运行以下命令:

ls -l | my_program

这并没有给我任何输出。

【问题讨论】:

  • 输入是什么?
  • 您应该通过在类 Unix 系统上输入 Control-D 或在 Windows 系统上输入 Control-Z 来指示 EOF。 %s 将跳过前导空格,包括换行符,等待非空白字符。只有 EOF 会让它停止。如果要进行基于行的输入并在空行或全空行上停止,请使用fgets() 读取该行并使用sscanf() 对其进行解析。请注意,在 Unix 上,Control-Z 暂停而不是终止进程。
  • 例如 -ab--c-- 7 是 否 1578
  • 我只需要提取-ab--c--和1578
  • 欢迎来到 Stack Overflow。请(重新)阅读How to Ask 页面,并注意创建 MCVE (minimal reproducible example) 的指南。发现您正在运行ls -l | ./your_program 应该不难;这应该是最初问题的一部分。一旦获得重要信息,问题就可以立即解决。重要的是要预先说明“必须使用scanf() 并且不能使用其他输入功能”之类的限制。人们会建议最好的做事方式,除非他们被告知你没有任何选择使用它。下次请记住。

标签: c scanf


【解决方案1】:

关于仅使用scanf() 来读取ls -l 命令的输出的最简单修改是这样的:

#include <stdio.h>

int main(void)
{
    char str[20];
    int number;
    if (scanf("%*[^\n]") != 0)
        return 1;
    while (2 == scanf("%s %*d %*s %*s %d %*[^\n]", str, &number))
        printf("%s  %d\n", str, number);
    return 0;
}

第一个scanf() 读到但不包括换行符;跳过ls -l 输出的total NNN 行。 第二个scanf() 与您的几乎相同,只是它将第二个数字(文件大小)之后的数据跳过到换行符。 幸运的是,开头的 %s 跳过了前导空格,包括换行符,因此扫描集 %*[^\n] 将换行符留在后面这一事实一点也不重要。

我的目录产生:

$ ls -l
total 152
-rw-r--r--    1 jleffler  staff  22072 Dec 30 09:19 LICENSE.md
-rw-r--r--    1 jleffler  staff   2694 Dec 30 09:19 README.md
dr-xr-xr-x    4 jleffler  staff    128 Aug 14  2016 Safe
drwxr-xr-x   84 jleffler  staff   2688 Jan 12 00:58 Untracked
drwxr-xr-x   26 jleffler  staff    832 Dec 25 22:39 bin
-rw-r--r--    1 jleffler  staff   1875 Jan 19 00:08 crseq71.sql
drwxr-xr-x   14 jleffler  staff    448 Dec 30 09:19 doc
drwxr-xr-x   10 jleffler  staff    320 Jan 12 01:13 etc
-rw-r--r--    1 jleffler  staff    173 Mar  3  2017 get.jl.activity
drwxr-xr-x   21 jleffler  staff    672 Jan  7 23:02 inc
drwxr-xr-x    5 jleffler  staff    160 May 28  2017 lib
-rw-r--r--    1 jleffler  staff    390 Jun 21  2017 makefile
drwxr-xr-x    4 jleffler  staff    128 Jan 12 01:13 packages
-rw-r--r--    1 jleffler  staff    218 Oct 15 10:18 pending.20171015.101828
-rwxr-xr-x    1 jleffler  staff   8704 Jan 19 21:39 rl43
-rw-r--r--    1 jleffler  staff    248 Jan 19 21:39 rl43.c
drwxr-xr-x    3 jleffler  staff     96 Jan 19 21:21 rl43.dSYM
-rw-r--r--    1 jleffler  staff   2247 Jan  6 22:44 sll43.c
-rw-r--r--    1 jleffler  staff    126 Oct 24 12:52 so-4689-5145.info
drwxr-xr-x  227 jleffler  staff   7264 Jan 19 11:34 src
-rw-r--r--    1 jleffler  staff     92 Jan 19 21:20 testfile.txt
-rw-r--r--    1 jleffler  staff    645 Jan 18 23:37 union71.c
$ ls -l | ./rl43
-rw-r--r--  22072
-rw-r--r--  2694
dr-xr-xr-x  128
drwxr-xr-x  2688
drwxr-xr-x  832
-rw-r--r--  1875
drwxr-xr-x  448
drwxr-xr-x  320
-rw-r--r--  173
drwxr-xr-x  672
drwxr-xr-x  160
-rw-r--r--  390
drwxr-xr-x  128
-rw-r--r--  218
-rwxr-xr-x  8704
-rw-r--r--  248
drwxr-xr-x  96
-rw-r--r--  2247
-rw-r--r--  126
drwxr-xr-x  7264
-rw-r--r--  92
-rw-r--r--  645
$

【讨论】:

  • 谢谢。由于 OP 使用了%*d%*s,所以没有太多需要向他们解释* 禁止赋值,并且转换规范不计入scanf() 的返回值中。答案确实提到了扫描集并再次使用了分配抑制——并且有一个指向scanf() 的 POSIX 文档的链接,其中详细介绍了这些要点。
  • 明白了......足够好。是的 OP 使用它 - 期望 OP 知道。
  • 我还看到 OP 在我编辑问题以添加 ls -l | program 信息之前不久编辑了格式字符串。最初,它没有%d 之后的所有尾随字段。没关系。使用%*[^\n] 扫描集可以全面处理该行的其余部分,即使文件名中有空格,问题中的代码现在处理不好也是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
  • 2018-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多