C語言一般使用scanf處理輸入,若是要讀取字符串,那麼就須要定義一個字符數組(char[]
)。但是,若是數組定義長度不足,就可能發生溢出。數組
在C語言裏有個能夠用來讀取字符的函數(getchar
),咱們能夠利用這個函數來實現不定長的字符串輸入。下面咱們就來說講如何作到這一點。函數
首先,說一下原理:getchar
每次只能讀取一個字符。所以,我經過循環使用getchar
逐個讀取字符的方式,將全部輸入字符讀取。指針
那麼,咱們要先解決一個問題:code
何時結束循環再也不讀取呢?內存
當咱們輸入字符串後,按下Enter鍵,那麼輸入的字符串就會被程序接收,寫入輸入緩衝區的除了剛纔輸入的字符串,還會有一個換行符\n
,所以getchar
當讀取到字符\n
時,便可跳出循環,完成讀取。跳出循環後咱們還要在後面加上\0
,這樣,它才能成爲一個真正的字符串。字符串
第二問題:get
存放在哪兒?class
當咱們使用scanf
讀取字符串時,咱們將字符串存放在字符數組(char[]
)裏面,那麼咱們使用循環讀取字符時,就須要有一個一樣連續的內存空間來存放讀取到的字符。並且,咱們由於不知道到底會讀取到多長的字符串,長度是不固定的,因此使用malloc
來動態申請一個連續的內存空間。原理
所以,咱們準備兩塊內存指針:內存泄漏
char* str; char* _str;
先給其中一個分配2個char
的內存空間(一個用來存\0
),同時用i來記錄輸入字符串的個數。
int i = 1; str = (char*)malloc(sizeof(char) * (i + 1));
而後,再用循環讀取字符,並把它存到申請的內存空間。
while('\n' != (str[i - 1] = getchar())) { i++; ... }
每次咱們讀取到一個字符時,就將i
加一。因此循環體開始的時候是i++
(剛讀完一個字符)。
如今,重點來了,由於咱們要預先申請多一個長度的內存,而後才能繼續存放接下來要讀的字符。因此咱們須要把str釋放掉,而後從新申請空間,但是,直接釋放會把原來讀的字符都弄丟,因此就到_str
出場了。
咱們先給_str
申請與str
相同長的內存空間 。而後,把str
的內容拷貝到_str裏。這時,就能夠把str
釋放掉了。在給str
從新申請內存空間成功後,把_str
的內容拷貝回來,而後釋放掉_str
就行了。
_str = (char*)malloc(strlen(str) + 1); str[i - 1] = '\0'; strcpy(_str, str); free(str); str = (char*)malloc(sizeof(char) * (i + 1)); if(NULL == str) { free(_str); printf("No enough memory!"); return NULL; } strcpy(str, _str); free(_str);
值得注意的是,在給str
從新申請內存空間後,須要判斷一下str
內存申請是否成功。若是失敗(NULL == str
),咱們須要先將_str
釋放掉(防止出現內存泄漏),再return NULL
。
最後,咱們只要將\0
加上,把str
的內存地址返回,就大功告成了。
str[i - 1]='\0'; return str;
附上完整代碼:
char* getstr() { char* str; char* _str; int i = 1; str = (char*)malloc(sizeof(char) * (i + 1)); while('\n' != (str[i - 1] = getchar())) { i ++; _str = (char*)malloc(strlen(str) + 1); str[i - 1] = '\0'; strcpy(_str, str); free(str); str = (char*)malloc(sizeof(char) * (i + 1)); if(NULL == str) { free(_str); printf("No enough memory!"); return NULL; } strcpy(str, _str); free(_str); } str[i - 1] = '\0'; return str; }