C語言通過gets和gets_s分別實現讀取含空格的字符串
導讀
在刷Oj題時,遇到包含空格的字符串輸入,如何讀取呢?如果使用scanf以%s格式去讀取輸入的字符串,遇到空格就讀取結束瞭,顯然這樣是讀取不瞭的。當然,scanf也是可以讀取含空格字符串的,但操作起來相對較難,對C語言初學者並不友好。下面開始介紹兩個可以對含空格字符串讀取的庫函數——gets和gets_s函數
gets函數
函數聲明
char * gets ( char * str );
函數介紹
頭文件
#include<stdio.h>
從stdin獲取字符串
從標準輸入(stdin)中讀取字符(包括空格,Tab),並將其作為C字符串存儲到str中,直到到達換行符或文件結尾。
如果找到換行符,則不會將其復制到str中。
在復制到str的字符之後,將自動追加終止的空字符。
請註意,gets與fgets完全不同:gets不僅使用stdin作為源,而且在結果字符串中不包含結尾的換行符,並且不允許指定str的最大大小(這可能導致緩沖區溢出)。
參數
str
指向內存塊(字符數組)的char*型指針,其中讀取的字符串作為C字符串復制。
返回值
成功時,函數返回str(返回輸入字符串的起始位置)。
讀取結束(讀取到’\n’)或讀取失敗時,函數返回空指針(NULL)。
以下兩行瞭解即可
如果在嘗試讀取字符時遇到文件結尾,則設置EOF指示符(FEOF)。如果在讀取任何字符之前發生這種情況,則返回的指針為空指針(NULL)(str的內容保持不變)。
如果發生讀取錯誤,將設置錯誤指示符(ferror),並返回空指針(NULL)(但str指向的內容可能已更改)。
兼容性
C標準的最新修訂版(2011年)已明確將該功能從其規范中刪除。
該函數在C++中被禁止(如2011個標準,它遵循C9+TC3)。
用法實例
(在DEV-C++編譯器環境底下,Visual Studio 2019並不支持gets函數)
eg1:多組輸入含空格字符串,輸出其字符串長度和字符串
#include<stdio.h> #include<string.h> int main() { char str[100] = { 0 }; int len=0; while(gets(str) != NULL) //gets函數的多組輸入寫法,讀取結束或失敗時返回NULL,註意和scanf函數的多組輸入結束或失敗返回值EOF區分開 { len = strlen(str); printf("輸入的字符串%s長度是%d\n", str, len); } return 0; }
eg2:使用動態內存分配函數返回的指針接收輸入的含空格的字符串
#include<stdio.h> #include<string.h> #include<stdlib.h> int main() { char* str = (char*)calloc(100, sizeof(char)); //char* str = (char*)malloc(100 * sizeof(char)); int len=0; if(str != NULL) { while(gets(str) != NULL) //gets函數的多組輸入寫法,讀取結束或失敗時返回NULL,註意和scanf函數的多組輸入結束或失敗返回值EOF區分開 { len = strlen(str); printf("輸入的字符串%s長度是%d\n", str, len); } free(str); str=NULL; } return 0; }
eg3:由於目標指針str不允許指定str的最大大小(這裡指內存空間大小)(這可能導致緩沖區溢出)
#include<stdio.h> #include<string.h> #include<stdlib.h> int main() { char str[3] = { 0 };//創建可以存放三個字符的數組 int len=0; //輸入字符串abcdef(超過str數組長度) 這種情況下的輸出依然可以得到期望的值。 //但是,這也體現瞭gets函數在某些情況下可能會導致緩沖區溢出,這是一個不安全的函數 while(gets(str) != NULL) //gets函數的多組輸入寫法,讀取結束或失敗時返回NULL,註意和scanf函數的多組輸入結束或失敗返回值EOF區分開 { len = strlen(str); printf("輸入的字符串%s長度是%d\n", str, len); } return 0; }
gets_s函數
函數聲明
char * gets_s( char * buffer, size_t sizeInCharacters );
函數介紹
頭文件
#include<stdio.h>
參數
buffer
輸入字符串的存儲位置,char*型指針。
sizeInCharacters
緩沖區的大小。
返回值
如果成功,則返回 buffer。 NULL 指針指示錯誤或文件尾條件。 使用 ferror 或 feof 來確定發生瞭哪一個。
註解
gets_s 函數從標準輸入流 stdin 中讀取一個行並將該行存儲在 buffer中。 該行由所有字符組成,其中包含第一個換行符 ( ” \n ” ) 。 gets_s 然後,在返回行之前,將換行符替換為空字符 ( ” \0 ” ) 。 相反, fgets_s 函數將保留換行符。
如果讀取的第一個字符是文件尾字符,則空字符將存儲在 buffer 的開頭,並返回 NULL。
_getws_s 是 gets_s 的寬字符版本;其參數和返回值都是寬字符字符串。
如果 buffer 為 NULL 或 sizeInCharacters 小於或等於零,或者如果緩沖區太小,無法包含輸入行和 null 終止符(小寫的null即空字符 ( ” \0 ” )),這些函數將調用無效參數處理程序,如buffer中所述。 如果允許執行繼續,則這些函數返回 NULL 並將 errno 設置為 ERANGE。
以下兩行瞭解即可
在C++ 中,使用這些函數由模板重載簡化;重載可以自動推導出緩沖區長度 (不再需要指定大小自變量),並且它們可以自動用以更新、更安全的對應物替換舊的、不安全的函數。 有關詳細信息,請參閱安全模板重載。
默認情況下,此函數的全局狀態的作用域限定為應用程序。 若要更改此項,請參閱 CRT 中的全局狀態。
用法實例
(由於gets_s是Visual Studio 編譯器提供的安全gets函數,因此僅在該編譯器環境底下可以使用)
eg1:多組輸入,多組輸出,求含空格字符串長度,以char類型型數組存放
#include<stdio.h> #include<string.h> #define SZ 10 //根據實際輸入情況定義最長字符串長度+1即可,增加1是為瞭給'\0'留位置,這裡最長可輸入9長度的字符串 int main() { int len = 0; char str[SZ] = { 0 }; while (gets_s(str, SZ) != NULL)//這裡隻能輸入不超過SZ-1長度的字符串,否則程序崩潰,這也體現出gets_s函數的安全性極高 { len = strlen(str); printf("輸入的字符串%s長度為%d", str, len); } return 0; }
eg2:多組輸入,多組輸出,輸入處理含空格的字符串,以動態內存分配函數形式
#include<stdio.h> #include<stdlib.h> #include<string.h> #define SZ 10 //根據實際輸入情況定義最長字符串長度+1即可,增加1是為瞭給'\0'留位置,這裡最長可輸入9長度的字符串 int main() { int len = 0; char* str = (char*)malloc(SZ * sizeof(char)); // char* str = (char*)calloc(SZ, sizeof(char)); while (gets_s(str, SZ) != NULL)//這裡隻能輸入不超過SZ-1長度的字符串,否則程序崩潰,這也體現出gets_s函數的安全性極高 { len = strlen(str); printf("輸入的字符串%s長度為%d", str, len); } free(str); str=NULL; return 0; }
學習小結
這兩個函數給我們提供瞭一種新的讀取字符串的方式,與scanf函數讀取字符串的區別就在於它們可以讀取含空格,Tab的字符串。解決關於字符串OJ問題的關鍵一步,讀取輸入的字符串就得到有效的解決瞭。
在DEV-C++編譯器環境底下,直接調用gets函數即可;在Visual Studio 2019等VS編譯器底下,gets函數被gets_s函數取代,調用gets_s函數即可。
這兩個函數,註意傳遞的參數,在提交到OJ系統上時,應該使用gets函數,因為OJ系統上的編譯環境其實是DEV。
給大傢西大OJ上的一道處理含空格字符串的題目,OJ練習:OnlineJudge
西大OJ時常會出現崩潰情況,我還是把題目放底下給大傢吧。
到此這篇關於C語言通過gets和gets_s分別實現讀取含空格的字符串的文章就介紹到這瞭,更多相關C語言讀取含空格的字符串內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- C語言編程動態內存分配常見錯誤全面分析
- 詳解windows下C/C++的內存泄露檢測
- C語言中#define定義的標識符和宏實例代碼
- 深入瞭解C語言的動態內存管理
- C語言中儲存類別與內存管理的深入理解