我想从文件中读取单词列表,该文件每行只有一个单词。每个单词最多应包含4个字符。如果其中一行比这更长,该如何产生错误?
我尝试使用fgets读取单词
char buf[5];
fgets(buf, 5, stdin);
和scanf
char buf[5];
scanf("%4s", &buf);
但是在两种情况下,它都会将长行拆分为较小的行。例如,qwerasdf
被读为qwer
和asdf
两个词。是否有办法检测到它试图读取多于4个字符的长行并给出错误信息?
我唯一想到的替代方法是逐个字符读取输入的内容,并自己处理所有事情。但是,使用标准库中的函数是否有更简单的解决方案?
您可以检查读取的字符串的长度,并且由于fgets也读取换行符,因此您可以显式检查'\ n'作为最后一个输入字符。
char buf[6];
while (fgets(buf, sizeof(buf), stdin)) {
if (strlen(buf) > 5
|| (strlen(buf) == 5 && buf[strlen(buf) - 1] != '\n')) {
fprintf(stderr, "line too long\n");
exit(EXIT_FAILURE);
}
}
缓冲区必须至少包含六个字符:4个输入字符+ 1个换行符+终止NUL字节的字符串。
您正在使用fgets()
进行出色的选择,唯一要打破的经验法则是不要在缓冲区大小上跳过。但是,即使您这样做,也可以使用fgets()
正确处理。
[当您从文件中读取一行时,fgets()
(或POSIX getline()
)读取并包括'\n'
作为它们填充的缓冲区的一部分(如果有空间)。如果期望最多4个字符,则缓冲区大小5太短,不足以容纳所有字符,nul-termination
'\n'
。您尝试使用带有"cats"
的5个字符的缓冲区读取4个字符的行(fgets()
)的情况将导致buf
保持:)要正常处理该问题,您需要检查:+---+---+---+---+---+ | c | a | t | s | \0| --> '\n' remains unread +---+---+---+---+---+
您也可以很好地处理(但最好不要跳过缓冲区大小
'\n'
是缓冲区中的最后一个字符,请完整读取行,通过用nul-termination字符覆盖来修剪'\n'
;'\n'
,那么好,您阅读了所有字符,而您刚刚阅读并检查过的'\n'
没有空间-继续阅读下一行;EOF
,那么您将读取文件中非POSIX结尾的文件的最后一行中的所有字符(最后一行数据后没有'\n'
),请中断读取循环,找到EOF
;'\n'
或EOF
将这种逻辑放在一起,您可以做:
#include <stdio.h> #include <string.h> int main (void) { char buf[5]; while (fgets (buf, 5, stdin)) { /* read each line */ if (strchr (buf, '\n')) /* if '\n' found - line read */ buf[strcspn (buf, "\n")] = 0; /* nul-termiante at '\n' */ else { /* otherwise */ int c = getchar(); /* read next chars */ if (c == '\n') /* if '\n', OK read next line */ continue; else if (c == EOF) /* if EOF, OK, non-POSIX eof */ break; fputs ("error: line too long - discarding remainder.\n", stderr); for (; c != '\n' && c != EOF; c = getchar()) {} } } }
仔细检查,如果还有其他问题,请告诉我。
这里我做了这个功能来读取文件char by char,每个调用仅返回一行]