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

标签 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 上。

最佳答案

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

The format string consists of whitespace characters (any single whitespace character in the format string consumes all available consecutive whitespace characters from the input), non-whitespace multibyte characters except % (each such character in the format string consumes exactly one identical character from the input) and conversion specifications.

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

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

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

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

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

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

最后,请注意,如果您只想逐行读取输入,使用 fgets 会更容易 .是的,如果你不想要尾随的换行符(如果有的话),你需要自己去掉它,但是这仍然比尝试使用 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);
}

关于c - 为什么这个 scanf 格式字符串不起作用? "%[^\n]\n",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35255891/

相关文章:

c - 如何在指向整数的指针中输入数据?

c - 共享内存段 shmget shmat 双访问两者

Android 多点触控 : ACTION_UP not always called?

javascript - 使用 moment.js 尝试在 native IOS 日历中创建事件

c - scanf 到 struct 不起作用

c - scanf() 将换行符保留在缓冲区中

c - 读写整数数组到共享内存

c++ - 分段故障本身挂起

javascript - 这里应该使用 'form',还是没有必要?

c - 读取用户信息时遇到问题