在C语言中,以下模式用于获取一个字符串直到换行符是否正确?
int n = scanf("%40[^\n]s", title);
getchar();
它似乎是一种快速去除末尾换行符的方法,但我想知道这里是否存在我没有看到的缺点。
格式字符串中的 s
并不是你想象中的那样: 规定是 %40[^\n]
,而 s
会尝试匹配输入流中的一个 s
,这可能发生在已经将 40 个字节存储到 title
中之后。
如果待转换的输入流是一个换行符,则 scanf()
将无法进行转换,将导致 title
未改变并潜在地未初始化。
getchar()
不一定读入换行符: 如果该行上有超过 40 个字符,则只会读取下一个字符。
如果要读取一行,最多 40 个字节并忽略其余直到包括换行符的行,请使用以下代码:
char title[41];
*title = '\0';
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] = '\0';
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 = '\0';
} 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
}
之前的注释中,应该删除s
,它不是格式说明符的一部分,足以破坏你的读取。当你输入超过40个字符的字符串时,scanf
将尝试将一个s
字符与其匹配,直到找到一个匹配为止,执行才会继续。
用单个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
缓冲区中剩余的所有字符,无论它们是什么。stdin
缓冲区,而单个getchar
只会清除1个字符。fgets
。()
吗? - David542getchar
呢?难道不应该是 getchar()
吗? - David542fgets
。 - anastaciu你的代码存在一些问题,比如n
从未被使用,以及scanf
的错误指示符。
更好的方法是使用fgets
。 fgets
也会读取换行符(如果在缓冲区满之前存在),但很容易去除。