首页 > 解决方案 > 在 C 中,如果输入字符串太大,如何产生错误?

问题描述

我想从一个文件中读取一个单词列表,每行一个单词。每个单词最多包含 4 个字符。如果其中一行比那长,我怎么能产生错误?

我尝试使用 fgets 阅读单词

char buf[5];
fgets(buf, 5, stdin);

和 scanf

char buf[5];
scanf("%4s", &buf);

但在这两种情况下,它都会将长线分成更小的线。例如qwerasdf读作两个词,qwerasdf。有没有办法检测它试图读取超过 4 个字符的长行并给出错误?

我能想到的唯一选择是逐个字符地读取输入并自己处理所有事情。但是使用标准库中的函数是否有更简单的解决方案?

标签: cstdio

解决方案


您正在做出一个很好的阅读选择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()) {}
        }
    }
}

如果您还有其他问题,请仔细查看并告诉我。


推荐阅读