0

呵呵!!我该如何把整个事情放在一个明确的问题中!!让我试试:

我知道使用打开的文件fopen()被缓冲到内存中。我们使用缓冲区来提高效率和易用性。在从文件读取期间,文件的内容首先被读取到缓冲区,然后我们从该缓冲区中读取。类似地,在写入文件,内容先写入缓冲区,然后写入文件。

但是fseek()fsetpos()之前rewind()调用的效果如何ungetc()呢?你能告诉我它是怎么做的吗?我的意思是,鉴于我们已经打开了一个文件进行读取并将它复制到缓冲区中。现在使用ungetc()我们已经更改了缓冲区中的一些字符。这就是我什至无法理解的内容很多努力:

  • 以下是关于ungetc()- “调用 fseek、fsetpos 或 rewind on stream 将丢弃之前使用此函数放回其中的任何字符。” --已经放入缓冲区的字符如何丢弃?一种方法是把原来被删除的字符“记住”,每一个放入的新字符都被识别并替换为原来的字符。但是这样看起来效率很低。另一种选择是将原始文件的副本加载到缓冲区中并将文件指针放在预期的位置。这两种方法中 fseek、fsetpos 或 rewind 采用哪种方法来丢弃使用的字符ungetc()

  • 对于文本流,流中未读字符的存在如何影响返回ungetc()ftell()ftell()ungetc()ftell

“对于文本流,数值可能没有意义,但仍可用于稍后使用 fseek 将位置恢复到相同位置(如果使用 ungetc 放回的字符仍等待读取,则行为未定义)。”

  • 关注上一段的最后一行,pending of being read与丢弃“ungetc()-obtained”字符有什么关系?每次我们读取一个放入流中的字符时ungetc(),它是否在读取后被丢弃
4

2 回答 2

1

放回角色的一个很好的心理模型就是它是一些额外的小属性,它悬挂在FILE *物体上。想象一下你有:

typedef struct { 
   /* ... */
   int putback_char;
   /* ... */
} FILE;

Imagineputback_char被初始化为EOF表示“没有放回字符”的值,并将ungetc字符简单地存储到该成员。

想象一下,每个读取操作都通过getc,并且执行如下操作getc

int getc(FILE *stream)
{
   int ret = stream->putback_char;

   if (ret != EOF) {
     stream->putback_char = EOF;
     if (__is_binary(stream))
        stream->current_position--;
     return ret;
   }

   return __internal_getc(stream); /* __internal_getc doesn't know about putback_char */
}

清除后推的功能只需分配EOFputback_char

换句话说,放回字符(并且只需要支持一个)实际上可以是一个与常规缓冲分开的微型缓冲区。(考虑到即使是无缓冲的流也支持ungetc:这样的流必须将字节或字符放在某处。)

关于位置指示器,C99 标准是这样说的:

对于文本流,在成功调用函数后,其文件位置指示符的值ungetc是未指定的,直到读取或丢弃所有推回的字符。对于二进制流,其文件位置指示符会随着函数的每次成功调用而递减ungetc;如果它的值在调用之前为零,则在调用之后它是不确定的。[7.19.7.11ungetc功能]

因此,您使用的 www.cplusplus.com 引用不正确;当有待处理的字符被 推回时,的行为ftell不是未定义的ungetc。对于文本流,该值未指定。访问未指定的值不是未定义的行为,因为未指定的值不能是陷阱表示。如果在位置 0 处发生推回,则二进制流存在未定义的行为,因为该位置随后变得不确定。不确定意味着它是一个未指定的值,可能是一个陷阱表示。访问它可能会停止程序并显示错误消息,或触发其他行为。

最好从马嘴里获取编程语言和库规范,而不是从随机的网站上获取。

于 2014-01-14T20:24:10.017 回答
0

让我们从头开始,

int ungetc(int c, FILE *stream);

ungetc() 函数应将 c 指定的字节(转换为无符号字符)推回到 stream 指向的输入流。一个字符实际上被放回输入流,减少其内部文件位置,就好像前一个 getc操作已撤消。这只会影响对该流的进一步输入操作,而不影响与其关联的物理文件的内容,任何对此函数的调用都不会修改该内容。

int fseek(FILE *stream, long offset, int whence);

新位置(从文件开头开始以字节为单位)应通过将偏移量添加到 wherece 指定的位置来获得。指定点是 SEEK_SET 的文件开头,SEEK_CUR 的文件位置指示符的当前值,或 SEEK_END 的文件结束。fseek 要么在设置文件位置之前刷新任何缓冲输出,要么记住它,因此稍后将在文件中的适当位置写入

int fsetpos(FILE *stream, const fpos_t *pos);

fsetpos() 函数根据 pos 指向的对象的值设置 stream 指向的流的文件位置和状态指示符,该值必须是从先前对同一流的 fgetpos() 调用获得的值。

void rewind(FILE *stream);

rewind 函数将与流关联的文件指针重新定位到文件的开头。倒带的调用类似于

(void) fseek(stream, 0L, SEEK_SET);

如您所见,ungetc(),推回字符不会改变文件;只有流的内部缓冲受到影响。所以您的第二条评论“另一个选项是将原始文件的副本加载到缓冲区并将文件指针放在预期位置”是正确的。

现在回答您的第二个问题 - 对文件定位函数的成功干预调用(流指向流)会丢弃流的任何推回字符。流对应的外部存储不变

于 2013-05-22T08:55:22.833 回答