【问题标题】:scanf() not working correctly within for loopscanf() 在 for 循环中无法正常工作
【发布时间】:2020-10-27 11:39:12
【问题描述】:

我正在尝试将多个字符串从标准输入存储到一个临时变量中。

每个字符串都将在一个换行符之后输入。

这是我的尝试:

#include <stdio.h>
int main() {
    for (int i=0; i<10; i++) {
        char string;
        scanf("%s\n", &string);
        printf("%d\n", i);
    }
}

for 循环没有按预期运行,它只循环了两次,似乎 scanf 干扰了循环。

标准输入:

test
test

标准输出:

7631717

有没有办法将输入/来自标准输入的每一行动态存储到没有固定大小/长度的char 变量中?

【问题讨论】:

  • 始终检查成功扫描的项目数。也就是说,您必须检查 scanf 的返回值。总是。如果对 scanf 的调用不在作业的 RHS 上,则这是一个错误。
  • 除非在while ( scanf(...) == ... 这样的情况下,所以我声称自己处于任务的右侧是夸张的。但是你必须检查返回值!

标签: c loops for-loop input scanf


【解决方案1】:

有没有办法将输入/每行从标准输入动态存储到没有固定大小/长度的 char 变量中?

如果愿意走 POSIX 路线,请使用 getline() 来“动态存储来自标准输入的输入/每一行”。

如果需要,删除潜在的尾随换行

       char *line = NULL;
       size_t len = 0;
       ssize_t nread;

       while ((nread = getline(&line, &len, stdin)) != -1) {
           if (nread > 0 && line[nread-1] == '\n') line[--nread] = 0;
           printf("Retrieved line of length %zu: <%s>\n", nread, line);
       }

       free(line);

我怀疑nread &gt; 0 &amp;&amp; line[nread-1] == '\n' 可以简化为line[nread-1] == '\n',因为我看不到nread 返回 0 的情况。

【讨论】:

    【解决方案2】:

    不限于读取字符串的给定大小,您可以使用修饰符'm':

    char * p;
    
    if (scanf("%ms", &p) == 1) {
      ...use p;
      free(p); /* when stop to be usefull
    }
    

    来自 scanf的人:

    可选的“m”字符。这与字符串转换(%s、%c、%[)和 使调用者无需分配相应的缓冲区来保存 输入: 相反,scanf() 分配一个足够大的缓冲区,并分配 这个缓冲区的地址到相应的指针参数,它应该是 指向 char * 变量的指针(此变量之前不需要初始化 通话)。调用者随后应该释放(3)这个缓冲区,当它不再是 必填。

    前一种方式允许将“单词”变红,以读取整行删除开头的空格(“ ”、换行符、制表符...):

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
      char * p;
    
      if (scanf(" %m[^\n]", &p) == 1) {
        printf("'%s'\n", p);
        free(p);
      }
      else
        puts("error (EOF...)");
      
      return 0;
    }
    

    编译和执行:

    /tmp % gcc -Wall c.c
    /tmp % ./a.out
        aze qsd
    'aze qsd'
    /tmp % ./a.out < /dev/null
    error (EOF...)
    /tmp % 
    

    如果您没有该修饰符(不是 posix ...)来读取整行,您可以这样做:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
      char * p = malloc(1);
      size_t len = 0;
      int c;
      
      while (((c = getchar()) != '\n') && (c != EOF)) {
        p = realloc(p, len+1);
        if (p == NULL) {
          puts("not enough memory");
          return -1;
        }
        p[len++] = c;
      }
      p[len] = 0;
      
      printf("'%s'\n", p);
      free(p);
      
      return 0;
    }
    

    编译和执行:

    /tmp % gcc -Wall c.c
    /tmp % ./a.out
      aze qsd
    '  aze qsd'
    /tmp % ./a.out < /dev/null
    ''
    /tmp % 
    

    【讨论】:

    • +1 我不知道scanf() 中的m 修饰符以及在各种情况下使用它的一个很好的例子。
    • +1 为m;不知道(并且仍然无法在 C 标准中找到它(例如,此在线草案port70.net/~nsz/c/c11/n1570.html#Contents)?
    • m 不是 C 标准的一部分 - 但在 POSIX 标准中可用。因此,如果您使用的是非 POSIX 系统,则必须寻找替代方案。
    • @RohanBari 我编辑了我的答案以添加另一个示例
    • Limitations.scanf(" %m[^\n]", &amp;p) 不“存储输入/来自标准输入的每一行”当行仅包含空格时。相反,它们被默默地消耗掉了。此外,不会保存行的前导空格。
    【解决方案3】:

    char string; 不是字符串,而是单个字符。只要输入至少一个字符,将格式为%s 的字符串读入单个字符是未定义的行为。这是因为字符串终止字符也会被附加。

    写...

    char string[100];
    scanf("%99s", string);
    

    一切都会好起来的。

    顺便说一句:如果您打算阅读完整的行(包括开头、中间和结尾的空格),请考虑使用fgets 而不是scanf

    【讨论】:

    • 是否有动态获取输入的方法,没有固定的大小/长度?
    猜你喜欢
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 2013-03-31
    • 2016-01-01
    • 2021-09-26
    相关资源
    最近更新 更多