![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuQTO0ATNzkDMwITMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
前言:最近在看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函數的含義了解以及兩個結論總結。