官术网_书友最值得收藏!

2.5 標準I/O函數

一個好的程序應該會將運行的狀態和執行的結果以信息的形式告知用戶,甚至在某些情況下會要求得到用戶的特定信息,這種與程序進行交流的行為就稱為交互。我們把一個程序獲取用戶的信息稱為程序的輸入,將信息告知用戶稱為程序的輸出,擁有這種功能的函數就稱為I/O函數(Input/Output),即輸入/輸出函數。如果是通過控制臺窗口來完成這些I/O操作的,即為標準I/O函數,C語言中有許多標準I/O函數,其中使用最廣泛、功能最強大的是printf函數和scanf函數了。

2.5.1 再談printf函數

在第1章的第一個C語言程序中使用了printf函數,程序通過這個函數在控制臺的窗口上輸出一行文本字符串。其實這只是printf函數最基本的用法,它還擁有更多強大的功能,值得我們進一步了解。

printf函數通常被稱為“格式化打印函數”,它的第一個參數稱為“格式化字符串”,在“格式化字符串”中可以使用“占位符”(或稱轉換說明符)把一些其他類型的數據鑲嵌到文本字符串中進行打印輸出。

不知大家在上學時有沒有去圖書館搶座位的經歷呢?先讓某個腿快的同學跑去圖書館,找到空的座位,就在上面放一本書或一個文具盒,表示這個座位已經有主人了,直到同學來了,再把東西收起來,然后坐到座位上。“占位符”與占座非常類似,我們可以在“格式化字符串”的某個位置放一個“占位符”,表示這兒會有數據出現。一個“格式化字符串”中可以放置多個“占位符”,當程序進行打印輸出時,這些“占位符”就會被真正的數據所替代。這些“占位符”都是以百分號“%”開頭的,常用的占位符見表2.16。

表2.16 printf函數的占位符

通過在格式化字符串中使用占位符,可以很靈活地將一些實時的數據嵌入到輸出字符串中進行打印,每一個占位符對應一種類型的數據。例如我們要使用printf函數來格式化打印一個學生的姓名、身高和體重,可以這樣寫:

int iHeight = 180;
float fWeight = 76.5F;
printf("Name:%s, Height:%dcm, Weight:%fkg\n", "XiaoMing", iHeight, fWeight);

在printf函數的格式化字符串中,出現了3個占位符:第一個占位符是“%s”,表示這兒會有一個字符串出現,在程序執行時,它會被后面的字符串常量"XiaoMing"所替代;第二個占位符是“%d”,表示這兒會有一個整數出現,在程序執行時,它會被后面的整型變量iHeight的值所替代;第三個占位符是“%f”,表示這兒會有一個浮點數出現,在程序執行時,它會被后面的浮點型變量fWeight的值所代替。所以在使用printf函數時,在格式化字符串中出現了多少個占位符,在后面就要跟上相應數量的參數。一個蘿卜一個坑。

當所有的占位符都被后面的數據替代后,最終輸出在控制臺窗口上的文本字符串為:“Name:XiaoMing, Height:180cm, Weight:76.500000kg”。

細心的讀者可能會發現,表示體重的浮點數的最后多出了5個0。這是正常的,因為默認對浮點數的輸出格式就是要求保留6位有效小數。這么多的0跟在后面,是不是感覺不太美觀?能不能改變一下,讓它不出現0,或者少出現幾個0呢?可以的,所以說printf函數功能強大,它除了可以使用占位符來給數據預留位置,還可以通過搭配“修飾符”來對這些數據進行輸出格式上的精細控制,例如利用“控制符”來設置數據的輸出寬度、對齊方式、數據精度等等。一些常用的“修飾符”見表2.17。

表2.17 printf函數的修飾符

這些修飾符是搭配占位符來使用的,不能單獨使用。假如想讓學生體重在輸出的時候只保留兩位有效小數,需要這樣修改:

printf("Name:%s,  Height:%dcm,  Weight:%.2fkg\n",  "XiaoMing",  iHeight,
fWeight);

由原來的“%f”改為“%.2f”,這樣就會讓體重的輸出結果只有兩位小數,最終輸出在控制臺窗口上的文本字符串變為:“Name:XiaoMing, Height:180cm, Weight:76.50kg”。少了一大堆0,是不是感覺美觀多了?

2.5.2 scanf函數

既然printf函數是用于打印輸出的,那么有沒有進行數據輸入的函數呢?當然有,就是scanf函數。scanf函數與printf函數類似,第一個參數是一個“格式化字符串”,并且也可以根據需要來使用“占位符”和“修飾符”。scanf函數的功能是將用戶在控制臺窗口中的輸入依據“占位符”的指示轉換成相應類型的數據保存到變量中。再形象一些,用戶使用鍵盤在控制臺窗口里的輸入雖然都是些字符,但通過“占位符”可以把這些字符理解為整型、實型、字符型或字符串等數據類型,把它們收集起來并存儲在相應的變量中。

因為要將數據保存到變量中,所以在使用scanf函數時要注意,需要在后面的參數變量名前加上一個“&”符號,表示取變量的內存地址。至于為什么要加取地址符,現在不必糾結,等到后面學習使用指針的時候就明白了。

下面用例子展示一下scanf函數的使用方式。

在這個scanf函數中,格式化字符串里只有一個占位符“%d”,它表示將用戶的輸入按照整數的形式讀取并保存到變量n中。變量n前面的“&”符號是必需的。

把這三行代碼放在main函數中,編譯生成可執行文件。然后執行程序時,會看到窗口中的光標不停地閃爍,它表示程序正在等待用戶的輸入。我們通過鍵盤在窗口輸入一串數字字符“1234”,然后按下回車鍵,這時scanf函數就會把“1234”作為一個整數1234讀取并保存到變量n中,最后會通過printf函數在窗口打印輸出“you input integer is : 1234”。

如果我們把代碼修改一下:

變量類型從int改為float,scanf函數中的占位符也就相應從“%d”改為“%f”。程序運行后,同樣地,我們還是在窗口中輸入一串數字字符“1234”,然后按下回車鍵。這次scanf函數就會把“1234”作為一個單精度浮點數讀取并保存到變量flt中,最后通過printf函數在窗口打印輸出“you input float is : 1234.000000”。

我們還可以使用scanf函數一次性讀取多個不同數據類型的數據,例如:

char ch;
int n;
float flt;
scanf("%c%d%f", &ch, &n, &flt);

在scanf函數的格式化字符串中連續有3個占位符,表示會分別把用戶的輸入按字符、整型和單精度浮點數的形式進行讀取,并保存到相應的變量中。用戶在輸入時要注意,每個數據之間要留有空白字符(例如空格字符),不要連在一起,如:“A 100 3.14”,這樣通過scanf函數最終會讓變量ch的值為'A',變量n的值為100,變量flt的值為3.14。如果把所有輸入字符都連在一起,如“A1003.14”,那么最終結果就會有所不同,變量ch的值依然為'A',但變量n的值變為1003,變量flt的值變為0.14。

下面再講一下使用scanf函數時的一些注意點。

scanf函數在讀取字符型數據時,會將用戶輸入的第一個字符(包含空白字符)讀取進來,并保存到字符變量中。所謂空白字符包括空格、水平制表符以及換行符等這些不可見的字符。

scanf函數在讀取非字符型數據時,會自動跳過用戶輸入中的前導空白字符,從第一個合法字符開始讀取,直到遇到空白字符或非法字符時才停止讀取,然后把這些字符轉換成對應的數據保存到變量中。什么是合法字符呢?例如,如果讀取的是一個十進制整數,合法字符就是指0~9這些數字字符;如果讀取的是一個八進制數,合法字符就是指0~7這些數字字符;如果讀取的是一個十六進制數,合法字符就是指0~9這些數字字符以及A~F、a~f這些字符;如果讀取的是一個浮點數,那么合法字符除了包括0~9這些數字字符外,還包括一個表示小數點“.”的字符。

scanf函數的格式化字符串中盡量不要包含占位符之外的其他字符,因為用戶必須嚴格按照格式化字符串的格式進行輸入,否則很容易導致錯誤。

int n;
scanf("Num:%d", &n);  //格式化字符串中使用了占位符之外的字符

在此例中,格式化字符串內容為“Num:%d”,那么在程序執行后,如果想讓變量n的值為1234,則用戶在控制臺窗口進行輸入時,不可直接輸入“1234”,必須嚴格按照格式進行輸入,如“Num:1234”,否則就會造成讀取錯誤,導致變量n得不到期望的數值。

主站蜘蛛池模板: 瓮安县| 卓资县| 嵩明县| 嵩明县| 新营市| 桐城市| 江门市| 镇雄县| 泽库县| 康平县| 萍乡市| 卓尼县| 东至县| 原阳县| 西平县| 织金县| 宁南县| 黑山县| 长治县| 大宁县| 洛浦县| 石棉县| 修水县| 成安县| 阜康市| 昭觉县| 将乐县| 桃园县| 武定县| 永泰县| 西宁市| 广饶县| 雷州市| 西乌| 光泽县| 龙里县| 襄汾县| 屏山县| 和顺县| 渝中区| 卓资县|