假設我想運行以下 C 代碼段:
scanf("%d" , &some_variable);
printf("something something\n\n");
printf("Press [enter] to continue...")
getchar(); //placed to give the user some time to read the something something
這個片段不會暫停!問題是輸入流1 中scanf會留下“輸入”( \n) 字符,弄亂它后面的所有內容;在這種情況下,將吃掉而不是等待實際的新角色。getchar()\n
由于我被告知不要使用fflush(stdin)(我真的不明白為什么),所以我能夠提出的最佳解決方案就是在我的代碼開頭重新定義掃描功能:
void nsis(int *pointer){ //nsis arconim of: no shenanigans integer scanf
scanf("%d" , pointer);
getchar(); //this will clean the inputstream every time the scan function is called
}
然后我們簡單地使用nsis代替scanf. 這應該飛。然而,這似乎是一個真正的自制、與管道膠帶結合在一起的解決方案。專業的 C 開發人員如何處理這種混亂?他們根本不使用scanf嗎?他們是否只是接受使用臟輸入流?這里的標準是什么?
我無法在任何地方找到明確的答案!我能找到的每個來源都提到了一個不同的(和粗略的)解決方案......
編輯:回應所有評論“只是不要使用scanf”的某些版本:好的,我可以這樣做,但是這樣做的目的是scanf什么?它只是一個永遠不應該使用的無用的損壞功能嗎?為什么一開始就在圖書館里呢?
這似乎真的很荒謬,特別是考慮到所有初學者都被教導使用scanf......
[1]:將\n左邊后面是用戶輸入時,變數的值鍵入的一個some_variable,并且不是一個本入printf。
uj5u.com熱心網友回復:
但是 scanf 的目的是什么?
一個很好的問題。
它只是一個永遠不應該使用的無用的損壞功能嗎?
它幾乎沒用。可以說,它是非常破碎的。它幾乎不應該被使用。
為什么一開始就在圖書館里呢?
我個人認為這是一個實驗。它試圖與printf. 但事實證明這在實踐中并不是一個好主意,而且這個功能從來沒有得到太多的使用,而且幾乎不受歡迎,除了一個特定的用例......
這似乎真的很荒謬,特別是考慮到所有初學者都被教導使用 scanf...
你是絕對正確的。這真的很荒謬。
教所有初學者使用scanf. 在你的第一個 C 編程課程的第一周,你可能會撰寫這個小程式
#include <stdio.h>
int main()
{
int size = 5;
for(int i = 0; i < size; i ) {
for(int j = 0; j < size; j )
putchar('*');
putchar('\n');
}
}
列印一個正方形。在第 1 周,要制作不同大小的正方形,您只需編輯該行int size = 5;并重新編譯。
但是很快——比如說,在第 2 周——你需要一種方法讓用戶輸入正方形的大小,而無需重新編譯。您可能還沒有準備好與argv. 您可能還沒有準備好使用 讀取一行文本fgets并將其轉換回整數atoi。(你可能甚至還沒有準備好認真考慮整數5和字串之間的巨大差異"5"。)所以——在你的第一個 C 編程課程的第 2 周——scanf似乎只是一張門票。
這就是我所說的“一個特定用例”。如果你過去只scanf在第一堂 C 編程課的第二周將小整數讀入簡單的 C 程式中,事情就不會那么糟糕了。(您仍然會遇到忘記 的問題&,但這或多或少是可以管理的。)
問題是(盡管這又是我個人的信念)它并不止于此。幾乎每一位剛開始 C 班的教師都會教學生使用scanf.不幸的是,這些教師很少或根本沒有明確告訴學生這scanf是權宜之計,在第二周臨時使用,并在以后的幾周內強調畢業。而且,更糟糕的是,許多教師繼續分配問題,涉及scanf,這scanf絕對不是一個好的解決方案,例如嘗試進行穩健或“用戶友好”的輸入驗證。
scanf的唯一優點是它似乎是一種很好、簡單的方法,可以將用戶的小整數和其他簡單輸入輸入到您的早期程式中。但問題——實際上是一大堆令人不寒而栗的 17 個不同的問題——scanf結果證明它非常復雜,充滿了例外并且難以使用,這與你想要讓初學者更容易做的事情正好相反。 scanf只對初學者有用,對初學者幾乎完全沒用。它被描述為就像兒童自行車上的方形輔助輪。
專業的 C 開發人員如何處理這種混亂?
很簡單:根本不使用scanf。一方面,很少有生產 C 程式將提示列印到基于行的螢屏上并要求用戶鍵入內容,然后回傳。對于那些以這種方式作業的程式,專業的 C 開發人員會毫不猶豫地使用fgets或類似的方式將輸入的一行讀取為文本,然后使用其他技術分解該行以提取必要的資訊。
在回答您最初的問題時,沒有好的答案。scanf使用的基本規則之一(順便說一句,沒有任何教師教過的一組規則)是你永遠不應該嘗試在同一個程式中混合scanf和getchar(或fgets)。如果有一種好方法可以讓您的"Press [enter] to continue..."代碼在呼叫 后正常作業scanf,我們就不需要該規則。
If you do want to try to flush the extra newline, so that a later call to getchar will work, there are several questions here with a bunch of good answers:
- scanf() leaves the newline character in the buffer
- Using fflush(stdin)
- How to properly flush stdin in fgets loop
There's one more unrelated point that ends up being pretty significant to your question. When C was invented, there was no such thing as a GUI with multiple windows. Therefore no C programmer ever had the problem of having their output disappear before they could read it. Therefore no C programmer ever felt the need to write printf("Press [enter] to continue..."); followed by getchar(). I believe (another personal belief) that it is egregiously bad behavior for any vendor of a GUI-based C compiler to rig things up so that the output disappears upon program exit. Persistent output windows ought to be the default, for the benefit of beginning C programmers, with some kind of non-default option to turn that behavior off for those who don't want it.
uj5u.com熱心網友回復:
被scanf打破?不它不是。當您想要決議幾乎沒有錯誤的自由格式輸入資料時,它是一個出色的輸入功能。自由格式在這里意味著新行與您在普通螢屏上讀/寫很長的段落時不完全相關。當您從檔案中讀取資料時,很少會出現預期的錯誤。
該scanf家庭功能還有一個好聽點:從標準輸入流,檔案流或字串閱讀時,你有相同的語法。它可以輕松決議簡單的常見型別并提供最小的回傳值,讓謹慎的程式員知道是否可以解碼所有或部分預期資料。
話雖如此,它有一個很大的缺點:首先是一個 C 函式,它不能直接控制程式員是否傳遞了符合格式規范的型別,其次,當初學者忘記控制它的回傳值時,他們的頭不是一致的,使用它來制作完全損壞的程式真的太容易了。
但規則是:
- 如果輸入是面向行的,首先使用
fgets獲取行,然后sscanf測驗兩者的回傳值 - 只有當輸入是自由形式(不相關的換行符)時,才
scanf應該直接使用。但除了瑣碎的測驗外,永遠不要不測驗它的回傳值。
另一個缺點是初學者希望它聰明一點。它確實可以決議簡單的輸入格式,但只是一個窮人的決議器:不要將它用作通用決議器,因為這不是它的用途。
只要遵守這些規則,它就是一個與大多數 C 語言及其標準庫一致的好工具:做簡單事情的簡單工具。由程式員或庫實作者來構建更豐富的工具。
我只用了 30 多年的 C 語言,從來沒有被咬過scanf(好吧,當我還是初學者的時候,但現在我知道我應該受到責備)。簡單地說,我已經嘗試了幾十年,只將它用于它可以做的事情......
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/406085.html
標籤:
