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,选项卡等。这通常是所需的行为,例如,如果您按 Enter 或 space 输入 它将丢弃那些并继续等待输入,但是如果你想解析空行你应该删除它,或者使用 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
的说明符错误。
更好的方法是使用 fgets
。 fgets
也将读取换行符(如果在缓冲区满之前存在)但它很容易删除。
见Removing trailing newline character from fgets() input
在 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,选项卡等。这通常是所需的行为,例如,如果您按 Enter 或 space 输入 它将丢弃那些并继续等待输入,但是如果你想解析空行你应该删除它,或者使用 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
的说明符错误。
更好的方法是使用 fgets
。 fgets
也将读取换行符(如果在缓冲区满之前存在)但它很容易删除。
见Removing trailing newline character from fgets() input