天天看點

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函數的含義了解以及兩個結論總結。