为什么不是 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 行。
在调用 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 行。