scanf ... getchar 的用法

Usage of scanf ... getchar

在 C 中可以使用以下模式获取换行符之前的字符串吗?

int n = scanf("%40[^\n]s", title);
getchar();

它似乎是一种快速去除尾随换行符的方法,但我想知道是否存在我在这里没有看到的缺点。

之前注意,s 应该被删除,它不是说明符的一部分并且足以扰乱你的阅读,scanf 将尝试匹配一个 s 字符你输入的字符串超过40个字符,直到找到一个才会继续执行。

使用单个 getchar 来回答您的问题并不是最好的方法,您可以使用以下常用例程来清除缓冲区:

int n = scanf(" %40[^\n]", title);

int c;
while((c = getchar()) != '\n' && c != EOF){}

if(c == EOF){
   // in the rare cases this can happen, it may be unrecoverable
   // it's best to just abort
   return EXIT_FAILURE;
}
//...

为什么这有用?它读取并丢弃 stdin 缓冲区中剩余的所有字符,无论它们是什么。

在输入字符串有 45 个字符的情况下,此方法将清除 stdin 缓冲区,而单个 getchar 仅清除 1 个字符。

请注意,我在说明符之前添加了一个 space,这很有用,因为它会在找到第一个可解析字符、换行符、spaces 之前丢弃所有白色 spaces,选项卡等。这通常是所需的行为,例如,如果您按 Enterspace 输入 它将丢弃那些并继续等待输入,但是如果你想解析空行你应该删除它,或者使用 fgets.

发布的代码有多个问题:

  • 格式字符串中的 s 不是您认为的那样:规范是 %40[^\n] 并且 s 将尝试匹配 s 在输入流中,这可能发生在 40 个字节存储到 title.

    之后
  • scanf() 将无法转换任何待定输入是换行符,使 title 保持不变并且可能未初始化

  • getchar() 不一定会读取换行符:如果该行超过 40 个字符,它只会读取下一个字符。

如果您想读取一行,最多 40 个字节并忽略该行的其余部分,包括换行符,请使用:

    char title[41];
    *title = '[=10=]';
    if (scanf("%40[^\n]", title) == EOF) {
        // end of file reached before reading anything, handle this case
    } else {
        scanf("%*[^\n]"); // discard the rest of the line, if any
        getchar();        // discard the newline if any (or use scanf("%1*[\n]"))
    }

这样写可能更具可读性:

    char title[41];
    int c, len = 0;
    while ((c = getchar()) != EOF && c != '\n') {
        if (len < 40)
            title[len++] = c;
    }
    title[len] = '[=11=]';
    if (c == EOF && len == 0) {
        // end of file reached before reading a line
    } else {
        // possibly empty line of length len was read in title
    }

你也可以使用fgets():

    char title[41];

    if (fgets(title, sizeof title, stdin) {
        char *p = strchr(title, '\n');
        if (p != NULL) {
            // strip the newline
            *p = '[=12=]';
        } else {
            // no newline found: discard reamining characters and the newline if any
            int c;
            while ((c = getchar()) != EOF && c != '\n')
                continue;
        }
    } else {
        // at end of file: nothing was read in the title array
    }

您的代码存在许多问题,例如 n 从未被使用,scanf 的说明符错误。

更好的方法是使用 fgetsfgets 也将读取换行符(如果在缓冲区满之前存在)但它很容易删除。

Removing trailing newline character from fgets() input