gets和fgets函数及其区别,C语言gets和fgets函数详解
gets和fgets函數及其區別,C語言gets和fgets函數詳解
每當討論 gets 函數時,大家不由自主地就會想起 1988 年的“互聯網蠕蟲”,它在 UNIX 操作系統的 finger 后臺程序中使用一個 gets 調用作為它的攻擊方式之一。很顯然,對蠕蟲病毒的實現來說, gets 函數的功勞不可小視。不僅如此,GCC 也不推薦使用gets和puts函數。
那么,究竟是什么原因導致 gets 函數這么不招人待見呢?
我們知道,對于 gets 函數,它的任務是從 stdin 流中讀取字符串,直至接收到換行符或 EOF 時停止,并將讀取的結果存放在 buffer 指針所指向的字符數組中。
這里需要注意的是,換行符不作為讀取串的內容,讀取的換行符被轉換為 null(’\0’) 值,并由此來結束字符串。即換行符會被丟棄,然后在末尾添加 null(’\0’) 字符。
其函數的原型如下:
如果讀入成功,則返回與參數 buffer 相同的指針;如果讀入過程中遇到 EOF 或發生錯誤,返回 NULL 指針。因此,在遇到返回值為 NULL 的情況,要用 ferror 或 feof 函數檢查是發生錯誤還是遇到 EOF。
函數 gets 可以無限讀取,不會判斷上限,所以程序員應該確保 buffer 的空間足夠大,以便在執行讀操作時不發生溢出。也就是說,gets 函數并不檢查緩沖區 buffer 的空間大小,事實上它也無法檢查緩沖區的空間。
如果函數的調用者提供了一個指向堆棧的指針,并且 gets 函數讀入的字符數量超過了緩沖區的空間(即發生溢出),gets 函數會將多出來的字符繼續寫入堆棧中,這樣就覆蓋了堆棧中原來的內容,破壞一個或多個不相關變量的值。如下面的示例代碼所示:
int main(void) {char buffer[11];gets(buffer);printf("輸出: %s\n",buffer);return 0; }示例代碼的運行結果為:
aaa
輸出: aaa
根據運行結果,當用戶在鍵盤上輸入的字符個數大于緩沖區 buffer 的最大界限時,gets 函數也不會對其進行任何檢查,因此我們可以將惡意代碼多出來的數據寫入堆棧。由此可見,gets 函數是極其不安全的,可能成為病毒的入口,因為 gets 函數沒有限制輸入的字符串長度。所以我們應該使用 fgets 函數來替換 gets 函數,實際上這也是大多程序員所推薦的做法。
相對于 gets 函數,fgets 函數最大的改進就是能夠讀取指定大小的數據,從而避免 gets 函數從 stdin 接收字符串而不檢查它所復制的緩沖區空間大小導致的緩存溢出問題。當然,fgets 函數主要是為文件 I/O 而設計的(注意,不能用 fgets 函數讀取二進制文件,因為 fgets 函數會把二進制文件當成文本文件來處理,這勢必會產生亂碼等不必要的麻煩)。
其中,fgets 函數的原型如下:
該函數的第二個參數 bufsize 用來指示最大讀入字符數。如果這個參數值為 n,那么 fgets 函數就會讀取最多 n-1 個字符或者讀完一個換行符為止,在這兩者之中,最先滿足的那個條件用于結束輸入。
與 gets 函數不同的是,如果 fgets 函數讀到換行符,就會把它存儲到字符串中,而不是像 gets 函數那樣丟棄它。即給定參數 n,fgets 函數只能讀取 n-1 個字符(包括換行符)。如果有一行超過 n-1 個字符,那么 fgets 函數將返回一個不完整的行(只讀取該行的前 n-1 個字符)。但是,緩沖區總是以 null(’\0’) 字符結尾,對 fgets 函數的下一次調用會繼續讀取該行。
也就是說,每次調用時,fgets 函數都會把緩沖區的最后一個字符設為 null(’\0’),這意味著最后一個字符不能用來存放需要的數據。所以如果某一行含有 size 個字符(包括換行符),要想把這行讀入緩沖區,要把參數 n 設為 size+1,即多留一個位置存儲 null(’\0’)。
最后,它還需要第 3 個參數來說明讀取哪個文件。如果是從鍵盤上讀入數據,可以使用 stdin 作為該參數,如下面的代碼所示:
int main(void) {char buffer[11];fgets(buffer,11,stdin);printf("輸出: %s\n",buffer);return 0; }對于上面的示例代碼,如果輸入的字符串小于或等于 10 個字符,那么程序將完整地輸出結果;如果輸入的字符串大于 10 個字符,那么程序將截斷輸入的字符串,最后只輸出前 10 個字符。示例代碼運行結果為:
aaaaaaaaaaaaaaaa
輸出: aaaaaaaaaa
除此之外,C99 還提供了 fgets 函數的寬字符版本 fgetws 函數,其函數的一般原型如下面的代碼所示:
wchar_t *fgetws(wchar_t * restrict s, int n, FILE * restrict stream);該函數的功能與 fgets 函數一樣。
參考:C語言中文網 http://c.biancheng.net/view/379.html
總結
以上是生活随笔為你收集整理的gets和fgets函数及其区别,C语言gets和fgets函数详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Array变化侦测
- 下一篇: opencv cvhog详解