當(dāng)前位置:首頁 > 公眾號精選 > C語言與CPP編程
[導(dǎo)讀]前言 有沒有發(fā)現(xiàn),基本上所有的C語言入門書籍,或者是我們的教程里面,第一個(gè)C語言程序?qū)嶓w,都是“Hello World!”;我不知道這是不是行業(yè)的“潛規(guī)則”,總之,它把無數(shù)的程序員帶進(jìn)了計(jì)算機(jī)的世界,步入了代碼的大坑里,所以你好,世界! 一件趣事 我記得大學(xué)學(xué)習(xí)計(jì)


前言

有沒有發(fā)現(xiàn),基本上所有的C語言入門書籍,或者是我們的教程里面,第一個(gè)C語言程序?qū)嶓w,都是“Hello World!”;我不知道這是不是行業(yè)的“潛規(guī)則”,總之,它把無數(shù)的程序員帶進(jìn)了計(jì)算機(jī)的世界,步入了代碼的大坑里,所以你好,世界!

一件趣事

我記得大學(xué)學(xué)習(xí)計(jì)算機(jī)的時(shí)候,就是在電腦這樣的一個(gè)程序,不知道經(jīng)過了什么過程,就能在計(jì)算機(jī)上顯示出"Hello World!"。后來我把這個(gè)"Hello World!"改成了"I Love xxx!",哦買噶,真是驚呆我了,有一種立馬在女神面前炫耀的感覺了.

那么,這其中有什么奧妙呢,我們從C語言的輸入輸出流開始說起.

hello world 是怎么顯示出來的

對的,就是這樣的一個(gè)程序

#include <stdio.h>
int main(int argc,char **argv)
{
  //printf("Hello World!");
  printf("I Love xxx!");
}

在我們?nèi)粘I钪?總看到電子顯示屏上面顯示著"歡迎某位領(lǐng)導(dǎo)蒞臨我校觀察","賓館"之類的,那是不是"Hello World!"也是這樣編譯出來的呢?

我們看到程序中的printf();由系統(tǒng)或者編譯器提供商提供的一個(gè)應(yīng)用接口,是格式化輸出函數(shù), 一般用于向標(biāo)準(zhǔn)輸出設(shè)備按規(guī)定格式輸出信息。一般其函數(shù)原型應(yīng)該是這樣的:

int  printf(const char *,...);
int _EXFUN(printf, (const char *__restrict, ...)
    _ATTRIBUTE ((__format__ (__printf__, 1, 2))));

經(jīng)過預(yù)處理,編譯,匯編,鏈接四個(gè)過程,借助了相應(yīng)的緩沖區(qū)來進(jìn)行輸入與輸出,就會顯示出來輸入輸出流

流是什么

“流”即是流動(dòng)的意思,是物質(zhì)從一處向另一處流動(dòng)的過程,是對一種有序連續(xù)且具有方向性的數(shù)據(jù)的抽象描述。

在計(jì)算機(jī)系統(tǒng)中是指信息從外部輸入設(shè)備向計(jì)算機(jī)內(nèi)部輸入,或者從內(nèi)存向外部輸出設(shè)備輸出的過程。這種輸入輸出的過程被形象的比喻為“”。

輸入輸出

什么是輸入輸出呢?C語言中我們用到的最頻繁的輸入輸出方式就是scanf()與printf()。

scanf():從標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)讀取數(shù)據(jù),并將值存放在變量中。

printf():將指定的文字/字符串輸出到標(biāo)準(zhǔn)輸出設(shè)備(屏幕)。注意寬度輸出和精度輸出控制。

字符輸入輸出(getchar/putchar),字符串輸入輸出函數(shù) (gets與puts),與gets/puts類似的還有fgets與fputs,它們一般用于對文件的操作.

緩沖區(qū)

定義

緩沖區(qū)是內(nèi)存空間的一部分,也就是說在內(nèi)存空間中預(yù)留了一定大小的存儲空間,這些存儲空間用來緩沖輸入或輸出的數(shù)據(jù),這部分預(yù)留的空間就叫做緩沖區(qū),根據(jù)其對應(yīng)的是輸入設(shè)備還是輸出設(shè)備,分為輸入緩沖區(qū)輸出緩沖區(qū)。

原理介紹

當(dāng)調(diào)用輸入函數(shù)scanf()時(shí),輸入函數(shù)會將我們輸入的數(shù)字輸入到輸入緩沖區(qū),而當(dāng)我們的輸入緩沖區(qū)有內(nèi)容時(shí),再次輸入將不會被執(zhí)行,而是直接跳過執(zhí)行,將輸入緩沖區(qū)的內(nèi)容賦給變量。

引入緩沖區(qū)的意義

緩沖區(qū)就是一塊內(nèi)存,用來做數(shù)據(jù)的一個(gè)臨時(shí)存放點(diǎn),在輸入輸出操作中起著至關(guān)重要的作用,在百度百科定義如下

比如我想把一篇文章以字符序列的方式輸出到計(jì)算機(jī)顯示器屏幕上,那么我的程序內(nèi)存作為數(shù)據(jù)源而顯示器驅(qū)動(dòng)程序作為數(shù)據(jù)目標(biāo),如果數(shù)據(jù)源直接對數(shù)據(jù)目標(biāo)發(fā)送數(shù)據(jù)的話。數(shù)據(jù)目標(biāo)獲得第一個(gè)字符,便將它顯示。然后從端口讀取下一個(gè)字符,可是這時(shí)就不能保證數(shù)據(jù)源向端口發(fā)送的恰好是第二個(gè)字符(也許是第三個(gè),而第二個(gè)已經(jīng)在數(shù)據(jù)目標(biāo)顯示時(shí)發(fā)送過了)。這樣的話就不能保證輸出的數(shù)據(jù)能完整的被數(shù)據(jù)目標(biāo)所接受并處理。

緩沖區(qū)的類型

緩沖區(qū)有三種,我一個(gè)一個(gè)地說下:

1、全緩沖

內(nèi)存中有一段存儲區(qū)域,比如有1024個(gè)字節(jié)大小,有一個(gè)程序會從這段存儲區(qū)域中讀取數(shù)據(jù)?,F(xiàn)在系統(tǒng)把一個(gè)文件的內(nèi)容放入這個(gè)存儲區(qū),只要1024個(gè)字節(jié)都放滿了,那么程序會立即來讀取這1024個(gè)字節(jié)的數(shù)據(jù)。只要1024個(gè)字節(jié)沒有放滿,哪怕只放了1023個(gè)字節(jié),程序都不會來讀取,這就是全緩沖的意思。

#include <fstream> 
using namespace std; 

int main() 

    //創(chuàng)建文件test.txt并打開 
   ofstream outfile("test.txt"); 

    //向test.txt文件中寫入4096個(gè)字符’a’ 
   for(int n=0; n < 4096; n++) 
    { 
        outfile << 'a'
    }

    //暫停,按任意鍵繼續(xù) 
   system("PAUSE"); 

    //繼續(xù)向test.txt文件中寫入字符’b’,也就是說,第4097個(gè)字符是’b’ 
   outfile << 'b'

    //暫停,按任意鍵繼續(xù) 
   system("PAUSE"); 

  return 0; 
}

編譯并執(zhí)行,運(yùn)行結(jié)果如下:

此時(shí)打開工程所在文件夾下的test.txt文件,您會發(fā)現(xiàn)該文件是空的,這說明4096個(gè)字符“a”還在緩沖區(qū),并沒有真正執(zhí)行I/O操作。敲一下回車鍵,窗口變?yōu)槿缦拢?/p>

此時(shí)再打開test.txt文件,您就會發(fā)下該文件中已經(jīng)有了4096個(gè)字符“a”。這說明全緩沖區(qū)的大小是4K(4096),緩沖區(qū)滿后執(zhí)行了I/O操作,而字符“b”還在緩沖區(qū)。

再次敲一下回車鍵,窗口變?yōu)槿缦拢骸 〈藭r(shí)再打開test.txt文件,您就會發(fā)現(xiàn)字符“b”也在其中了。這一步驗(yàn)證了文件關(guān)閉時(shí)刷新了緩沖區(qū)。

2、行緩沖

內(nèi)存中有一段存儲區(qū)域,比如有1024個(gè)字節(jié)大小,有一個(gè)程序會從這段存儲區(qū)域中讀取數(shù)據(jù)?,F(xiàn)在系統(tǒng)把一個(gè)文件的內(nèi)容放入這個(gè)存儲區(qū),假如放了10個(gè)字節(jié)的數(shù)據(jù),你敲了回車鍵,那么程序就馬上來讀取了。假如放了20個(gè)字節(jié),你敲了回車獎(jiǎng),程序也會來讀取。所以即使1024個(gè)字節(jié)沒有放滿,但是你敲了回車鍵,程序就會來讀取,這個(gè)就叫做行緩沖。

使用鍵盤操作演示行緩沖,先介紹getchar()函數(shù)。函數(shù)原型:

int getchar(void) ;

說明:當(dāng)程序調(diào)用getchar()函數(shù)時(shí),程序就等著用戶按鍵,用戶輸入的字符被存放在鍵盤緩沖區(qū)中,直到用戶按回車為止(回車字符也放在緩沖區(qū)中)。當(dāng)用戶鍵入回車之后,getchar()函數(shù)才開始從鍵盤緩沖區(qū)中每次讀入一個(gè)字符。也就是說,后續(xù)的getchar()函數(shù)調(diào)用不會等待用戶按鍵,而直接讀取緩沖區(qū)中的字符,直到緩沖區(qū)中的字符讀完后,才重新等待用戶按鍵。

#include<iostream> 
using namespace std; 

int main() 
{  

    char c;  
  //第一次調(diào)用getchar()函數(shù),程序執(zhí)行時(shí),您可以輸入一串字符并按下回車鍵,按下回車鍵后該函數(shù)返回。返回值是用戶輸入的第一個(gè)字符 (假設(shè)用戶輸入了 abcdef,函數(shù)返回a)
   c = getchar(); 
    //顯示getchar()函數(shù)的返回值
   cout<< c << endl; // 輸出 a  
  // 循環(huán)多次調(diào)用getchar()函數(shù),將每次調(diào)用getchar()函數(shù)的返回值顯示出來,直到遇到回車符才結(jié)束。 這時(shí)函數(shù)執(zhí)行不會讓用戶輸入而是順序讀取緩沖區(qū)字符內(nèi)容。第一個(gè)字符用戶輸入結(jié)束后已經(jīng)讀取,所以會從第二個(gè)字符開始讀
   while((c = getchar())!='\n'
   { 
       cout<< "," << c <<endl 
   } 

   return 0;
}

最后輸出結(jié)果是

a ,b ,c ,d ,e ,f可以交替按下一些字符,編譯結(jié)果如下:

當(dāng)按到第4096個(gè)字符時(shí),提示您不能再按下去,說明行緩存的大小是4k,此時(shí)按下回車鍵,返回第一個(gè)字符是‘a(chǎn)’繼續(xù)敲下回車鍵,緩存區(qū)的其他字符就全部輸出

3、無緩沖

內(nèi)存中有一段存儲區(qū)域,比如有1024個(gè)字節(jié)大小,有一個(gè)程序會從這段存儲區(qū)域中讀取數(shù)據(jù)?,F(xiàn)在系統(tǒng)把一個(gè)文件的內(nèi)容放入這個(gè)存儲區(qū),剛放了1個(gè)字節(jié),程序就馬上來讀取了;又放了一個(gè)字節(jié),程序又馬上來讀取了,這就是沒有緩沖。

在C語言中,一般規(guī)定是要有行緩沖的。但是使用scanf函數(shù)和getchar時(shí),如果行緩沖的換行符沒有處理好,程序運(yùn)行可能會有異常或者閃退等現(xiàn)象。也就是不進(jìn)行緩沖,標(biāo)準(zhǔn)出錯(cuò)情況stderr是典型代表,這使得出錯(cuò)信息可以直接盡快地顯示出來。

如錯(cuò)誤輸出時(shí)使用:

cerr<<”錯(cuò)誤,請檢查輸入的參數(shù)!” ;

這條語句等效于:

fprintf(stderr, ”錯(cuò)誤,請檢查輸入的參數(shù)!”) ;

緩沖區(qū)的大小

如果我們沒有自己設(shè)置緩沖區(qū)的話,系統(tǒng)會默認(rèn)為標(biāo)準(zhǔn)輸入輸出設(shè)置一個(gè)緩沖區(qū),這個(gè)緩沖區(qū)的大小通常是 512個(gè)字節(jié) 的大小。

緩沖區(qū)大小由 stdio.h 頭文件中的宏 BUFSIZ 定義,如果希望查看它的大小,包含頭文件,直接輸出它的值即可:

printf("%d", BUFSIZ);

緩沖區(qū)的大小是可以改變的,也可以將文件關(guān)聯(lián)到自定義的緩沖區(qū),詳情可以查看 setvbuf()和 setbuf() 函數(shù)。

緩沖區(qū)的刷新

下列情況會引發(fā)緩沖區(qū)的刷新:

  • 緩沖區(qū)滿時(shí);
  • 執(zhí)行flush語句,即使用特定函數(shù)刷新緩沖區(qū);
  • 執(zhí)行endl語句,即行緩沖區(qū)遇到回車時(shí);
  • 關(guān)閉文件。

可見,緩沖區(qū)滿或關(guān)閉文件時(shí)都會刷新緩沖區(qū),進(jìn)行真正的I/O操作。另外,在C++中,我們可以使用flush函數(shù)來刷新緩沖區(qū)(執(zhí)行I/O操作并清空緩沖區(qū)) 如:

cout << flush; //將顯存的內(nèi)容立即輸出到顯示器上進(jìn)行顯示

endl控制符的作用是將光標(biāo)移動(dòng)到輸出設(shè)備中下一行開頭處,并且清空緩沖區(qū)。

cout < < endl;

相當(dāng)于

cout < < ”\n”< < flush;

強(qiáng)制緩沖區(qū)的數(shù)字打印

/* 
輸出緩沖區(qū)演示 
*/ 
#include <stdio.h>
int main(){ 
    printf("1\n"); 
    fflush(stdout); //強(qiáng)制將輸出緩沖區(qū)的內(nèi)容顯示在屏幕上 
    while (1){
    } 
    return 0; 
}

如何清空輸入緩沖區(qū)的內(nèi)容?

如果我想讓getchar()每次都能夠等待用戶輸入的話就要清空緩沖區(qū),下面就介紹不同平臺的方法

C標(biāo)準(zhǔn)規(guī)定 fflush()函數(shù)是用來刷新輸出(stdout)緩存的。對于輸入(stdin),它是沒有定義的。但是有些編譯器也定義了 fflush( stdin )的實(shí)現(xiàn),比如微軟的VC。其它編譯器是否也定義了 fflush( stdin )的實(shí)現(xiàn)應(yīng)當(dāng)查找它的手冊。GCC編譯器沒有定義它的實(shí)現(xiàn),所以不能使用 fflush( stdin )來刷新輸入緩存。

對于沒有定義 fflush( stdin )的編譯器,可以使用 fgets()函數(shù)來代替它(比用 getchar()、scanf()等函數(shù)通用性好)??梢赃@樣忽略輸入流中留下的回車等其它輸入,從而使下一次的輸入總是保持一個(gè)“干凈”的狀態(tài)。(這個(gè)是任何平臺下都可以的)

char sbuf[1024];
// ...
fgets( sbuf, 1024, stdin );
// ...

在windows 的vc下面就可以這樣了:

for(int i=0;i<10;++i)
{
    char ch=getchar();
    fflush(stdin); //每次都會有等待狀態(tài)了
}

這里說到gcc編譯器沒有定義fflush的實(shí)現(xiàn),我們一般用getchar();來清除緩沖區(qū)

#include <stdio.h>
main()
{
    char c;
   for(;(c=getchar())!='a';)
   printf("%c",c);
   getchar();
    c=getchar();
   printf("%c",c);
}

輸入:ssss,回車得到:ssss,光標(biāo)處(等待輸入)

說明: 此時(shí)程序沒有結(jié)束,進(jìn)行到for循環(huán),因?yàn)椴]有字符a出現(xiàn),所以還沒跳出for循環(huán).鍵入回車后,getchar依次從緩沖區(qū)內(nèi)取出(for循環(huán)):'s''s''s''s''\n'

如果我們輸入:ssssa,回車得到:ssssa,光標(biāo)處(等待輸入)

說明: 程序已經(jīng)跳出for循環(huán),但是由于我們用getchar();清除了換行'\n',后面第7句c=getchar();需要你輸入一個(gè)字符(因?yàn)閟sssa后面并沒有新的字符),所以程序仍然沒有結(jié)束.

如果我們注釋掉getchar();這一句,那么得到:ssss,光標(biāo)處(程序結(jié)束) 這個(gè)輸入ssssa是的回車中的換行符'\n'就被c=getchar();這一句讀取并輸出了。

總結(jié):鍵盤輸入的字符都存到緩沖區(qū)內(nèi),一旦鍵入回車,getchar就進(jìn)入緩沖區(qū)讀取字符,一次只返回第一個(gè)字符作為getchar函數(shù)的值,如果有循環(huán)或足夠多的getchar語句,就會依次讀出緩沖區(qū)內(nèi)的所有字符直到'\n'.

要理解這一點(diǎn),之所以你輸入的一系列字符被依次讀出來,是因?yàn)檠h(huán)的作用使得反復(fù)利用getchar在緩沖區(qū)里讀取字符,而不是ge

最后

很多表面的現(xiàn)象看起來可能不能引起我們的注意,但是當(dāng)我們注意到細(xì)節(jié)的時(shí)候,才能深究其中的奧秘,寫代碼亦是如此。

   

叨叨一下,最近建了一個(gè)學(xué)習(xí)群,用于學(xué)習(xí)交流,需要加群的,加微信號:cyuyan2020,備注:加群


點(diǎn)【在看】是最大的支持 

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉