au加载默认的输入和输出设备失败_一文带你读懂 C/C++ 语言输入输出流与缓存区...
(給CPP開發者加星標,提升C/C++技能)
作者:技術讓夢想更偉大 / 李肖遙 (本文來自作者投稿)
前言
有沒有發現,基本上所有的C語言入門書籍,或者是我們的教程里面,第一個C語言程序實體,都是“Hello World!”;我不知道這是不是行業的“潛規則”,總之,它把無數的程序員帶進了計算機的世界,步入了代碼的大坑里,所以你好,世界!
一件趣事
我記得大學學習計算機的時候,就是在電腦這樣的一個程序,不知道經過了什么過程,就能在計算機上顯示出"Hello World!"。后來我把這個"Hello World!"改成了"I Love xxx!",哦買噶,真是驚呆我了,有一種立馬在女神面前炫耀的感覺了.
那么,這其中有什么奧妙呢,我們從C語言的輸入輸出流開始說起.
hello world 是怎么顯示出來的
對的,就是這樣的一個程序
#include?在我們日常生活中,總看到電子顯示屏上面顯示著"歡迎某位領導蒞臨我校觀察","賓館"之類的,那是不是"Hello World!"也是這樣編譯出來的呢?
我們看到程序中的printf();由系統或者編譯器提供商提供的一個應用接口,是格式化輸出函數, 一般用于向標準輸出設備按規定格式輸出信息。一般其函數原型應該是這樣的:
printf(const char *,...);printf,?(const?char?*__restrict,?...)經過預處理,編譯,匯編,鏈接四個過程,借助了相應的緩沖區來進行輸入與輸出,就會顯示出來輸入輸出流
流是什么
“流”即是流動的意思,是物質從一處向另一處流動的過程,是對一種有序連續且具有方向性的數據的抽象描述。
在計算機系統中是指信息從外部輸入設備向計算機內部輸入,或者從內存向外部輸出設備輸出的過程。這種輸入輸出的過程被形象的比喻為“流”。
輸入輸出
什么是輸入輸出呢?C語言中我們用到的最頻繁的輸入輸出方式就是scanf()與printf()。
scanf():從標準輸入設備(鍵盤)讀取數據,并將值存放在變量中。
printf():將指定的文字/字符串輸出到標準輸出設備(屏幕)。注意寬度輸出和精度輸出控制。
字符輸入輸出(getchar/putchar),字符串輸入輸出函數 (gets與puts),與gets/puts類似的還有fgets與fputs,它們一般用于對文件的操作.
緩沖區
定義
緩沖區是內存空間的一部分,也就是說在內存空間中預留了一定大小的存儲空間,這些存儲空間用來緩沖輸入或輸出的數據,這部分預留的空間就叫做緩沖區,根據其對應的是輸入設備還是輸出設備,分為輸入緩沖區和輸出緩沖區。
原理介紹
當調用輸入函數scanf()時,輸入函數會將我們輸入的數字輸入到輸入緩沖區,而當我們的輸入緩沖區有內容時,再次輸入將不會被執行,而是直接跳過執行,將輸入緩沖區的內容賦給變量。
引入緩沖區的意義
緩沖區就是一塊內存,用來做數據的一個臨時存放點,在輸入輸出操作中起著至關重要的作用,在百度百科定義如下
比如我想把一篇文章以字符序列的方式輸出到計算機顯示器屏幕上,那么我的程序內存作為數據源而顯示器驅動程序作為數據目標,如果數據源直接對數據目標發送數據的話。數據目標獲得第一個字符,便將它顯示。然后從端口讀取下一個字符,可是這時就不能保證數據源向端口發送的恰好是第二個字符(也許是第三個,而第二個已經在數據目標顯示時發送過了)。這樣的話就不能保證輸出的數據能完整的被數據目標所接受并處理。
緩沖區的類型
緩沖區有三種,我一個一個地說下:
1、全緩沖
內存中有一段存儲區域,比如有1024個字節大小,有一個程序會從這段存儲區域中讀取數據。現在系統把一個文件的內容放入這個存儲區,只要1024個字節都放滿了,那么程序會立即來讀取這1024個字節的數據。只要1024個字節沒有放滿,哪怕只放了1023個字節,程序都不會來讀取,這就是全緩沖的意思。
#include??編譯并執行,運行結果如下:
此時打開工程所在文件夾下的test.txt文件,您會發現該文件是空的,這說明4096個字符“a”還在緩沖區,并沒有真正執行I/O操作。敲一下回車鍵,窗口變為如下:
此時再打開test.txt文件,您就會發下該文件中已經有了4096個字符“a”。這說明全緩沖區的大小是4K(4096),緩沖區滿后執行了I/O操作,而字符“b”還在緩沖區。
再次敲一下回車鍵,窗口變為如下: 此時再打開test.txt文件,您就會發現字符“b”也在其中了。這一步驗證了文件關閉時刷新了緩沖區。
2、行緩沖
內存中有一段存儲區域,比如有1024個字節大小,有一個程序會從這段存儲區域中讀取數據。現在系統把一個文件的內容放入這個存儲區,假如放了10個字節的數據,你敲了回車鍵,那么程序就馬上來讀取了。假如放了20個字節,你敲了回車獎,程序也會來讀取。所以即使1024個字節沒有放滿,但是你敲了回車鍵,程序就會來讀取,這個就叫做行緩沖。
使用鍵盤操作演示行緩沖,先介紹getchar()函數。函數原型:
int?getchar(void)?;說明:當程序調用getchar()函數時,程序就等著用戶按鍵,用戶輸入的字符被存放在鍵盤緩沖區中,直到用戶按回車為止(回車字符也放在緩沖區中)。當用戶鍵入回車之后,getchar()函數才開始從鍵盤緩沖區中每次讀入一個字符。也就是說,后續的getchar()函數調用不會等待用戶按鍵,而直接讀取緩沖區中的字符,直到緩沖區中的字符讀完后,才重新等待用戶按鍵。
#include?最后輸出結果是
a ,b ,c ,d ,e ,f可以交替按下一些字符,編譯結果如下:
當按到第4096個字符時,提示您不能再按下去,說明行緩存的大小是4k,此時按下回車鍵,返回第一個字符是‘a’繼續敲下回車鍵,緩存區的其他字符就全部輸出
3、無緩沖
內存中有一段存儲區域,比如有1024個字節大小,有一個程序會從這段存儲區域中讀取數據。現在系統把一個文件的內容放入這個存儲區,剛放了1個字節,程序就馬上來讀取了;又放了一個字節,程序又馬上來讀取了,這就是沒有緩沖。
在C語言中,一般規定是要有行緩沖的。但是使用scanf函數和getchar時,如果行緩沖的換行符沒有處理好,程序運行可能會有異常或者閃退等現象。也就是不進行緩沖,標準出錯情況stderr是典型代表,這使得出錯信息可以直接盡快地顯示出來。
如錯誤輸出時使用:
cerr<這條語句等效于:
fprintf(stderr,?”錯誤,請檢查輸入的參數!”)?;緩沖區的大小
如果我們沒有自己設置緩沖區的話,系統會默認為標準輸入輸出設置一個緩沖區,這個緩沖區的大小通常是 512個字節 的大小。
緩沖區大小由 stdio.h 頭文件中的宏 BUFSIZ 定義,如果希望查看它的大小,包含頭文件,直接輸出它的值即可:
printf(緩沖區的大小是可以改變的,也可以將文件關聯到自定義的緩沖區,詳情可以查看 setvbuf()和 setbuf() 函數。
緩沖區的刷新
下列情況會引發緩沖區的刷新:
- 緩沖區滿時;
- 執行flush語句,即使用特定函數刷新緩沖區;
- 執行endl語句,即行緩沖區遇到回車時;
- 關閉文件。
可見,緩沖區滿或關閉文件時都會刷新緩沖區,進行真正的I/O操作。另外,在C++中,我們可以使用flush函數來刷新緩沖區(執行I/O操作并清空緩沖區) 如:
cout?<endl控制符的作用是將光標移動到輸出設備中下一行開頭處,并且清空緩沖區。
cout?相當于
cout?強制緩沖區的數字打印
/*?輸出緩沖區演示?
*/?
#include?
int?main(){?
????printf("1\n");?
????fflush(stdout);?//強制將輸出緩沖區的內容顯示在屏幕上?
????while?(1){
????}?
????return?0;?
}
如何清空輸入緩沖區的內容?
如果我想讓getchar()每次都能夠等待用戶輸入的話就要清空緩沖區,下面就介紹不同平臺的方法
C標準規定 fflush()函數是用來刷新輸出(stdout)緩存的。對于輸入(stdin),它是沒有定義的。但是有些編譯器也定義了 fflush( stdin )的實現,比如微軟的VC。其它編譯器是否也定義了 fflush( stdin )的實現應當查找它的手冊。GCC編譯器沒有定義它的實現,所以不能使用 fflush( stdin )來刷新輸入緩存。
對于沒有定義 fflush( stdin )的編譯器,可以使用 fgets()函數來代替它(比用 getchar()、scanf()等函數通用性好)。可以這樣忽略輸入流中留下的回車等其它輸入,從而使下一次的輸入總是保持一個“干凈”的狀態。(這個是任何平臺下都可以的)
char?sbuf[1024];//?...
fgets(?sbuf,?1024,?stdin?);
//?...
在windows 的vc下面就可以這樣了:
for(int?i=0;i<10;++i)這里說到gcc編譯器沒有定義fflush的實現,我們一般用getchar();來清除緩沖區
#include?輸入:ssss,回車得到:ssss,光標處(等待輸入)
說明:?此時程序沒有結束,進行到for循環,因為并沒有字符a出現,所以還沒跳出for循環.鍵入回車后,getchar依次從緩沖區內取出(for循環):'s''s''s''s''\n'
如果我們輸入:ssssa,回車得到:ssssa,光標處(等待輸入)
說明:?程序已經跳出for循環,但是由于我們用getchar();清除了換行'\n',后面第7句c=getchar();需要你輸入一個字符(因為ssssa后面并沒有新的字符),所以程序仍然沒有結束.
如果我們注釋掉getchar();這一句,那么得到:ssss,光標處(程序結束) 這個輸入ssssa是的回車中的換行符'\n'就被c=getchar();這一句讀取并輸出了。
總結:鍵盤輸入的字符都存到緩沖區內,一旦鍵入回車,getchar就進入緩沖區讀取字符,一次只返回第一個字符作為getchar函數的值,如果有循環或足夠多的getchar語句,就會依次讀出緩沖區內的所有字符直到'\n'.
要理解這一點,之所以你輸入的一系列字符被依次讀出來,是因為循環的作用使得反復利用getchar在緩沖區里讀取字符,而不是ge
最后
很多表面的現象看起來可能不能引起我們的注意,但是當我們注意到細節的時候,才能深究其中的奧秘,寫代碼亦是如此。
- EOF -
推薦閱讀??點擊標題可跳轉1、真的可以,用 C 語言實現面向對象編程 OOP
2、C語言與C++面試知識總結
3、一文讀懂 C 語言與 C++ 動態內存
看完本文有幫助?請分享給更多人
關注「CPP開發者」加星標,提升C/C++技能
好文章,我在看??
總結
以上是生活随笔為你收集整理的au加载默认的输入和输出设备失败_一文带你读懂 C/C++ 语言输入输出流与缓存区...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch tensor_[PyTo
- 下一篇: c++ socket编程_C/C++中的