为什么这个scanf格式字符串不起作用? "%[^ \ n]的\ n"

时间:2016-02-07 16:21:38

标签: c input scanf

我已经看过一些例子,人们给scanf一个"%[^\n]\n"格式字符串来读取整行用户输入。如果我的理解是正确的,这将读取每个字符,直到到达换行符,然后新行被scanf消耗(并且不包括在结果输入中)。

但是我无法在我的机器上使用它。我尝试过一个简单的例子:

#include <stdio.h>

int main(void)
{
    char input[64];

    printf("Enter some input: ");
    scanf("%[^\n]\n", input);

    printf("You entered %s\n", input);
}

当我运行它时,我提示输入,我输入一些字符,我按Enter键,光标移到下一行的开头,但scanf调用没有完成。

scanf not finished

我可以按我喜欢的次数按Enter键,但它永远不会完成。

scanf still not finished

我发现结束scanf调用的唯一方法是:

  • 输入\n作为提示时的第一个(也是唯一的)字符
  • 在提示符
  • 中输入Ctrl-d作为第一个(也是唯一的)字符
  • 输入一些输入,一个或多个\n,零个或多个其他字符,然后输入Ctrl-d

我不知道这是否与机器有关,但我很好奇知道发生了什么。我是OS X的,如果那是相关的。

3 个答案:

答案 0 :(得分:6)

根据documentation对于scanf(强调我的):

  

格式字符串由空格字符组成(格式字符串中的任何单个空白字符使用输入中的所有可用连续空白字符),除%之外的非空白多字节字符(每个格式字符串中的此类字符仅使用输入中的一个相同字符和转换规范。

因此,您的格式字符串%[^\n]\n将首先从输入中读取(并存储)任意数量的非空白字符(因为%[^\n]部分),然后,由于以下换行符,读取(并丢弃)任意数量的空白字符,例如空格,制表符或换行符。

因此,要使scanf停止读取输入,您需要在换行符后键入至少一个非空白字符,或者安排输入流结束(例如,通过按< Unix-ish系统上的kbd> Ctrl + D

相反,要使代码按预期工作,只需从格式字符串末尾删除最后一个\n(如Umamahesh P已经建议的那样)。

当然,这将使换行符仍然在输入流中。要摆脱它(如果你想稍后再阅读另一行),你可以{i}离开流,或者只是追加%*c(这意味着“读取一个字符并丢弃它”)或者偶数%*1[\n](读取一个换行符并将其丢弃)到scanf格式字符串的末尾。

Ps。请注意,您的代码还有其他一些问题。例如,为了避免缓冲区溢出错误,您应该使用%63[^\n]而不是%[^\n]来限制scanf将读入缓冲区的字符数。 (限制需要比缓冲区的大小小一个,因为scanf将始终附加一个尾随空字符。)

此外,%[格式说明符始终至少需要一个匹配字符,如果没有,则会失败。因此,如果您在没有输入任何内容的情况下立即按Enter键,您的scanf将失败(默认情况下,因为您不检查返回值)并且将使您的输入缓冲区充满随机垃圾。为了避免这种情况,你应该a)检查scanf的返回值,b)在调用scanf之前设置input[0] = '\0',或者c)优选两者。

最后请注意,如果您只是想逐行阅读输入,那么 更容易使用getc。是的,如果你不想要它,你需要自己去除尾随的换行符(如果有的话),但是这仍然更容易和更安全,试图将scanf用于一个它不是真正意义的工作:

#include <stdio.h>
#include <string.h>

void chomp(char *string) {
    int len = strlen(string);
    if (len > 0 && string[len-1] == '\n') string[len-1] = '\0';
}

int main(void)
{
    char input[64];

    printf("Enter some input: ");
    fgets(input, sizeof(input), stdin);
    chomp(input);

    printf("You entered \"%s\".\n", input);
}

答案 1 :(得分:3)

format scanf()中的空格字符具有特殊含义:

  

空格字符:该函数将读取并忽略任何空格   在下一个非空白字符之前遇到的字符   (空格字符包括空格,换行符和制表符 -   见isspace)。格式字符串中的单个空格验证任何内容   从流中提取的空白字符数量(包括   无)。

因此,"%[^\n]\n"只相当于"%[^\n] ",告诉scanf()忽略%[^\n]之后的所有空白字符。这就是为什么在输入非空格字符之前忽略所有'\n'的原因,这种情况在您的情况下就会发生。

参考:http://www.cplusplus.com/reference/cstdio/scanf/

答案 2 :(得分:1)

删除第二个新行字符,以下就足够了。

scanf("%[^\n]\n", input);

回答原文,

Enter some input: lkfjdlfkjdlfjdlfjldj
t
You entered lkfjdlfkjdlfjdlfjldj

如果您在输入后输入非空格字符,这也应该有效。例如:

$url = 'http://clashofclans.com';
echo file_get_contents($url);