c - 在 C 中,如果输入字符串太大,如何产生错误?
问题描述
我想从一个文件中读取一个单词列表,每行一个单词。每个单词最多包含 4 个字符。如果其中一行比那长,我怎么能产生错误?
我尝试使用 fgets 阅读单词
char buf[5];
fgets(buf, 5, stdin);
和 scanf
char buf[5];
scanf("%4s", &buf);
但在这两种情况下,它都会将长线分成更小的线。例如qwerasdf
读作两个词,qwer
和asdf
。有没有办法检测它试图读取超过 4 个字符的长行并给出错误?
我能想到的唯一选择是逐个字符地读取输入并自己处理所有事情。但是使用标准库中的函数是否有更简单的解决方案?
解决方案
您正在做出一个很好的阅读选择fgets()
,您打破的唯一经验法则是不要吝啬缓冲区大小。但是,即使你这样做了,你也可以用fgets()
.
当您从文件中读取一行时,fgets()
(或 POSIX getline()
)读取并将其包含'\n'
为它们填充的缓冲区的一部分(如果有空间)。如果您期望最多 4 个字符,那么 5 的缓冲区大小太短了,无法容纳所有字符、nul 终止字符和'\n'
. 您尝试"cats"
使用 5 字符缓冲区读取 4 字符行 ( ) 的情况fgets()
将导致buf
持有:
+---+---+---+---+---+
| c | a | t | s | \0| --> '\n' remains unread
+---+---+---+---+---+
您也可以优雅地处理它(但最好不要吝啬缓冲区大小)要优雅地处理您需要检查的问题:
- 如果
'\n'
是缓冲区中的最后一个字符,则完整的行读取,通过用nul 终止字符'\n'
覆盖来修剪; - 否则,读取下一个字符;
- 如果下一个字符是
'\n'
,那么好的,您阅读了所有字符并且没有空间容纳'\n'
您刚刚阅读和检查的字符 - 继续阅读下一行; - 否则,如果 next char 是
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()) {}
}
}
}
如果您还有其他问题,请仔细查看并告诉我。
推荐阅读
- windows - 如何在批量扩展重命名时删除文件
- algorithm - 点数组中两点之间的最小欧几里得距离
- spring-boot - JHipster i18n 似乎坏了
- swift - 无法将“TaskElement”类型的值转换为预期的参数类型“EnvironmentObject”
' - github - 使组织中的私有存储库对一组人可见
- google-cloud-cdn - 太快了 Google CDN 缓存驱逐或错误
- amazon-web-services - DynamoDB 枚举转换版本 2
- tensorflow - 如果我使用预训练的嵌入模型,为什么 seq2seq 模型会返回负损失
- php - 无法在 codigniter 中上传图像,出现错误的路径错误
- python - Minimax 返回未来的移动,而不是导致胜利的实际移动