- 第一行代碼 C語(yǔ)言(視頻講解版)
- 翁惠玉
- 4710字
- 2019-09-10 14:45:38
3.2 數(shù)據(jù)的輸入/輸出
數(shù)據(jù)的輸入是指在程序運(yùn)行過(guò)程中從鍵盤接收數(shù)據(jù)存入變量。數(shù)據(jù)的輸出是指將程序執(zhí)行過(guò)程中的某些變量或表達(dá)式的計(jì)算結(jié)果顯示在顯示器上。
C 語(yǔ)言中,鍵盤在內(nèi)存有一塊對(duì)應(yīng)的空間,稱為緩沖區(qū)。鍵盤輸入的信息在按 enter 鍵后被送到了緩沖區(qū)。當(dāng)程序中遇到輸入時(shí),從緩沖區(qū)讀數(shù)據(jù)。如果緩沖區(qū)中無(wú)數(shù)據(jù),則程序暫停,等待用戶通過(guò)鍵盤進(jìn)行輸入,該過(guò)程如圖3-2所示。

圖3-2 數(shù)據(jù)的輸入
C 語(yǔ)言沒有專門的輸入/輸出語(yǔ)句。輸入/輸出是由 C 語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的函數(shù)提供的,如代碼清單2-1中的 scanf 和 printf。除了 scanf 和 printf 函數(shù)外,C 語(yǔ)言還提供了 getchar、putchar、gets 和puts 函數(shù),這些函數(shù)被定義在庫(kù) stdio 中。本節(jié)將介紹 scanf、printf、getchar 和 putchar 函數(shù)的使用,gets和puts函數(shù)將在第7章介紹。
3.2.1 字符的輸入/輸出
字符的輸入/輸出
輸出一個(gè)字符可使用函數(shù)putchar。如
putchar(ch);
putchar('a');
前者輸出字符型變量ch的值,后者輸出字符a。
讀入一個(gè)字符可使用函數(shù)getchar。如
c=getchar();
putchar(getchar());
前者將從鍵盤讀入一個(gè)字符存入字符類型的變量 c中;后者將從鍵盤接收到的字符顯示在顯示器上。
注意
在輸入時(shí),當(dāng)在鍵盤上輸入完所有輸入信息后,必須按 enter 鍵才能將輸入信息傳送到內(nèi)存,C 語(yǔ)言的程序才能讀到這些信息。enter 本身也是一個(gè)字符,也可以被 getchar讀取。
例3.5 編寫一個(gè)程序,從鍵盤讀入兩個(gè)字符并將輸入字符回顯在顯示器上。
讀者可能編寫了一個(gè)如代碼清單3-2的程序,用getchar函數(shù)讀入字符,用putchar函數(shù)顯示字符。
代碼清單3-2 利用getchar和putchar實(shí)現(xiàn)字符的輸入/輸出
/ * 文件名: 3-2.c
利用getchar和putchar實(shí)現(xiàn)字符的輸入/輸出 */
#include <stdio.h>
int main()
{
char c1, c2;
c1 =getchar();
c2 =getchar();
putchar(c1);
putchar(c2);
return 0;
}
如果用戶希望 c1的值為'a',c2的值為'b',當(dāng)程序執(zhí)行到第一個(gè) getchar時(shí),由于鍵盤對(duì)應(yīng)的緩沖區(qū)中沒有數(shù)據(jù),于是程序暫停等待輸入。用戶輸入了
a enter
但此時(shí)程序運(yùn)行結(jié)束,輸出
a
程序運(yùn)行時(shí)并沒有讓用戶輸入第二個(gè)字符!為什么?因?yàn)閳?zhí)行到第二個(gè) getchar 時(shí),緩沖區(qū)中的a已被讀取,但enter仍在緩沖區(qū)中。于是第二個(gè)getchar讀入了字符enter。第一個(gè)putchar輸出了 a,第二個(gè) putchar 輸出了 enter,程序結(jié)束。如果要正確讀入'a'和'b',可以在程序暫停等待輸入時(shí)直接輸入兩個(gè)字符
ab enter
此時(shí),第一個(gè)getchar讀入了a。執(zhí)行到第二個(gè)getchar時(shí),由于緩沖區(qū)中還有b和enter,于是就讀入了b。
如果希望運(yùn)行時(shí)字符一個(gè)個(gè)輸入,則必須跳過(guò)enter字符,這個(gè)過(guò)程如代碼清單3-3所示。
代碼清單3-3 利用getchar跳過(guò)輸入的enter
/ * 文件名: 3-3.c
利用getchar跳過(guò)輸入的enter */
#include <stdio.h>
int main()
{
char c1, c2;
c1 =getchar();
getchar();
c2 =getchar();
putchar(c1);
putchar(c2)
return 0;
}
運(yùn)行此程序時(shí),輸入
a enter
b enter
則輸出為
ab
代碼清單3-3運(yùn)行時(shí),運(yùn)行到第一個(gè) getchar 時(shí),由于緩沖區(qū)為空,程序暫停,此時(shí)用戶輸入了
a enter
第一個(gè) getchar 讀入了字符'a',第二個(gè) getchar 讀取了字符enter。當(dāng)遇到第三個(gè) getchar 時(shí),因?yàn)榫彌_區(qū)中的數(shù)據(jù)已被讀完,沒有數(shù)據(jù)可讀,于是程序停下來(lái)等用戶輸入。在用戶輸入了
b enter
后,第三個(gè)getchar讀入了b。
3.2.2 格式化輸入/輸出
1.格式化的輸出
格式化的輸出
格式化的輸出是采用 printf 函數(shù),它可以同時(shí)輸出各種類型的數(shù)據(jù),包括常量和變量。printf函數(shù)的格式為
printf(格式控制字符串,輸出列表);
如代碼清單3-1中的
printf("%d %d %d\n", sizeof(long int), sizeof(int),
sizeof (short));
其中,"%d %d %d\n"是格式控制字符串,sizeof(long int), sizeof(int), sizeof(short)是輸出列表。printf函數(shù)的作用是將輸出列表中的數(shù)據(jù)按格式控制字符串指定的格式輸出。
格式控制字符串規(guī)定了此次輸出的格式,它包括2部分內(nèi)容。
? 格式說(shuō)明:由%和格式控制字符組成,如%d、%f等。它表示將輸出列表中的數(shù)據(jù)按指定格式輸出。
? 普通字符:需要原式原樣輸出的字符,如上述控制字符串中的空格和'\n'。
輸出列表是一組需要輸出的數(shù)據(jù),列表中的數(shù)據(jù)之間用逗號(hào)分開。列表中的第一個(gè)數(shù)據(jù)對(duì)應(yīng)格式控制字符串中的第一個(gè)格式說(shuō)明,第二個(gè)數(shù)據(jù)對(duì)應(yīng)格式控制字符串中的第二個(gè)格式說(shuō)明,以此類推。即
上述語(yǔ)句表示輸出 long int 占用的內(nèi)存字節(jié)數(shù),輸出1個(gè)空格;輸出 int 占用的內(nèi)存字節(jié)數(shù),輸出1個(gè)空格;輸出short占用的內(nèi)存字節(jié)數(shù),最后輸出換行。在VS2010中的輸出結(jié)果為
4 4 2
再如,語(yǔ)句
printf("long int 占%d 個(gè)字節(jié),int 占%d 個(gè)字節(jié),short 占%d 個(gè)字節(jié)\n", sizeof(long int),sizeof(int), sizeof(short));
的輸出結(jié)果是
long int占4個(gè)字節(jié),int占4個(gè)字節(jié),short占2個(gè)字節(jié)
這個(gè)語(yǔ)句執(zhí)行時(shí),將格式控制字符串中的普通字符原式原樣輸出,格式控制字符用輸出列表中的數(shù)據(jù)替代。
格式控制字符定義了輸出數(shù)據(jù)的類型及格式,常用的格式控制字符如表3-6所示。
表3-6 printf的格式控制字符

利用printf可以靈活輸出各種類型的數(shù)據(jù),也可以實(shí)現(xiàn)各種表示形式間的轉(zhuǎn)換。
例3.6 編寫一個(gè)程序,以各種數(shù)制輸出十進(jìn)制數(shù)12380,以十進(jìn)制和科學(xué)計(jì)數(shù)法輸出123.45678。
程序的實(shí)現(xiàn)如代碼清單3-4所示。以十進(jìn)制輸出整數(shù)可用格式控制字符"%d",八進(jìn)制用"%o",十六進(jìn)制用"%x"。以十進(jìn)制及科學(xué)計(jì)數(shù)法輸出實(shí)型數(shù)分別用格式控制字符"%f"和"%e"。
代碼清單3-4 用printf輸出整型數(shù)和實(shí)型數(shù)
/ * 文件名: 3-4.c
用printf輸出整型數(shù)和實(shí)型數(shù) */
#include <stdio.h>
int main()
{
int iint=12380;
double ddouble=123.4567891;
printf("12380的十進(jìn)制為:%d,八進(jìn)制為:%o,十六進(jìn)制為:%x\n", iint, iint, iint);
printf("123.4567891的十進(jìn)制為:%f,科學(xué)計(jì)數(shù)法為:%e\n", ddouble, ddouble);
return 0;
}
該程序的輸出為
12380的十進(jìn)制為:12380,八進(jìn)制為:30134,十六進(jìn)制為:305c
123.4567891的十進(jìn)制為:123.456789,科學(xué)計(jì)數(shù)法為:1.234568e+002
注意
程序的第2行輸出,輸出的數(shù)值并不精確,首先浮點(diǎn)數(shù)在計(jì)算機(jī)內(nèi)不是精確表示的。當(dāng)數(shù)值的長(zhǎng)度超過(guò)精度時(shí),后面的數(shù)字被自動(dòng)刪去。其次,以%f 輸出實(shí)數(shù)時(shí),整數(shù)部分全部輸出,并輸出6位小數(shù),所以123.4567891以十進(jìn)制輸出時(shí)是123.456789,以科學(xué)計(jì)數(shù)法輸出時(shí)也是如此。但要注意,并非所有的輸出數(shù)值都是正確的。單精度數(shù)的有效位數(shù)一般是7位,雙精度數(shù)的有效位數(shù)一般是16位。
如果把代碼清單3-4中ddouble的類型改為float,則第2行的輸出為
123.4567891的十進(jìn)制為:123.456787,科學(xué)計(jì)數(shù)法為:1.234568e+002
其中只有7位是精確的。
格式控制字符前還可以插入附加控制字符使輸出格式更加多樣化,附加控制字符如表3-7所示。
表3-7 printf的附加控制字符

指定輸出寬度時(shí),如果輸出的數(shù)據(jù)長(zhǎng)度超過(guò)指定的寬度,按實(shí)際長(zhǎng)度輸出。如果實(shí)際長(zhǎng)度小于輸出寬度,前面部分用空格填充。如把代碼清單3-4中的第2個(gè)printf語(yǔ)句改為
printf("123.4567891的十進(jìn)制為:%10.7f,科學(xué)計(jì)數(shù)法為:%10.9e\n",
ddouble, ddouble);
則輸出為
123.4567891的十進(jìn)制為:123.4567891,科學(xué)計(jì)數(shù)法為:1.234567891e+002
因?yàn)榈?個(gè)格式控制字符指定了輸出寬度為10位數(shù),小數(shù)點(diǎn)后面7位。第2個(gè)格式控制字符指定了寬度為10,小數(shù)點(diǎn)后面9位。
如果將第一個(gè)printf語(yǔ)句改為
printf("12380的十進(jìn)制為:%10d,八進(jìn)制為:%10o,十六進(jìn)制為:%10x\n",
iint, iint, iint);
表示每個(gè)數(shù)值在輸出時(shí)占用屏幕上10個(gè)字符的位置。如果數(shù)字的位數(shù)超過(guò)10位,按實(shí)際長(zhǎng)度輸出。如果小于10位,前面填空格。這種填空方式稱為右對(duì)齊。該語(yǔ)句對(duì)應(yīng)的輸出是
12380的十進(jìn)制為: 12380,八進(jìn)制為: 30134,十六進(jìn)制為: 305c
如果將第一個(gè)printf語(yǔ)句改為
printf("12380的十進(jìn)制為:%-10d,八進(jìn)制為:%-10o,十六進(jìn)制為:%-10x\n",
iint, iint, iint);
表示輸出時(shí)左對(duì)齊,即當(dāng)輸出的數(shù)字位數(shù)小于指定長(zhǎng)度時(shí),后面填空格。該語(yǔ)句對(duì)應(yīng)的輸出是
12380的十進(jìn)制為:12380,八進(jìn)制為:30134,十六進(jìn)制為:305c
2.格式化的輸入
格式化的輸入
格式化輸入采用函數(shù) scanf,scanf 接收鍵盤輸入的各種類型的數(shù)據(jù)存入指定的變量。scanf函數(shù)的格式與printf函數(shù)類似
scanf(格式控制字符串,地址列表);
其中的格式控制字符串與 printf 函數(shù)中相同,如輸入十進(jìn)制整數(shù)用%d,輸入一個(gè)字符用%c,輸入 float 類型的數(shù)用%f。地址列表對(duì)應(yīng)輸入數(shù)據(jù)需要存入的變量在內(nèi)存中的地址,變量在內(nèi)存中的地址可用“&變量名”表示。例如輸入一個(gè)十進(jìn)制整型數(shù)存入變量iint,可用
scanf("%d", &iint);
例3.7 利用格式化輸入/輸出實(shí)現(xiàn)八進(jìn)制到十進(jìn)制和十六進(jìn)制的轉(zhuǎn)換。
解決該問(wèn)題可以用 scanf 輸入一個(gè)八進(jìn)制數(shù),然后在 printf 中用十進(jìn)制及十六進(jìn)制輸出。具體實(shí)現(xiàn)見代碼清單3-5。
代碼清單3-5 八進(jìn)制到十進(jìn)制及十六進(jìn)制的轉(zhuǎn)換
/ * 文件名: 3-5.c
八進(jìn)制整數(shù)到十進(jìn)制及十六進(jìn)制的轉(zhuǎn)換 */
#include <stdio.h>
int main()
{
int iint;
printf("請(qǐng)輸入一個(gè)八進(jìn)制數(shù):");
scanf("%o", &iint);
printf("八進(jìn)制 %o 的十進(jìn)制為:%d,十六進(jìn)制為:%x\n”, iint, iint, iint);
return 0;
}
程序運(yùn)行時(shí),首先輸出一個(gè)提示信息,提示用戶輸入一個(gè)八進(jìn)制數(shù)。然后在 scanf中用“%o”表示把輸入數(shù)據(jù)解釋成八進(jìn)制,如輸入177,程序把它解釋成八進(jìn)制的177,即十進(jìn)制的127。程序的輸出為
八進(jìn)制177的十進(jìn)制為:127,十六進(jìn)制為:7F
程序運(yùn)行到 scanf 函數(shù)調(diào)用時(shí),由于鍵盤對(duì)應(yīng)的緩沖區(qū)中沒有數(shù)據(jù),程序會(huì)停下來(lái)等待用戶的輸入,用戶按照格式控制字符串中指定的格式輸入數(shù)據(jù)。如果有多個(gè)輸入數(shù)據(jù),輸入的數(shù)值之間可以用空格、Tab鍵或回車鍵分開,如對(duì)應(yīng)于
scanf("%d%d", &a, &b);
則相應(yīng)的輸入可以是
35enter
則a的值是3,b的值是5,也可以輸入
3 Tab 5 enter
或者是
3 enter
5 enter
輸入時(shí),如果讀到一個(gè)不合法的字符,輸入也會(huì)結(jié)束。如對(duì)應(yīng)于語(yǔ)句
scanf("%o", &iint);
如果用戶輸入
1790 enter
因?yàn)?9'不是八進(jìn)制數(shù)的合法字符,所以變量iint的值為八進(jìn)制的17。如果接下去有一個(gè)
scanf("%d", &n);
則n的值為90。
除了格式控制字符外,格式控制字符串中還可以有其他字符。如果格式控制字符串中有其他字符,這些字符必須原式原樣輸入。如對(duì)應(yīng)的輸入語(yǔ)句為
scanf("%d, %d",&a, &b);
則相應(yīng)的輸入為
3,5 enter
執(zhí)行此語(yǔ)句后,a的值是3,b的值是5。
如果要以hh:mm:ss的格式輸入時(shí)間,則可用
scanf("%d: %d:%d", &hh, &mm, &ss);
如果要輸入8點(diǎn)05分23秒,則可輸入
8:5:23 enter
執(zhí)行此語(yǔ)句后,變量hh的值為8,變量mm的值為5,變量ss的值為23。
例3.8 如代碼清單3-6所示,以格式“hh:mm:ss”輸入時(shí)間,以“hh時(shí)mm分ss秒”的格式輸出。
代碼清單3-6 時(shí)間格式轉(zhuǎn)換
/ * 文件名:3-6.c
時(shí)間格式轉(zhuǎn)換 */
#include <stdio.h>
int main()
{
int hh, mm, ss;
printf("input time: hh:mm:ss:");
scanf("%d:%d:%d", &hh, &mm, &ss);
printf("%d時(shí)%d分%d秒\n", hh, mm, ss);
return 0;
}
在函數(shù) printf 的格式控制字符串中,除了格式控制字符外還有輔助格式控制字符,scanf 函數(shù)也是如此。表3-8給出了scanf函數(shù)中的輔助格式控制字符。代碼清單3-7~代碼清單3-9給出了附加控制字符的幾個(gè)應(yīng)用示例。
表3-8 scanf函數(shù)中的附加控制字符

代碼清單3-7 附加控制字符的應(yīng)用—指定輸入寬度
/ * 文件名: 3-7.c
scanf中附加控制字符的應(yīng)用—指定輸入寬度 */
#include <stdio.h>
int main()
{
int int1;
scanf("%3d", &int1);
printf("%d \n", int1);
return 0;
}
代碼清單3-7中,scanf 的格式控制字符是%3d,表示輸入一個(gè)十進(jìn)制整數(shù)。其中的3表示不管用戶在鍵盤上輸入的數(shù)字是多少位,都只讀取3位。如果運(yùn)行此程序時(shí)輸入的值是
123456
盡管輸入的值有6位,但只讀取3位。程序的輸出是
123
在使用格式化輸入時(shí),特別要注意的是雙精度數(shù)的輸入。單精度數(shù)輸入是采用格式控制字符%f,而雙精度數(shù)輸入必須用格式控制字符%lf。代碼清單3-8演示了雙精度數(shù)的輸入。
代碼清單3-8 附加控制字符的應(yīng)用—雙精度數(shù)的輸入
/ * 文件名: 3-8.c
scanf中附加控制字符的應(yīng)用—雙精度數(shù)的輸入 */
#include <stdio.h>
int main()
{
double d;
scanf("%lf", &d);
printf("%f \n", d);
return 0;
}
運(yùn)行此程序時(shí),如果輸入的是
123.456
則輸出為
123.456000
對(duì)雙精度數(shù),特別要注意的是輸入的格式控制字符是%lf,而輸出的格式控制字符是%f。
代碼清單3-9 附加控制字符*的應(yīng)用
/ * 文件名: 3-9.c
scanf中附加控制字符*的應(yīng)用 */
#include <stdio.h>
int main()
{
int iint=9;
long lint=10;
printf("請(qǐng)輸入一個(gè)整型數(shù)、一個(gè)短整型和一個(gè)長(zhǎng)整型數(shù):");
scanf("%d %*hd %ld", &iint, &lint);
printf("輸入的整型數(shù)為:%d,輸入的長(zhǎng)整型數(shù)為:%ld\n", iint, lint);
return 0;
}
在 scanf 中有3個(gè)格式控制字符,但只有2個(gè)地址列表。第二個(gè)格式控制字符中包含了一個(gè)附加控制字符*,表示第二個(gè)輸入值被忽略。第一個(gè)輸入值給變量 iint,第三個(gè)輸入值給變量 lint。如果程序運(yùn)行時(shí)輸入的3個(gè)整型數(shù)是
10 20 30↙
程序?qū)⒌谝粋€(gè)整數(shù)解釋成整型存入變量 iint。第二個(gè)數(shù)據(jù)20被忽略了,因?yàn)榈诙€(gè)格式控制字符串中有個(gè)附加控制字符‘*’。第三個(gè)整數(shù)被解釋成長(zhǎng)整型數(shù)存入變量lint。程序輸出為
輸入的整型數(shù)為:10,輸入的長(zhǎng)整型數(shù)為:30
例3.9 例3.5要求輸入兩個(gè)字符并回顯在顯示器上,代碼清單3-2給出了一個(gè)實(shí)現(xiàn)程序,但程序運(yùn)行時(shí)不能用輸入
a enter
b enter
的方式運(yùn)行,因?yàn)?enter 也是一個(gè)字符,可以被 getchar 函數(shù)讀入,所以第二個(gè) getchar 讀入了enter。為了解決這個(gè)問(wèn)題,代碼清單3-3在用getchar讀入一個(gè)有用的字符后再調(diào)用一次getchar跳過(guò)enter,這個(gè)程序看起來(lái)有點(diǎn)啰唆。
另一個(gè)解決方案是改用 scanf 函數(shù),scanf 函數(shù)的格式控制字符串中的字符常量必須原式原樣輸入,可以將enter字符放在格式控制字符串中,這樣就不需要另外一個(gè) getchar去跳過(guò)enter了。該函數(shù)的實(shí)現(xiàn)見代碼清單3-10。
代碼清單3-10 利用scanf和putchar實(shí)現(xiàn)字符的輸入/輸出
/ * 文件名: 3-10.c
利用scanf和putchar實(shí)現(xiàn)字符的輸入/輸出 */
#include <stdio.h>
int main()
{
char c1, c2;
scanf("%c\n", &c1);
scanf("%c", &c2);
putchar(c1);
putchar(c2);
return 0;
}
想一想并試一試,如果將代碼清單3-10的程序改為代碼清單3-11,程序的執(zhí)行過(guò)程是
a
a
b
b
還是
a
b
ab
本書將在第11章解答這個(gè)問(wèn)題。
代碼清單3-11 利用scanf和putchar實(shí)現(xiàn)字符的輸入/輸出
/ * 文件名: 3-11.c
利用scanf和putchar實(shí)現(xiàn)字符的輸入/輸出 */
#include <stdio.h>
int main()
{
char c1, c2;
scanf("%c\n", &c1);
putchar(c1);
scanf("%c", &c2);
putchar(c2);
return 0;
}
- Apache ZooKeeper Essentials
- Java Web程序設(shè)計(jì)
- Hands-On Natural Language Processing with Python
- Jupyter數(shù)據(jù)科學(xué)實(shí)戰(zhàn)
- Internet of Things with ESP8266
- 深度學(xué)習(xí)原理與PyTorch實(shí)戰(zhàn)(第2版)
- MATLAB GUI純代碼編寫從入門到實(shí)戰(zhàn)
- 新印象:解構(gòu)UI界面設(shè)計(jì)
- Java EE 8 and Angular
- Mastering Bootstrap 4
- Learning Apache Thrift
- 樹莓派開發(fā)從零開始學(xué):超好玩的智能小硬件制作書
- 開源網(wǎng)絡(luò)地圖可視化:基于Leaflet的在線地圖開發(fā)
- vSphere High Performance Cookbook(Second Edition)
- Learn Spring for Android Application Development