【问题标题】:how ftell() function works?ftell() 函数是如何工作的?
【发布时间】:2020-09-19 02:23:57
【问题描述】:

我有这段代码,但我不明白它是如何工作的:

void print(char * fileName)
{
    FILE * fp;
    int ch;
    fp = fopen(fileName, "r");
    while (ftell(fp) < 20)
    {
        ch = fgetc(fp);
        putchar(ch);
    }
    fclose(fp);
}

那么如果 ftell(fp) 在循环中,它是如何工作的? 因为循环内部没有任何东西可以启动它。 它是如何进步的?

【问题讨论】:

  • 循环中有fgetc()。这会推进文件位置,这就是ftell() 报告的内容。首次以"r" 模式打开文件时,文件位置为0。每次调用fgetc() 都会将文件位置提前1
  • ... 除非在 Windows 环境中以文本模式打开文件,其中行结尾是 两个 字符,其中一个被跳过。因此,您将收到 一个 字符 '\n' 换行符,但文件指针前进了 2
  • 因为看起来这段代码可能利用了特定于实现的行为,你能告诉我们这段代码适用于什么平台吗?关于它可能打算做什么的任何想法 - 它是如何使用的,它与什么样的文件一起使用?

标签: c file while-loop


【解决方案1】:

ftell 返回文件位置指示器的当前值,fgetc 确实在循环内推进文件位置指示器。


但是这个程序是错误的。对于以文本模式打开的流 ("r"),ftell 的返回值不能用于任何其他操作,除了寻找前一个位置。来自C11 draft n1570 7.21.9.4p2

[...] 对于文本流,其文件位置指示符包含未指定的信息,fseek 函数可使用该信息将流的文件位置指示符返回到 ftell 调用时的位置;两个这样的返回值之间的差异不一定是衡量写入或读取字符数的有意义的量度。

确实,在这个程序中使用ftell 没有任何意义。要么以二进制模式打开文件,"rb",然后保证

[...] 值是文件开头的字符数。

或者为了计算从文本文件中读取的字符,使用计数器变量:

int c_read = 0;
while (c_read < 20)
{
    ch = fgetc(fp);
    putchar(ch);
    c_read ++;
}

最后,如果文件少于 20 个字符,您的原始版本和我的原始版本都不能正常工作。在这种情况下,EOFfgetc 返回,putchar 会将(unsigned char)EOF 写入流(很可能是一个字节值255!)

因此正确的代码应该是

int c_read = 0;
while (c_read < 20)
{
    ch = fgetc(fp);
    if (ch == EOF) {
        // report the error
        perror("Failed to read 20 characters");
        break;
    }
    putchar(ch);
    c_read ++;
}

【讨论】:

  • “错误”可能言过其实——该程序可能只是依赖于ftell 在特定实现上的一些不可移植行为。例如,Weather Vane 在上面的评论中引用了 Windows 上的 CR/LF 问题。在这种情况下,您建议的“正确”代码实际上不会按预期工作。
【解决方案2】:

ftell() 为您获取流的位置指示器的当前值(在您的情况下,它基本上返回它当前当前指向的字符位置)。

fgetc() 从指定的流中获取下一个字符(无符号字符)并推进流的位置指示符。此函数将读取的字符作为无符号字符强制转换为文件末尾的 int 或 EOF 或错误

你的程序流程

简单来说就是——

  • fgetc() 正在从文件中读取一个字符一个字符并将指针前进 到下一个字符。

  • ftell() 返回当前位置(以字节为单位) 文件的开头。这意味着它告诉它现在指向的字符的位置(因为 1 个字符占用 1 个字节)。

  • 因此,您的程序从文件中读取,直到 ftell() 返回 位置小于 20。这意味着它将继续循环,直到从您的文件中读取 20 个字符

希望这能消除您的疑虑!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    • 2020-07-18
    • 2015-11-08
    • 2017-05-21
    • 2011-04-24
    • 2017-12-08
    • 2018-06-15
    相关资源
    最近更新 更多