《C語言入門1.2.3—一個老鳥的C語言學習心得》—清華大學出版社炮制的又一本劣書及偽書
【薛非評】
區區15頁,有80多個錯誤。
最嚴重的有:
通篇完全是C++代碼,根本不是C語言代碼。其中的很多代碼根本不可能通過編譯。僅此足矣說明該書不僅是一本劣書,而是一本掛羊頭賣狗肉的偽書。
通篇的void main()。C語言從來沒說過可以這樣寫main()。
很多地方完全是一個外行荒唐的臆想和信口開河,如: “scanf("%d,%d\n",&a,&b);
該格式字符串在之前的字符串基礎上,增加了一個\n 換行符。但是輸入函數並不認為格式字符串中的\n 是一個換行符,而是將其視做一個反斜杠\和一個字母n。因此在輸入的時候,還應當輸入這兩個字符。正確的輸入應當為:
18,33\n”
================================================================
第3 章 輸入與輸出
任何一個完整的程序應當包括輸入【錯:程序可以沒有輸入】和輸出(Input/Output)功能。通過輸入功能程序使用者能根據需要使用程序,通過輸出功能使用者能得到程序運行的反饋。前面章節已經對C 語言的輸出方法有所了解,本章將詳細介紹C 語言的輸入輸出方法,主要學習C 語言在標准輸入輸出設備上(屏幕和鍵盤)的輸入輸出。關於磁盤文件的輸入輸出方法,將在第9 章進行講解。本章涉及的知識點有:
q 格式化輸出和輸入函數的使用。
q 常用的字符輸入輸出函數。
3.1 輸入輸出——讓人與機器交流的窗口
輸入輸出(Input/Output,也稱做I/O),是計算機的重要組成部分。輸入是指計算機程序在計算機中運行,需要的數據通過輸入操作從外部設備中輸入到計算機內部。輸出是指計算機程序運行過程中或結束時,將程序運算的結果在外部設備上顯示或打印到外部設備上。
輸入輸出需要通過必要的設備才能完成,輸入設備通常是鼠標和鍵盤,輸出設備通常是顯示器。程序真正處理的地方,僅在主機的內存和CPU 上。在計算機運行某個程序時,其運算過程的相關的指令和數據都將被轉換成二進制形式的電信號。程序的用戶想要知道程序的運行狀況和結果,就必須使用輸出設備將程序數據轉換成為人能識別的文字或圖像信息。若用戶想控制正在執行的程序,也必須通過輸入設備,將指令輸入到主機中去。人與計算機交流的過程如圖3-1 所示。
輸入輸出是人與機器進行交流的窗口。大多數的程序在編寫過程中,都需要有輸入和輸出功能。對於編程語言而言,輸入輸出功能體現在它能夠提供某些方法來打開計算機的輸入輸出設備供給程序用戶使用。程序的用戶通常不是程序的設計者,他們並不知道程序內部實現的步驟,只能通過必要的輸入和相應的輸出結果來判斷程序功能是否有用。在設計程序的時候,就需要考慮到使用者並不知道何時輸入、輸入什么樣的數據等問題。因此,編寫程序時必要的提示信息和非法輸入數據的檢測也很重要。例如當需要用戶輸入一個數據時,應該有相應的提示;當需要輸入整數時,用戶可能會輸入浮點數等情況出現。程序員需要對全部的程序功能負責,並且需要控制好輸入輸出。這才能保證程序的最終用戶與計算機之間的交流暢通無阻。
在C 語言中,沒有直接提供輸入和輸出的語句,只能從標准函數庫中調用相應的輸入和輸出函數來實現。在調用這些函數時,需要在代碼文件的開始加入編譯預處理語句【錯:語句是程序執行的動作,預處理和程序執行無關】#include<stdio.h>,使頭文件stdio.h 包含到用戶的源程序中。stdio.h 文件包括所有標准輸入輸出的庫函數【錯:stdio.h 文件中有的只是一些聲明和宏而已】。
圖3-1 人與計算機交流的過程
3.2 格式化的輸入輸出
C 語言中使用格式化的輸入輸出方法,本節將講解格式化輸出函數printf()和格式化輸入函數scanf()。
3.2.1 格式化輸出函數printf()
printf()函數的功能是讓計算機系統默認的輸出設備(一般是顯示器)輸出一個或多個任意數據類型的數據【錯:printf()函數不可能輸出任意數據類型的數據】。其基本格式為:
printf("格式控制參數",輸出項1,輸出項2,…,輸出項n);
其中格式控制參數是以字符串的形式描述的,也成【錯別字】為格式控制字符串。格式控制參數包括普通字符和格式說明項。
1.普通字符
普通字符包括可打印字符和轉義字符【錯:這並非是兩個互斥的概念,轉義字符也可以是可打印字符】。可打印字符主要起說明作用,可以按字符的原樣顯示在屏幕上。轉義字符是不可打印的字符【錯:胡扯】,輸出轉義字符可以實現控制字符顯示等特殊效果【錯:不知所雲】。printf()函數除了支持ASCII 中的字符【錯:支持ASCII不是必須的】,還可以輸出漢字。
2.格式說明項
在前面一章的學習中,已經接觸到了關於整數、浮點數和字符輸出的格式說明項。格式說明項是由%與格式字符組成,其作用是將數據轉換為指定的格式進行輸出,不同的數據類型有不同的格式字符。
q d 格式字符,用於輸出十進制整數。%d、%hd、%ld 分別用於輸出整型、短整型【錯:片面的描述】和長整型。【錯:前面講“用於輸出十進制整數”,后面“用於輸出整型…”,言外之意是“整型…”是“十進制”的,誤導。】
q o 格式字符,用於輸出八進制整數。
q x 格式字符,用於輸出十六進制整數。
q u 格式字符,用於輸出unsigned 的整數。【錯:“unsigned 的整數”與前面的“十進制整數”、“八進制整數”及“十六進制整數”並列,邏輯錯亂】
q c 格式字符,用於輸出一個字符【錯:輸出幾個字符與很多因素有關。如果這里的字符指的是轉換對象為char類型,同樣是錯的。】。
q s 格式字符,用於輸出一個字符串。
q f 格式字符,用於輸出一個浮點數。%f 和%lf 分別控制輸出單精度和雙精度浮點數【錯:%lf與%f完全等價】。小數部分保留6 位。
q e 格式字符,用於以指數形式輸出浮點數。
q g 格式字符,用於輸出浮點數,系統根據輸出數據的寬度自動選擇使用f 格式或e格式【錯:根據的不是數據的寬度】。
如代碼3-1 所示,實現各種數據類型的輸出。
代碼3-1 各種數據類型的輸出(3-1.cpp)【大錯特錯:這個根本就不是C語言的代碼,而是C++代碼。參見《品悟C》<問題1 C啊,多少C++假汝之名而行——C、C++不分>】
01 #include <stdio.h>
02 void main()【錯:參見《品悟C》<五花八門的main()> http://www.cnblogs.com/pmer/archive/2011/09/08/2171823.html 】
03 {
04 short snum = 100; //短整型變量
05 int num = 200; //整型變量
06 long lnum = 300; //長整型變量
07 printf("%hd\t%d\t%ld\n",snum,num,lnum);
//使用%hd、%d、%ld 輸出這個3 個變量
08
09 float fnum = 1.23f; //單精度浮點數【大錯特錯:對於基於C90的VC++6.0來說,這根本無法通過編譯】
10 double dnum = 1.234; //雙精度浮點數
11 printf("%f\t%lf\n",fnum,dnum); //使用%f、%lf 輸出這兩個變量【錯:畫蛇添足。使用任一種皆可】
12 printf("%e\t%g\n",fnum,dnum); //使用%e、%g 輸出這兩個變量
13
14 char ch = 'C'; //字符變量
15 printf("%s%c\n","the character is :",ch);
//使用%s 輸出字符串常量
16 } //使用%c 輸出字符變量【錯:這里輸出的其實是 (int)ch 】
這段代碼的執行結果為:
100 200 300
1.230000 1.234000
1.230000e+000 1.234
the character is :C
代碼第04~06 行分別定義了短整型變量snum、整型變量num 和長整型變量lnum。
這3 種數據類型分別使用%hd、%d 和%ld 格式說明項。【錯:其實輸出的還是int類型的值】
%注意:在本段代碼中,這些變量不采用其對應的數據類型的說明項,輸出也不會有任何問題【錯:fnum就不能用%d】。但如果變量中保存的值,與說明項對應數據類型的取值范圍不一致,將會導致問題【錯:這個問題根本扯不到范圍問題上】。例如將lnum 的值改為30000000【錯:這是根本不可能的】,而輸出的時候按短整型輸出(使用%hd),則輸出的結果將會發生溢出【錯:根本就不存在輸出結果溢出這回事】,結果將不再是30000000【錯:結果從來就不是30000000,哪來的什么“不再”?】,而是-15488。
代碼第09 和第10 行定義了一個單精度浮點數fnum 和一個雙精度浮點數dnum。【錯:這種定義對於VC++6.0是非法的】分別使用格式說明符%f 和%lf 輸出,此時輸出數據的形式是小數形式。同時,如果要使其輸出的形式為指數形式,就要使用%e。代碼第12 行使用%e 將fnum 輸出為指數形式,而使用%g 輸出dnum,通過判斷dnum 的寬度【錯:不是通過判斷寬度】,最終仍然輸出小數形式。
代碼第15 行,輸出了一個字符串常量和一個字符變量。字符串常量除了以格式字符串的形式輸出外,還可以像變量一樣使用格式控制項%s 將其輸出。
3.輸出寬度
在通過%d、%hd 和%ld 輸出整型變量時,可以通過在百分號%與格式字符之間增加一個字段寬度m,來控制輸出數據的寬度。格式說明項相應改變為%md、%mhd 和%mld,其中m 是1~9 之間的數字【錯:沒這回事】。如果整數的位數小於m,則輸出結果在最左端用空格補齊;如果整數的位數大於m,則輸出結果按實際的長度輸出。數據寬度是指一個數值的位數。例如,整數123 有3 位有效數字,如果指定數據寬度m 為5,輸出的123 前面將有兩個空格;如果指定m 為1,則仍然輸出123。
如代碼3-2 所示,展示了通過%md 控制整數輸出的寬度。
代碼3-2 指定整數輸出的進制和寬度(3-2.cpp)
01 #include <stdio.h>
02 void main()
03 {
04 int num = 200;
05 printf("%d\t%o\t%x\n",num,num,num); //指定整數輸出為十、八、十六進制
06 printf("%5d\t%3d\t%2d\n",num,num,num); //指定輸出寬度為5、3、2
07
08 }
代碼的輸出結果為:
200 310 c8
200 200 200
從輸出結果可以看出,代碼第05 行分別使用%d、%o 和%x 對同一個變量num 進行輸出控制。輸出結果為這個數的十進制、八進制和十六進制形式。同時從結果第2 行可以看出,第1 個200 前多了兩個空格,這是由於代碼第06 行輸出第1 個整型變量時,指定其寬度為5 位,如果指定寬度大於數據寬度,則使用空格進行填充。當指定寬度小於或等於數據寬度時,則仍然按照該數據實際寬度輸出。
%注意:使用轉義字符\t 之后,輸出數據應該按照列進行左對齊。【錯:對\t的誤解】
同樣,在使用%f 和%lf 輸出浮點數時,也可以使用%m.nf 和%m.nlf 來控制輸出數據的寬度。其中m 表示數據的寬度(小數點同樣占用1 位),n 表示小數的位數。如果數據的位數小於m,則左端補齊;如果數據的數位大於m,則按實際長度輸出。例如,輸出浮點數1.36,指定m 為5,n 為1,則輸出為“ 1.4”。小數位后只保留1 位,其余位四舍五入【無依據的說法】,整數位不足按空格補齊。
如代碼3-3 所示,實現的是控制浮點數輸出的寬度。
代碼3-3 指定輸出浮點數的寬度(3-3.cpp)
01 #include <stdio.h>
02 void main()
03 {
04 double dnum = 123.321;
05 printf("%10.5lf\n",dnum); //輸出數據寬度為10【錯:應為寬度至少為10】,小數占5 位
06 printf("%6.2lf\n",dnum); //輸出數據寬度為6,小數占2 位
07 printf("%3.0lf\t%3lf\n",dnum,dnum); //小數占0 位與省略小數寬度
08 printf("%0.5lf\t%.5lf\n",dnum,dnum); //數據寬度為0【錯:這個0說的根本就不是寬度】 位與省略數據寬度
09 }
代碼的輸出結果為:
123.32100
123.32
123 123.321000
123.32100 123.32100
printf()函數輸出雙精度浮點數時,使用%m.nlf 控制輸出數據的寬度。代碼第05 行,當輸出寬度10 大於數據寬度7,輸出小數位5 大於實際小數占的位數3,則首先小數部分以0 補齊,整數部分以空格補齊,因此輸出 123.32100。而代碼第06 行則剛好相反,整數部分和小數部分的輸出寬度都小於實際數據的寬度【錯:“整數部分”“輸出寬度”是子虛烏有的說法】,則小數部分保留指定位數(多余位四舍五入【無依據的說法】),整數部分按123 原樣輸出,輸出結果為123.32。
在使用%m.nlf 控制輸出數據寬度時,可以省略m 或n,但兩者不可同時省略。在使用省略寬度數值時,尤其要注意省略數值與指定數值為0 的區別。代碼第07 行,指定了輸出小數部分占用0 位和不指定輸出的小數位數n。從輸出結果可以看出,指定小數部分占用0位輸出時將不再帶有小數,並且小數點也沒有了。而沒有指定小數位的輸出,則按照正常%lf 的輸出,保留了小數的6 位數字。代碼第08 行,則是指定輸出數據寬度為0 【錯:這個0說的不是寬度】和省略數據寬度。從結果可以看出,它們的小數部分都按指定寬度輸出,但整數部分仍然按原樣輸出。
%注意:從這里可以看出,printf()函數輸出一個浮點數時,默認采用的是%.6lf。【錯:浮點數其實至少有3種類型;這個l毫無意義】
以指數形式輸出浮點數時,同樣可以使用%m.ne 的形式控制輸出數據的寬度。m 和n的含義與%m.nf 的含義相同,這里不再介紹。
另外,使用printf()函數輸出數據時,還可以在百分號%與格式字符之間增加減號-,來實現數據按左對齊輸出。在百分號%與格式字符之間增加0 可以在數據前使用0 補齊【這與前面“寬度為0”的說法自相矛盾,兩者必有一錯】(默認為空格)。
如代碼3-4 所示,指定用0 補齊數據
代碼3-4 用數字0 補齊輸出數據(3-4.cpp)
01 #include<stdio.h>
02 void main()
03 {
04 int num = 100;
05 printf("%05d\n",num); //指定輸出寬度為5,不足部分以0 補齊
06
07 double dnum = 123.321;
08 printf("%010.5lf\n",dnum); //指定輸出寬度為10,不足部分以0 補齊
09 }
輸出結果為:
00100
0123.32100
代碼第05 行使用%05d 輸出整數變量num,該變量的值為100,只有3 位數字,因此
需要在數字前面使用00 補齊。代碼第08 行使用%010.lf 輸出浮點數變量,會在最高位用0
補齊,其結果為0123.32100。
4.其他注意事項
(1)printf()除了輸出變量,同樣可以輸出常量和表達式。【廢話。輸出的本來就是表達式的值,常量、變量都是表達式】輸出常量時也要使用格式說明符,且必須按從左到右的順序與輸出項中的數據一一對應【嚴格地說,一一對應的說法並不成立】。
例如,可以使用下列語句輸出一個整數和一個結果為浮點數的算術表達式【兩者都是表達式】。
printf("%d\n%f",5,1.2*5);
換句話來說,printf()輸出項不僅可以是變量,也可以是常量和表達式。
(2)字符串常量可以直接使用printf 輸出,也可以使用格式字符s 輸出。例如:
printf("I LOVE CHINA\n");
prinf("%s\n","I LOVE CHINA");
字符串常量中可以是打印字符和控制字符。第2 句還可以將換行符'\n'放在字符串常量中,相應改寫為:
prinf("%s","I LOVE CHINA\n");
(3)格式字符x、e、g 可以使用小寫字母,也可以使用大寫字母。使用大寫字母時,輸出數據中如果帶有字母,也會相應輸出為大寫。除了x、e、f 【前面說x、e、g,這里又成了x、e、f】格式字符外,其他格式字
符必須使用小寫,否則會出錯。例如,%d 不能寫做%D,%f 不能寫做%F【錯:C語言有%F】。
(4)格式字符緊跟在百分號%后面才表示為格式字符,其輸出控制作用。否則將視做字符串的普通字符輸出。例如:
char c = 'C';
float f = 1.2;
printf("c=%c,f=%f",c,f);
輸出結果為:
c=C,f=1.2
上述printf()函數中,多次出現字符c 和字符f,但每一個c 和f 的含義都不相同。c=%c的第1 個字符c 是普通字符c,會按照原樣輸出;第2 個字符c 前面有百分號%,因此會被編譯器認為是格式字符,該處會按輸出項中的字符變量c 的內容輸出。同樣,f=%f 的第1個字符f 是普通字符,按照原樣輸出;第2 個字符f 為格式字符,按照輸出項中變量f 的內容輸出。
3.2.2 格式化輸入函數scanf()
格式化輸入函數scanf()的功能是從鍵盤上輸入數據【未必】,該輸入數據按指定的輸入格式被賦值給相應的輸入項。其基本輸入格式為:
scanf("格式字符串",輸出項1,輸入項2,…,輸入n);
其中格式字符串用於規定數據的輸入格式,必須用雙引號括起來【沒這回事】。其內容由格式說明項、普通字符和輸入分隔符3 部分組成。輸入項是一個或多個變量的地址,當有多個輸入項時,每個輸入項使用逗號隔開。輸入項變量的地址,就是在每個變量前加取地址符&。輸入與輸出都需要保持格式字符和輸入項數據一致。輸入多項數據時,輸入數據使用空格或回車符隔開【錯:有時不可以,有時還可以用其他字符隔開】。
scanf()函數的格式說明項與printf()的格式說明項基本相同,使用%d、%lf 等控制輸入數據類型。但在輸入浮點數時,不能使用m.n 中的n,因為輸入數據不能規定其精度。同時scanf()也沒有%u 的格式說明符【錯:scanf()有%u 】,需要輸入無符號數時,通常以%d、%o 或%x 格式輸入。【錯:誤導】如果百分號%后加*表示跳過相應的數據,即“虛讀”。
如代碼3-5 所示,展示了整數、浮點數和字符的輸入。
代碼3-5 整數、浮點數和字符的輸入(3-5.cpp)
01 #include <stdio.h>
02 void main()
03 {
04 int num;
05 double dnum;
06 char ch;
07 printf("please input <char> <int>and <double> type data:\n");
08 scanf("%c",&ch); //輸入一個字符,保存在ch 中
09 scanf("%d%lf",&num,&dnum); //輸入一個整數和小數,保存在num 和dnum
10 printf("you have input:\n");
11 printf("%d\t%lf\t%c\n",num,dnum,ch);
12 }
程序運行過程中,CMD 窗口的輸入輸出內容為:
please input <int> <double> and <char> type data:
A↙ //該行是輸入內容
12﹍1.2↙ //輸入
you have input:
12 1.20 A
程序首先提示輸入char、int 和double 類型的數據,依次輸入字符'A',數字12 和1.2
之后,輸出這幾個輸入的值。
尤其需要注意的是使用%c 輸入一個字符。從前面章節已經知道,ASCII 不僅定義了大小寫字母、常用符號和數字等鍵盤上的可打印字符,還定義了轉義字符【錯:驢唇不對馬嘴的說法。轉義字符是C代碼層面上的概念,跟ASCII八竿子打不着】。使用scanf()函數不僅可以輸入可打印字符,還可以輸入轉義字符【荒唐】。這樣的特性有時候會有一些麻煩。比如上面的程序,在第一次輸入字符A 的時候,不輸入任何字符直接按回車鍵,然后輸入12﹍1.2↙,則程序仍然正常執行。輸出的時候,輸出結果將會多一個空行。這是因為按回車鍵這個確認輸入的操作,被scanf()函數讀入,並認為是一個轉移字符 '\n' 保存在字符變量ch 中。
scanf()函數這樣的特性有時候會導致一些錯誤的產生。例如,同時讀取字符與整數、浮點數等類型數據時,代碼如下:
scanf("%d%lf%c",&num,&dnum,&ch);
如果輸入內容為12﹍1.2﹍A↙,將會發生錯誤。輸出結果為:
12 1.20
這是因為在輸入數據時習慣性使用空格間隔不同的數據,導致1.2 后面的空格被認為是需要輸入的字符將其讀取,而真正需要讀取的字符A 卻被忽略掉了。如果一定要同時輸入字符數據和其他類型數據,則字符數據不要使用空格間隔,上面的輸入修改為12﹍1.2A↙就沒有問題了。【拙劣的方案,不能從根本上解決問題】
%注意:為了讀者能看清楚輸入的內容,在輸入時本書使用﹍表示空格,使用↙表示回車。
輸入數據時,需要注意以下幾點。
(1)scanf()函數同時輸入兩個或多個數據時,在兩個輸入的數據之間可以使用一個或
多個空格間隔,也可以使用回車或制表符(鍵盤Tab 鍵)間隔。例如:
scanf("%d%d",&a,&b);
假設輸入18 保存在變量a 中,輸入33 保存在b 中,其輸入內容應當為:
18﹍33↙
或者
18↙
33↙
(2)格式字符串中出現的普通字符必須原樣輸入。例如:【這種設計本身很拙劣】
scanf("%d,%d",&a,&b);
該scanf()語句的格式字符串為"%d,%d",在兩個格式字符之間有一個逗號,因此在輸入時必須在兩個數據之間帶有一個逗號。正確的輸入應當為:
18,33↙
此外,對於scanf()函數中的帶有轉義字符的格式字符串,C 語言編譯並不將其視做轉移字符,而是當做普通的字符,所以輸入時同樣需要原樣輸入該字符。例如:
scanf("%d,%d\n",&a,&b);
該格式字符串在之前的字符串基礎上,增加了一個\n 換行符。但是輸入函數並不認為格式字符串中的\n 是一個換行符,而是將其視做一個反斜杠\和一個字母n。因此在輸入的時候,還應當輸入這兩個字符。正確的輸入應當為:
18,33\n↙【完全是胡扯】
(3)scanf()函數會依次在輸入的內容中讀取數據。讀取數據時遇到以下情況,程序會
認為輸入結束:
q 遇到空格、回車鍵或Tab 鍵【錯:只在個別情況下成立而已】
q 輸入域寬度結束。例如輸入%3d,讀取時只會讀入3 位數字。
q 非法輸入。非法輸入是指在輸入數據時使用與數據類型不相關的字符。例如,輸入整數時遇到字母【錯:十六進制就不排斥字母】,或者其他非數值符號(數值符號僅由數字字符0~9、小數點和正負號組成【錯:十六進制就不排斥字母】)。
(4)使用格式說明符%c 控制單個字符的輸入時,空格和轉義字符【概念錯誤,轉義字符是C代碼語境下的概念】均作為有效字符被輸入。例如,輸入函數【?】:
scanf("%c%c",&ch1,&ch2);
當輸入的字符帶有空格和反斜杠\時,【錯:空格和反斜杠\本來就是字符】
﹍\
則ch1 保存空格字符,ch2 保存反斜杠字符。
(5)在格式說明符的%與格式字符之間可以增加一個整數m,來控制讀入數據的最大位數【拜托,那叫寬度好不好】,如%mlf、%md。這和控制輸出寬度時使用的方法類似。使用這種方法控制讀入數據的寬度,則系統會自動截取所需要的數據,因而在輸入多個數據的時候不需要任何分隔符進行分隔。
如代碼3-6 所示,展示了設置寬度的輸入。
代碼3-6 設置輸入數據的寬度(3-6.cpp)
01 #include<stdio.h>
02 void main()
03 {
04 int num;
05 double dnum;
06 printf("please input <int> and <double> type data:\n");
07 printf("please keep input data with 5 bit!\n");【chinglish?】
08 scanf("%5d%5lf",&num,&dnum); //輸入一個小數
09 printf("you have input:\n");
10 printf("%d %.2lf\n",num,dnum); //輸出小數,保留小數點后2 位
11 }
代碼執行時,CMD 窗口的顯示內容為:
please input <int> and <double> type data:
please keep input data with 5 bit!
12345123.4↙ //輸入
you have input:
12345 123.40
代碼第08 行,要求執行程序的人輸入兩個5 位數據、1 個整數和1 個浮點數。但是在實際輸入過程中,輸入行輸入的是12345123.4。但從輸出可以看出,程序仍然識別其為兩個數:12345 和123.4。說明使用%md 或%mlf 時,程序最多讀取m 位就截斷數據,不論后面是否有空格進行分隔,都認為該數值的讀取完畢。
當然在輸入的時候,往往並不能保證輸入的數據寬度正好等於需要的數據寬度。此時,如果數據之間沒有使用空格等進行分隔,則程序會依次讀取每個數,每個數都讀入相應m位,最后不足m 位的那個數作為最后1 個數。
(6)格式說明中使用符號*可以過濾掉當前的輸入數據,而將下一個數據讀入后繼變量中。例如輸入代碼:
scanf("%c%*c%c%c",&a,&b,&c);
當輸入內容為ABCDEF↙時,a 的值為A,b 的值為C,c 的值為D。可以看出當讀入字符A 並將其賦值給變量a 后,下一個讀取的字符數據B 成為當前輸入的數據,但它讀入之后並不賦值給后繼變量b,變量b 得到的值是C。
(7)輸入數據時,再按回車鍵之后才會將數據傳送給各個變量。輸入的這行字符先放到緩存區中,當按回車鍵之后,這些數據會按照格式控制參數規定的要求,將數據轉換為相應格式再賦值給指定變量。如果輸入數據多於變量個數,則數據被保留在緩存區,當下一次輸入時這些數據會再被使用。
3.3 常用字符輸入輸出函數
字符數據的輸入輸出,除了使用printf()和scanf()函數之外,C 語言還提供了單個字符讀取和輸出的函數putchar()和getchar()。本節將學習這兩個函數的使用方法。
3.3.1 putchar()函數
putchar()函數的完整形式如下:
putchar(char ch);【錯:putchar()的函數原型為int putchar( int );】
該函數的功能是將字符變量ch 保存的字符【字符變量不保存字符】輸出到標准輸出設備。putchar()函數的功能與printf()函數使用%c 相同【錯:只有部分功能相同】。putchar()函數必須帶有輸出項,輸出項可以是字符常量、變量或者表達式,甚至是轉義字符【錯,沒什么“甚至”,都是int類型的表達式】。putchar()函數只能輸出一個字符,不能輸出字符串。例如代碼:
putchar('A');
可以輸出字符'A'。
%注意:這里使用的是單引號' ',與printf()函數的格式控制字符串不同。
3.3.2 getchar()函數
getchar()函數的功能是從標准輸入設備上讀取一個字符。字符在按下回車鍵之后被送到緩沖區,然后getchar()函數從緩沖區取出並返回。getchar()不帶任何參數,其通常的格式如下:
ch = getchar();
其中ch 是一個字符變量【錯:C語言並沒有對ch的類型做出限制,通常應該是int類型】,getchar()函數執行的結果通過賦值符號=賦值給ch 保存。
例如代碼3-7,實現了使用getchar()函數讀入一個小寫字符,並且通過putchar()函數輸出該字符的大寫形式。
代碼3-7 小寫字母轉化為大寫字母(3-7.cpp)
01 #include<stdio.h>
02 void main()
03 {
04 char ch;
05 ch = getchar(); //讀入字符
06 ch -= 32【MAGIC NUMBER,風格拙劣,且代碼缺乏一般性】 //將小寫變為大寫
07 putchar(ch); //輸出字符
08 }
代碼通過getchar()函數讀入字符,使用putchar()函數輸出字符。在ASCII 碼中,大寫字母比小寫字母的數值小32,例如字母A 的編碼為65,字母a 的編碼為97,兩者的差值為32。因此任何一個小寫字母的字符,減去32 就是該字母的大寫字母。代碼第06 行,通過復合算術運算【臆造概念】減去32,將其值修改為相應的大寫字母的值。
3.4 本 章 小 結
本章內容較少,但非常重要。學好本章的標准輸入輸出函數,對今后的學習都會有莫大的幫助。通過輸入輸出,讀者可以很方便地與計算機進行交互,可以直觀地看到計算機運行的結果。靈活的運用sacnf()函數和printf()函數,是一個C 語言程序員應該具備的最基本素質。【錯謬百出,這段話簡直是一種自我諷刺】
3.5 本 章 習 題
1.編程實現:輸入字符串,在顯示器輸出該字符串3 次。
2.編程實現:輸入兩個整數變量,計算它們的加、減、乘、除后輸出結果。
3.編程實現:輸入一個字符,輸出該字符的ASCII 值。
4.編程實現:輸入3 個數,求其平均值並輸出。