为什么这个scanf格式字符串不起作用? "%[^ \ n] \ n" [英] Why won't this scanf format-string work? "%[^\n]\n"

查看:169
本文介绍了为什么这个scanf格式字符串不起作用? "%[^ \ n] \ n"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过一些例子,人们给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调用不会结束.

我可以按Enter键多次,但它将永远不会结束.

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

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

我不知道这是否与机器有关,但是我很想知道发生了什么.如果相关的话,我在OS X上.

解决方案

根据文档用于scanf(强调我的):

格式字符串由空格字符组成(格式字符串中的任何单个空格字符都会消耗输入中所有可用的连续空格字符),非空格多字节字符(%除外)(每个此类字符格式字符串中的字符完全消耗了输入和转换规范中的一个相同字符.

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

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

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

当然,这会将换行符保留在输入流中.要摆脱它(以防以后再读另一行),可以 getc 它从流中删除,或者只是在您的scanf格式字符串的末尾附加%*c(这意味着读取一个字符并丢弃它")甚至%*1[\n](读取一个换行符并丢弃它).

Ps..请注意,您的代码还有其他一些问题.例如,为避免缓冲区溢出错误,您实际上应该使用%63[^\n]而不是%[^\n]来限制scanf读入缓冲区的字符数. (此限制必须比缓冲区的大小小1,因为scanf总是会附加一个尾随的null字符.)

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

最后,请注意,如果您只想逐行阅读输入,那么使用

I've seen a few examples where people give scanf a "%[^\n]\n" format string to read a whole line of user input. If my understanding is correct, this will read every character until a newline character is reached, and then the newline is consumed by scanf (and not included in the resulting input).

But I can't get this to work on my machine. A simple example I've tried:

#include <stdio.h>

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

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

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

When I run this, I'm prompted for input, I type some characters, I hit Enter, and the cursor goes to the beginning of the next line but the scanf call doesn't finish.

I can hit Enter as many times as I like, and it will never finish.

The only ways I've found to conclude the scanf call are:

  • enter \n as the first (and only) character at the prompt
  • enter Ctrl-d as the first (and only) character at the prompt
  • enter some input, one or more \n, zero or more other characters, and enter Ctrl-d

I don't know if this is machine dependent, but I'm very curious to know what's going on. I'm on OS X, if that's relevant.

解决方案

According to the documentation for scanf (emphasis mine):

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.

Thus, your format string %[^\n]\n will first read (and store) an arbitrary number of non-whitespace characters from the input (because of the %[^\n] part) and then, because of the following newline, read (and discard) an arbitrary number of whitespace characters, such as spaces, tabs or newlines.

Thus, to make your scanf stop reading input, you either need to type at least one non-whitespace character after the newline, or else arrange for the input stream to end (e.g. by pressing Ctrl+D on Unix-ish systems).

Instead, to make your code work as you expect, just remove the last \n from the end of your format string (as already suggested by Umamahesh P).

Of course, this will leave the newline still in the input stream. To get rid of it (in case you want to read another line later), you can getc it off the stream, or just append %*c (which means "read one character and discard it") or even %*1[\n] (read one newline and discard it) to the end of your scanf format string.

Ps. Note that your code has a couple of other problems. For example, to avoid buffer overflow bugs, you really should use %63[^\n] instead of %[^\n] to limit the number of characters scanf will read into your buffer. (The limit needs to be one less than the size of your buffer, since scanf will always append a trailing null character.)

Also, the %[ format specifier always expects at least one matching character, and will fail if none is available. Thus, if you press enter immediately without typing anything, your scanf will fail (silently, since you don't check the return value) and will leave your input buffer filled with random garbage. To avoid this, you should a) check the return value of scanf, b) set input[0] = '\0' before calling scanf, or c) preferably both.

Finally, note that, if you just want to read input line by line, it's much easier to just use fgets. Yes, you'll need to strip the trailing newline character (if any) yourself if you don't want it, but that's still a lot easier and safer that trying to use scanf for a job it's not really meant for:

#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);
}

这篇关于为什么这个scanf格式字符串不起作用? &quot;%[^ \ n] \ n&quot;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆