C 中為什麼按兩次ctrl D才能結束標準I O

2021-10-08 08:23:12 字數 2221 閱讀 6303

參考資料:

今天學習了c++語言的標準i/o,也就是std::cin和std::cout,但是我發現當系統在讀取標準的輸入後需要按兩次ctrl+d或者按一次回車再按一次ctrl+d才能結束標準i/o,翻閱相關資料後我把這個問題研究透徹了記錄在此。(使用類unix系統,所以eof是ctrl+d,windows上可能是ctrl+z)

首先我們必須知道乙個概念:緩衝區,緩衝區是幹什麼的?

我們為什麼要引入緩衝區?

比如我們從磁碟裡取資訊,我們先把讀出的資料放在緩衝區,計算機再直接從緩衝區中取資料,等緩衝區的資料取完後再去磁碟中讀取,這樣就可以減少磁碟的讀寫次數,再加上計算機對緩衝區的操作大大快於對磁碟的操作,故應用緩衝區可大大提高計算機的執行速度。

又比如,我們使用印表機列印文件,由於印表機的列印速度相對較慢,我們先把文件輸出到印表機相應的緩衝區,印表機再自行逐步列印,這時我們的cpu可以處理別的事情。現在您基本明白了吧,緩衝區就是一塊記憶體區,它用在輸入輸出裝置和cpu之間,用來快取資料。它使得低速的輸入輸出裝置和高速的cpu能夠協調工作,避免低速的輸入輸出裝置占用cpu,解放出cpu,使其能夠高效率工作。  

緩衝區的種類?

全緩衝:在這種情況下,當填滿標準i/o快取後才進行實際i/o操作。全緩衝的典型代表是對磁碟檔案的讀寫。

行緩衝:在這種情況下,當在輸入和輸出中遇到換行符時,執行真正的i/o操作。這時,我們輸入的字元先存放在緩衝區,等按下回車鍵換行時才進行實際的i/o操作。典型代表是鍵盤輸入資料。

不帶緩衝:也就是不進行緩衝,標準出錯情況stderr是典型代表,這使得出錯資訊可以直接盡快地顯示出來。 

我們研究的物件是鍵盤的輸入,也就是行緩衝了,下面用乙個例子說明問題:

#include /*

* ****** main function:

* read several numbers and write their sum

*/int main()

std::cout << "the sum is " << sum << std::endl;

return 0;

}

在這個例子中我們從標準輸入中取值,賦給val,當賦給val的值是可用的值時,while迴圈繼續,否則打破迴圈。

讀者可以試驗一下這兩種情況:

1.執行程式之後輸入1 2 3然後按回車鍵,此時程式不結束,再按ctrl+d鍵,也就是輸入eof,程式給出輸出6。

2.執行程式之後輸入1 2 3 (注意3後面我多輸入乙個空格,上面那個例子我不輸入)然後按ctrl+d,沒反應,再按ctrl+d,程式輸出6。

我們用學到的緩衝區的知識細緻細緻再細緻地分析這個過程:

第一種情況:

輸入1 2 3,此時緩衝區是這樣的:'1' '空格' '2' '空格' '3',因為行緩衝,輸入回車後'1' '空格' '2' '空格' '3' '回車'被送給cpu,也就是送給while了,while拿到資料後很高興,按照空格和回車都是分割符的原理,將1 2 3交給val加了起來。此時緩衝區呢:空了!!但是程式還在期待輸入,但我不想再輸入了,那麼在乙個空的緩衝區中輸入ctrl+d就可以直接結束標準輸入。

第二種情況:

輸入1 2 3 (3後面有空格),此時緩衝區是這樣的:'1' '空格' '2' '空格' '3' '空格',根據eof符號的定義,此時我們打出eof符號(ctrl+d)。'1' '空格' '2' '空格' '3' '空格'被送給cpu,同時eof被丟棄了。while拿到資料後又很高興,按照空格是分割符的原理,將1 2 3交給val加了起來。但是輸入還沒完啊,此時'1' '空格' '2' '空格' '3' '空格'交給cpu了,eof被丟棄了,緩衝區是不是空了?此時再打出eof符號,標準輸入即被關閉。

讀者可能會問為什麼第二種情況在3後面要加上空格,是這樣的,可以考慮不加空格是什麼樣的結果:cpu會拿到'1' '空格' '2' '空格' '3',此時因為3後面沒有分隔符,那麼我們此時輸入eof就是把標準輸入截斷了。假如我們輸入'8' '空格',再按兩次ctrl+d,此時sum的加和是1+2+38=41,所以說這種情況就和std::cin傳值機理的問題了,和緩衝區的原理關係不大。

總結一下:

回車鍵的效果:將緩衝區連帶自身傳給cpu,緩衝區清空。

ctrl+d(eof)的效果:將緩衝區不帶自身傳給cpu,緩衝區清空。

緩衝區為空時收到eof,標準檔案輸入關閉!

qemu中daemonize為什麼要兩次fork

函式void os daemonize void 將當前程序變成後台程序即放棄終端。一開始不理解為什麼要兩次fork,後來查網上資料得知,兩次fork是為了防止第乙個子程序開啟終端。首次fork使父程序退出,子程序繼承了父程序的程序組id,但具有乙個新的程序id,這就保證了子程序不是乙個程序組的首程...

為什麼Action中的介面執行了兩次

問題場景 程式中的方法莫名其妙的執行了兩次,導致結果與預期的不一致 比如 呼叫介面傳送簡訊驗證,收到了兩次簡訊,傳送時間幾乎相同 問題分析 1.struts2中action呼叫兩次問題 struts2 中json的原理是在action中的get方法都會序列化,所以前面是get的方法只要沒指定不序列化...

daemon 程序為什麼要fork兩次

daemon 程序為什麼要fork兩次 daemon程序是後台守護程序,有時候也叫精靈程序 agent linux下server都是daemon程序。相信大部分開發人員都知道如何去寫乙個daemon程序。但是另一方面,大部分人不知道為什麼要這麼做,不少人是從某個地方copy乙個函式,拿來主義。但是具...