gets() 與 scanf() 函數相處呢有點小尷尬的,就是 gets() 在 scanf() 後邊就愛搗亂。為什麼呢,先瞭解它們兩者之間的異同: 同: 都是可以接受連續的字元數據 併在字元結束後自動加上 '\0',標誌結束接受 異: scanf 不能接受空格、製表符Tab、回車等,遇空格時就結束 ...
gets() 與 scanf() 函數相處呢有點小尷尬的,就是 gets() 在 scanf() 後邊就愛搗亂。為什麼呢,先瞭解它們兩者之間的異同:
同: 都是可以接受連續的字元數據 併在字元結束後自動加上 '\0',標誌結束接受
異:
scanf 不能接受空格、製表符Tab、回車等,遇空格時就結束接受
gets 則能夠接受空格、製表符Tab和回車等,遇回車或EOF(end of file)時都會結束接受
當 gets() 在 scanf() 後,結束輸入 scanf() 後回車時,gets()就把回車這個鍵給接收了。這關鍵就在於二者使用的結束標記不同。輸入字元串時,scanf()遇到空格、回車、Tab結束,但在緩衝區中還留著這些結束符,此後如果使用gets()想去獲取下一行字元串,它碰到的卻是前面遺留下來的回車(或者回車之前還有空格等空白符),那麼這次gets()就直接失效了。所以就出現了常碰到的第一個字元串變成空白字元串的現象。之前總是遇到,於是筆者本人就繞了個彎來解決這個問題。
本人所用的是 sscanf() 這個函數(是C語言中從一個字元串中讀進與指定格式相符的數據的函數)來解決這個回車被吃掉的問題,關於 sscanf() 這個函數格式頭文件 stdio.h 中這麼描述:
_Check_return_ _CRT_INSECURE_DEPRECATE(sscanf_s)
_CRT_STDIO_INLINE int __CRTDECL sscanf(
_In_z_ char const* const _Buffer,
_In_z_ _Scanf_format_string_ char const* const _Format,
...)
sscanf(待讀進字元串,指定與字元串相符的格式,變數數據列表)
舉個粟子吧
#include<stdio.h>
int main(void)
{
int d;
char c, a[100] = "365hello", b[100];
sscanf(a, "%d%c%s", &d, &c, b);
printf("%d %c %s", d, c, b);
}
運行列印出結果 365 h ello ,這些都是符合指定的格式。也正是通過這樣,我就同時用了兩個 gets 第一個用來讀取本就在 scanf()獲取的字元信息,再通過 sscanf() 提取出可用的數據,這就有點麻煩了,不過對於特殊的輸入還是有大用處的,因為 sscanf() 支持正則表達式。比如要求輸入 m:4 而需要的數據是 4 ,那麼就可以通過 sscanf() 正則表達式來將 : 忽略掉獲取我們可用的數據。(關於強大的正則表達式可以參閱此文章 https://www.cnblogs.com/lanjianhappy/p/7171341.html)
後來,偶然的機會對嘗試了將 scanf() 和 gets() 混用,不同的是用了 getchar() 在 scanf() 後,發現竟然可以,大概的原因是 getchar() 阻止了 gets() 吃掉 scanf() 的回車。(好像是廢話。。。)再後者上網查閱了一下,原來還可以這樣的,還有個方法就是在 scanf() 後加上個 scanf("\n") 算是再加上一個回車符來補充被 gets() 吃掉的回車吧。
像這樣就對了,簡單的可以用 scanf() 解決的就這樣咯,同時也可適用 C++ 的 cin 不用像筆者那樣來個 雙gets() 來加上個 sscanf() 當然用用也無妨,特殊情況也是有的嘛。
#include<stdio.h>
int main(void)
{
int n;
char a[100];
scanf("%d", &n); //或這樣 不用下一條的 scanf("\n"); 直接這樣 scanf("%d\n", &n);
scanf("\n");
gets_s(a);
puts(a);
}