- C和C++安全編碼(原書第2版)
- (美)Robert C.Seacord
- 1059字
- 2020-10-30 17:56:43
2.5.2 C99
嚴格符合C99的應用程序的兩個選項是用fgets()或getchar()取代gets()。
C標準fgets()函數和gets()擁有相似的行為。fgets()函數接受兩個額外的參數:期望讀入的字符數和輸入流。我們可以通過指定stdin作為輸入流來使fgets()模擬gets()的行為。
例2.9的程序片段中使用fgets()函數從stdin中讀取一行文本。
例2.9 使用fgets()從stdin中讀取
01 char buf[LINE_MAX]; 02 int ch; 03 char *p; 04 05 if (fgets(buf, sizeof(buf), stdin)) { 06 /* fgets 成功, 掃描查找換行符 */ 07 p = strchr(buf, '\n'); 08 if (p) { 09 *p = '\0'; 10 } 11 else { 12 /* 未找到換行符, 刷新stdin 到行尾 */ 13 while (((ch = getchar()) != '\n') 14 && !feof(stdin) 15 && !ferror(stdin) 16 ); 17 } 18 } 19 else { 20 /* fgets 失敗, 處理錯誤 */ 21 }
與gets()不同,fgets()函數保留換行符,這意味著不能將fgets()作為gets()的直接替代品。
當使用fgets()時,可能只讀取了一行的部分數據,然而,可以確定用戶的輸入是否被截斷了,因為那樣的話,輸入緩沖區內將不會包含一個換行符。
fgets()函數從流中最多讀入比指定數量少1個的字符到一個數組中。如果遇到換行符或者EOF標志,則不會繼續讀取。在最后一個字符讀入數組中后,一個空字符隨即被寫入緩沖區的結尾處。
使用fgets()可以安全地處理太長而不能在目標數組中存儲的輸入行,但出于性能方面的原因,不推薦使用它。如果指定的輸入字符數超過目標緩沖區的長度,fgets()函數也可能導致緩沖區溢出。
在嚴格符合C99標準的應用程序中更換gets()函數的第二個方法是使用getchar()函數。getchar()函數返回stdin指向的輸入流中的下一個字符。如果流在EOF處,則該流的EOF標記就會被設置,且getchar()返回EOF。如果發生讀取錯誤,則該流的錯誤標記就會被設置,且getchar()返回EOF。例2.10中的程序片段使用getchar()函數從stdin中讀取一行文本。
例2.10 使用getchar()從stdin中讀取
01 char buf[BUFSIZ]; 02 int ch; 03 int index = 0; 04 int chars_read = 0; 05 06 while (((ch = getchar()) != '\n') 07 && !feof(stdin) 08 && !ferror(stdin)) 09 { 10 if (index < BUFSIZ-1) { 11 buf[index++] = (unsigned char)ch; 12 } 13 chars_read++; 14 } /* while 循環結束 */ 15 buf[index] = '\0'; /* 空終結符 */ 16 if (feof(stdin)) { 17 /* 處理 EOF */ 18 } 19 if (ferror(stdin)) { 20 /* 處理錯誤 */ 21 } 22 if (chars_read > index) { 23 /* 處理截斷 */ 24 }
如果在循環結束時,,feof(stdin) ! = 0,則表示循環讀取到文件末尾,而沒有遇到一個換行符。如果在循環結束時,fferror(stdin) ! = 0,則表示循環在遇到一個換行符之前,發生了讀取錯誤。如果在循環結束時,chars_read > index,則表示輸入的字符串已被截斷?!禖安全編碼標準》[Seacord 2008],“FIO 34-C.使用int捕捉字符IO函數的返回值”,在此解決方案中也適用。
如果寫入到沒有設定正確的邊界的緩沖區中,那么使用getchar()函數讀取一行仍然可能導致緩沖區溢出。
一次讀取一個字符在控制行為方面提供了更多的靈活性,而無須額外的性能開銷。下面的測試對于while循環通常是足夠的:
while (( (ch = getchar()) ! = '\n') && ch ! = EOF )
參見《C安全編碼標準》[Seacord 2008],“FIO 35-C.在sizeof(int)==sizeof(char)的情況下,用feof()和ferror()檢測文件結束和文件錯誤”,這種情況下,必須用feof()和ferror()來代替上面的語句的寫法。
- Getting Started with Citrix XenApp? 7.6
- Java高手真經(高級編程卷):Java Web高級開發技術
- PySide GUI Application Development(Second Edition)
- Java編程的邏輯
- Mastering Xamarin.Forms(Second Edition)
- Python Essentials
- OpenCV Android開發實戰
- Hack與HHVM權威指南
- 算法秘籍
- Qt 5.12實戰
- Python無監督學習
- 產品架構評估原理與方法
- HTML并不簡單:Web前端開發精進秘籍
- HTML5 Game Development by Example:Beginner's Guide(Second Edition)
- Office VBA開發經典:中級進階卷