【问题标题】:Printing number of lines in a file without using fgets不使用 fgets 打印文件中的行数
【发布时间】:2020-02-02 04:20:10
【问题描述】:

所以我试图打印文件中的行数。问题是我不能使用 fgets。有没有其他只涉及 fscanf 的替代方案? 我尝试运行以下命令:

while (1) {
  ret = fscanf(fin, "%[^\n]", string);
  if (ret == EOF) break;
  line_count++;
}

但它不起作用。它给了我一个无限循环。谁能告诉我是什么问题?

【问题讨论】:

  • 不幸的是它没有。你能指出我程序中的缺陷吗?
  • 您正在扫描除换行符以外的所有内容。这意味着扫描卡在换行符上。链接的答案告诉您如何扫描包含换行符的行。您只需要调整它以计算行数并循环执行。
  • 除了fgetc,你为什么要使用其他东西? scanf 不是合适的工具。

标签: c file-io


【解决方案1】:

此声明:

ret = fscanf(fin, "%[^\n]", string);

应该是:

ret = fscanf(fin, " %[^\n]", string);

注意前导空格,它将占用任何前导“空白”

我同意 cmets 关于换行符的观点。因此,建议:

size_t lineCount = 0;
int ch;
while( ( ch = getchar() ) != EOF )
{
    if( '\n' == ch )
    {
        lineCount++;
    }
}

【讨论】:

  • 它将消耗连续的换行符,这违背了计算它们的目的。
  • 您还应该将EOF之前读取的最后一个字符(例如int ch, last;)保存为while中的最后一个命令设置last = ch;,然后在最后检查if (last != '\n') lineCount++;来处理文件在最后一行不包含 POSIX 行结尾的情况。 (注意: chlast 应输入 int 以检测 EOF
【解决方案2】:

您还必须注意其他答案未涵盖的极端情况。对于符合 POSIX 的文件,最后一个字符必须是 '\n' 字符,否则文件开头可能为空。例如,包含 POSIX 文件结尾的两行文件可能是:

my dog has fleas\n
my cat has none\n

如果您通过计算'\n' 字符数来计算上述文件中的行数,那么您的文件行数将符合预期——2。但是,今天有许多编辑器不创建符合 POSIX 的文件,因为他们未能在最后一行文本之后写入最终的 '\n'。如此多的编辑会将文件保留为:

my dog has fleas\n
my cat has none

这是保存文件的一种完全合法的方式,它只是一种非 POSIX 方式。现在,如果您只是计算'\n' 字符来确定文件中的行,您的程序会输出什么? (1 -- 你会数几行)

要解决非 POSIX eof 问题以确保您的行数正确无误,您需要检查 EOF 之前的最后一个字符,看看它是否是 '\n',如果不是您需要将+1 添加到您的行数中。

你可以很简单地做到这一点,只需在循环结束时保存当前字符,以便在遇到EOF 后保留它以供比较。您可以执行以下操作:

/* count lines in file from open file-stream.
 * returns number of lines in file, including files
 * with non-POSIX end-of-file.
 */
size_t linecount (FILE *fp)
{
    int c, last = 0;                    /* current and last char read */
    size_t nlines = 0;                  /* line counter */
    
    rewind(fp);                         /* prevent UB if EOF already set on fp */
    
    while ((c = fgetc(fp)) != EOF) {    /* loop reading each char */
        if (c == '\n')                  /* if '\n' increment line counter */
            nlines++;
        last = c;                       /* save current as last */
    }
    /* if not empty-file and not POSIX eof, add 1 to nlines */
    return last && last != '\n' ? nlines + 1 : nlines;
}

循环也可以写成:

    do {
        last = c;
        if ((c = fgetc(fp)) == '\n')
            nlines++;
    } while (c != EOF);

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-29
    • 2022-01-10
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-13
    相关资源
    最近更新 更多