【问题标题】:Changing the scanf() delimiter更改 scanf() 分隔符
【发布时间】:2012-10-14 19:15:58
【问题描述】:

我的目标是将scanf 的分隔符更改为“\n”。 我尝试使用 scanf("%[^\n]s",sen); 并且适用于单个输入。 但是,当我将同一行放在 for 循环中的多个句子时,它给了我垃圾值。

有人知道为什么吗?


这是我的代码:

char sen[20];
for (i=0;i<2;i++)
{
    scanf("%[^\n]s",sen);
    printf("%s\n",sen);
}

【问题讨论】:

  • 从终端读取一行以 \n 作为分隔符的意义是有效的,但我忘了放 % 符号,但对其进行了编辑。
  • 我认为您只需要从格式字符串中删除最后的's'%[^\n] 指定读取直到下一个'\n' 的字符,然后's' 需要在输入中使用文字's'
  • %[^\n]试了一下,它仍然给出垃圾值
  • @firecast 您需要从输入缓冲区中删除换行符。
  • 刚刚注意到编译器没有在for 循环内执行scanf 语句,但它确实进入了循环内部。习惯于从文件中获取输入,所以之前不会注意到它。

标签: c scanf delimiter


【解决方案1】:

考虑一下这个 (C99) 代码:

#include <stdio.h>

int main(void)
{
    char buffer[256];

    while (scanf("%255[^\n]", buffer) == 1)
        printf("Found <<%s>>\n", buffer);
    int c;
    if ((c = getchar()) != EOF)
        printf("Failed on character %d (%c)\n", c, c);
    return(0);
}

当我运行它并输入一个字符串“绝对是任何带有空格 TABTABtabs galore!”的字符串时,它给了我:

Found <<absolutely anything with   spaces       tabs galore!>>
Failed on character 10 (
)

ASCII (UTF-8) 1010 当然是换行符。

这是否有助于您理解您的问题?


它在这种情况下有效(对于单行),但如果我想将多行输入放入一个数组数组中,那么它会失败。而且我不明白scanf 如何在您的代码中返回值?

许多(大多数?)有经验的 C 程序员避免 scanf()fscanf() 是有原因的;他们很难正常工作。我推荐这个替代方案,使用sscanf(),它不会得到与scanf()fscanf() 相同的执行。

#include <stdio.h>

int main(void)
{
    char line[256];
    char sen[256];

    while (fgets(line, sizeof(line), stdin) != 0)
    {
        if (sscanf(line, "%255[^\n]", sen) != 1)
            break;
        printf("Found <<%s>>\n", sen);
    }
    int c;
    if ((c = getchar()) != EOF)
        printf("Failed on character %d (%c)\n", c, c);
    return(0);
}

这会读取输入行(使用fgets() 确保没有缓冲区溢出(假设gets() 函数,如果您听说过它,将您的计算机熔化成金属和硅池),然后使用sscanf() 处理该行。这处理换行符,这是原始代码的失败。

char sen[20];
for (i=0;i<2;i++)
{
    scanf("%[^\n]s",sen);
    printf("%s\n",sen);
}

问题:

  1. 你不检查scanf()是否成功。
  2. 在第一次迭代时将换行符留在缓冲区中;第二次迭代生成返回值 0,因为要读取的第一个字符是换行符,也就是被扫描集排除的字符。
  3. 您看到的乱码可能是输入的第一行,重复出现。事实上,如果不是有界循环,它不会等你再输入任何东西;它会一遍又一遍地吐出第一行。

来自scanf()的返回值

scanf()(来自 ISO/IEC 9899:1999)的定义是:

§7.19.6.4 scanf 函数

概要

 #include <stdio.h>
 int scanf(const char * restrict format, ...);

说明

2 scanf 函数等效于 fscanf 插入参数 stdinscanf 的参数之前。

返回

3 如果之前发生输入失败,scanf 函数会返回宏 EOF 的值 任何转换。否则,scanf 函数返回输入项的数量 分配的,这可能比规定的要少,甚至为零,如果提前 匹配失败。

请注意,当我的第一个程序中的循环退出时,这是因为 scanf() 返回 0,而不是 EOF。

【讨论】:

  • 它在这种情况下有效(对于单行),但如果我想将多行输入放入数组数组中,那么它会失败。而且我不明白scanf 如何在您的代码中返回值?
  • 您提供的代码可以正常工作。但出于好奇,我不小心将我的代码从scanf("%[^\n]s",sen); 更改为scanf(" %[^\n]s",sen);,它开始正常工作。你知道为什么吗?
  • 在开始处理扫描集转换之前,格式前面的空格会吃掉杂散的空白,包括换行符(可能有几个)。这对%c 和扫描集转换很重要;无论如何,所有其他 AFAICR 已经跳过了前导空格。 scanf() 格式字符串的微妙之处很多;正确使用它是一个非常复杂的功能。您应该花时间阅读该标准(可从 ANSI 以 35 美元的价格获得 PDF 版——如果您打算成为一名认真的 C 程序员,那么这笔投资非常值得),或者至少是您系统的手册页。并经常重读。
  • @JonathanLeffler :另外,对于获取整数而不是字符串 (%d)"%255[^\n]" 的等价物是什么?
  • @user2284570:我不明白你之前的评论。您以后的评论可以有多种解释。您可以使用%d%ld%lld"%" PRIdMAX 来获得一个可能有符号的整数。我认为您无法阻止用户输入或输入接受符号(+-)。如果要输入一串数字,则可以使用%255[0-9] 输入最多255 位数字后跟一个空字节(因此变量需要为char buffer[256]; 或更大)。
【解决方案2】:

%[^\n] 将换行符留在缓冲区中。 %[^\n]%*c 吃掉换行符。 在任何情况下,%[^\n] 可以读取任意数量的字符并导致缓冲区溢出或更糟。 我使用格式字符串%*[^\n]%*c 来吞噬文件中输入行的剩余部分。例如,可以读取一个数字并通过%d%*[^\n]%*c 丢弃该行的其余部分。如果数字后面有注释或标签,或者其他不需要的数据,这很有用。

【讨论】:

    【解决方案3】:
    char sen[20];
    for (i=0;i<2;i++)
    {
      scanf("%[^\n]s",sen);
      printf("%s\n",sen);
      getchar();
    }
    

    希望这会有所帮助...实际上“\n”仍保留在流输入缓冲区中...在再次调用 scanf 之前需要将其刷新

    【讨论】:

      【解决方案4】:

      我知道我迟到了,但是我在很久之后测试 C 后遇到了同样的问题。
      这里的问题是新行被认为是下一次迭代的输入。

      所以,这是我的解决方案,使用getchar() 丢弃输入流的换行符:

      char s[10][25];
      int i;
      
      for(i = 0; i < 10; i++){
          printf("Enter string: ");
          scanf("%s", s[i]);
          getchar();
      }
      

      希望对你有帮助:)

      【讨论】:

        【解决方案5】:

        在循环中使用scanf("%[^\n]", sen) 时,出现的问题是\n 停留在输入缓冲区内并且没有被刷新。结果下次使用相同的输入语法时,它会读取\n并将其视为空输入。解决此问题的一个简单但有效的解决方案是使用:

        char sen[20];
        for (i=0;i<2;i++)
        {
            scanf("%[^\n]%*c",sen);
            printf("%s\n",sen);
        }
        

        %*c 删除输入缓冲区中的\n 字符。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-17
          • 2011-11-10
          • 2016-11-21
          • 1970-01-01
          相关资源
          最近更新 更多