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

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;

}

主站蜘蛛池模板: 横峰县| 天津市| 东台市| 葵青区| 深圳市| 大同县| 鸡泽县| 武陟县| 巫溪县| 南安市| 绿春县| 云阳县| 巴里| 芷江| 博爱县| 苏尼特左旗| 罗源县| 社会| 巢湖市| 唐山市| 石屏县| 巴彦县| 封开县| 托克托县| 淮阳县| 乌海市| 天柱县| 江阴市| 收藏| 通山县| 抚远县| 贵州省| 金阳县| 搜索| 秦皇岛市| 老河口市| 淮阳县| 平南县| 务川| 滦南县| 新源县|