天天看点

C语言文件I/O操作值ungetc()函数深入详解

C语言文件I/O操作值ungetc()函数深入详解

前言:最近在看C语言的基本文件操作,遇到一个函数ungetc(),看了一些文章,发现并没有一篇真正写清楚的,都是转载来转再去,就那几句话说来说去,决定自己写一篇,来详细探讨这个函数的用法。

一、ungetc函数概述

我们都知道getc函数的作用,它的作用是从文件流中读取一个字符char,这个文件流可以是一般的文件流,也可以是标准文件流,顾名思义,ungetc的作用应该是和这个相反的,既然getc是“读出”一个char字符,那么ungetc当然就是将一个字符“放回”流了,意思很简单,下面来看一下一些常见的用法以及注意事项。

简而言之,ungetc的作用就是将一个字符放回输入流中。放回,放回,放回!!!重要的是说三遍。函数原型为:

int __cdecl ungetc(int Ch,FILE *_File);
           

1.1 标准输入流stdin不支持“放回”操作

ungetc ('c', stdin);  //给标准输入流放回一个'c'字符
ungetc ('b', stdin);
ungetc ('a', stdin);
while(feof(stdin))
{
     char c=getc(stdin);
     putchar(c);   //发现没有任何输出
} 
           

但是很遗憾,上面的运行结果没有任何结果输出,按道理说,我依次给标准输入流中放进去 c  b  a 三个字符,应该再读出来才对啊,为什么不行呢?这是因为因为标准输入流stdin只支持从键盘输入数据哦!!!

结论一:

标准输入流stdin无法使用ungetc放回任何字符,标准输入stdin只支持从键盘输入字符;

1.2 普通文件输入流是否可以一次放回多个字符

看下面的代码:

FILE * ffile=fopen("file1.txt","r"); //打开一个文件输入流
ungetc ('c', ffile);   //依次放回 c  b  a
ungetc ('b', ffile);
ungetc ('a', ffile);
char ch;
while(!feof(ffile))
{
    ch=getc(ffile);
    putchar(ch);  //只能够输出一个字母c
       
}
           

按道理说,这里依次给文件输入流ffile放回了三个字符 c  b  a 啊,但是为什么只输出了一个c呢?

这个地方实际上只写入了一个,后面的b,a并没有写入,即每次只能写入一个,不能写入很多个。

即一个数据放回到缓冲区去后,没有将缓冲区的数据读出来 就再次试图把读出的数据放回到缓冲区去,数据是放不进去的 (可以把缓冲区看做一个可变化的容器,当你把试图用ungetc()函数把读出的数据放回到缓冲区,缓冲区这个容器就为这些数据分配相应的大小空间,之后这个空间是不变的,直到你把缓冲区的数据读出去,所以你在没有释放缓冲区时,再次想往缓冲区装数据是装不进去的。

结论二:

普通文件输入流可以使用ungetc放回一个字符,但是一次只能够放回一个,必须要等到放回的字符读出来之后再才能接着放回一个字符;

按照结论二,我们看下面的例子:

FILE * fffile=fopen("file2.txt","r");
int i=1;
   
char ch2;
while(!feof(fffile))
{
     if(i==1)
         ungetc ('c', fffile);  //每一次只放回一个字符,然后又在下面取出来了
     else if(i==2)
         ungetc ('b', fffile);
     else if(i==3)
         ungetc ('a', fffile);
           
     ch2=getc(fffile);
     putchar(ch2);      //依次输出cba
     i++; 
       
   }
           

上面的运行结果为 cba  ,

这是比较合理的,每一只放回了一个字符,放回c,取出c,然后接着放回b,取出b,再放回a,再取出a。验证了结论二。

1.3 综合案例

现在有一个文本文件,内容如下:

i love you too!
owhat?
ohow?
owhere?
           

我有下面的这一段代码:

FILE *fp;
int c;
char buffer [256];

fp = fopen("file.txt", "r");
if( fp == NULL ) 
{
    perror("Error in opening file");
    return(-1);
}
while(!feof(fp))     //判断是否是到达了文件结尾
{
    c = getc (fp);
    if( c == 'o' )    //如果读到了字符 'o' ,则像文件输入流中 “放回” 一个 '*' 字符
    {
       ungetc ('*', fp); 
    }
    putchar(c);
}
/*运行结果为:
i lo*ve yo*u to*o*!
o*what?
o*ho*w?
o*where?
*/
           

为什么会是这样的结果呢?

分析可知,当读入一个字符遇到 'c' 之后,然后往标准输入流里面放回了一个 '*'字符,所以接下来会读取这个字符,然后再继续读取后面的内容。

总结:

注意ungetc函数的含义理解以及两个结论总结。