为什么不是 scanf("%*[^\n]\n");和 scanf("%*[^\n]%*c");清除挂起的换行符?

Why aren't scanf("%*[^\n]\n"); and scanf("%*[^\n]%*c"); clearing a hanging newline?

在调用 scanf("%d", &variable); 之后,我们在 stdin 处留下了一个换行符,应该在调用 fgets 之前清除它,或者我们最终给它提供了一个换行符并使它过早 return。

我找到了建议在第一次调用 scanf 后使用 scanf("%*[^\n]%*c"); 以丢弃换行符的答案,以及其他建议使用 scanf("%*[^\n]\n"); 的答案。从理论上讲,两者都应该起作用:第一个会消耗所有不是换行符的东西(但不包括换行符本身)然后消耗 exactly 一个字符(换行符)。第二个将消耗不是换行符的所有内容(不包括它),然后 \n,一个空白字符,将指示 scanf 读取每个空白字符,直到第一个非空白字符。

然而,尽管我认为这些方法在某些答案中起作用,但我无法让它们在这里起作用(下面的代码)。

为什么 scanf 方法都不起作用?

测试于: Ubuntu Linux - gcc 5.4.0

scanf("%*[^\n]\n");方法:

#include <stdio.h>

int main(int argc, char **argv){
    int number;
    char buffer[1024];

    printf("Write number: \n");
    scanf("%d", &number);

    //Clearing stdin?
    scanf("%*[^\n]\n");

    printf("Write phrase: \n");
    fgets(buffer, 1024, stdin);

    printf("\n\nYou wrote:%u and \"%s\"\n", number, buffer);

    return 0;
}

输出:

$ ./bug 
Write number: 
2
Write phrase: 


You wrote:2 and "
"

scanf("%*[^\n]%*c");方法:

#include <stdio.h>

int main(int argc, char **argv){
    int number;
    char buffer[1024];

    printf("Write number: \n");
    scanf("%d", &number);

    //Clearing stdin?
    scanf("%*[^\n]%*c");

    printf("Write phrase: \n");
    fgets(buffer, 1024, stdin);

    printf("\n\nYou wrote:%u and \"%s\"\n", number, buffer);

    return 0;
}

输出:

$ ./bug2 
Write number: 
3
Write phrase: 


You wrote:3 and "
"

以下方法是唯一按预期方式工作的方法:

工作方法:

#include <stdio.h>

int main(int argc, char **argv){
    int number;
    char buffer[1024];

    printf("Write number: \n");
    scanf("%d", &number);

    //Clearing stdin!
    int c;
    while((c = getchar()) != '\n' && c != EOF){
        //Discard up to (and including) newline
    }

    printf("Write phrase: \n");
    fgets(buffer, 1024, stdin);

    printf("\n\nYou wrote:%u and \"%s\"\n", number, buffer);

    return 0;
}

输出:

$ ./notbug 
Write number: 
4
Write phrase: 
phrase :D


You wrote:4 and "phrase :D
"

基本问题是 scanf 模式 %[^\n] 匹配 一个或多个 个不是换行符的字符。因此,如果下一个字符 一个换行符,该模式将失败并且 scanf 将立即 return 而不读取任何内容。添加 * 不会改变这一基本事实。所以事实证明你不能只用一个电话来做到这一点,你需要两个:

scanf("%*[^\n]"); scanf("%*c");

请注意,将空换行符放入扫描模式几乎总是没有用——它会导致 scanf 读取并丢弃所有空白,直到它看到 non-whitespace 字符(它将留在输入缓冲区中).特别是如果您尝试在交互式程序中使用它,它似乎会挂起,直到您输入 non-blank 行。