中國建設(shè)集團(tuán)門戶網(wǎng)站百度信息流怎么收費
第 6 章 分支語句和邏輯運算符
C++是在 C 語言基礎(chǔ)上開發(fā)的一種集面向?qū)ο缶幊?、泛型編程和過程化編程于一體的編程語言,是C語言的超集。本書是根據(jù)2003年的ISO/ANSI C++標(biāo)準(zhǔn)編寫的,通過大量短小精悍的程序詳細(xì)而全面地闡述了 C++的基本概念和技術(shù),并專辟一章介紹了C++11新增的功能。
《C++ Primer Plus(第6版)中文版》分18章,分別介紹了C++程序的運行方式、基本數(shù)據(jù)類型、復(fù)合數(shù)據(jù)類型、循環(huán)和關(guān)系表達(dá)式、分支語句和邏輯運算符、函數(shù)重載和函數(shù)模板、內(nèi)存模型和名稱空間、類的設(shè)計和使用、多態(tài)、虛函數(shù)、動態(tài)內(nèi)存分配、繼承、代碼重用、友元、異常處理技術(shù)、string類和標(biāo)準(zhǔn)模板庫、輸入/輸出、C++11新增功能等內(nèi)容。
《C++ Primer Plus(第6版)中文版》針對C++初學(xué)者,從C語言基礎(chǔ)知識開始介紹,然后在此基礎(chǔ)上詳細(xì)闡述C++新增的特性,因此不要求讀者有C語言方面的背景知識。《C++ Primer Plus(第6版)中文版》可作為高等院校教授C++課程的教材,也可供初學(xué)者自學(xué)C++時使用。
本章內(nèi)容包括:if 語句。if else 語句。邏輯運算符:&&、||和!。cctype 字符函數(shù)庫。條件運算符:?:。switch 語句。continue 和 break 語句。讀取數(shù)字的循環(huán)?;疚募斎?輸出。
設(shè)計智能程序的一個關(guān)鍵是使程序具有決策能力。第 5 章介紹了一種決策方式——循環(huán),在循環(huán)中,
程序決定是否繼續(xù)循環(huán)?,F(xiàn)在,來研究一下 C++是如何使用分支語句在可選擇的操作中做出決定的。程序
應(yīng)使用哪一種防止吸血鬼的方案(大蒜還是十字架)呢?用戶選擇了哪個菜單選項呢?用戶是否輸入了 0?
C++提供了 if 和 switch 語句來進(jìn)行決策,它們是本章的主要主題。另外,還將介紹條件運算符和邏輯運算
符,前者提供了另一種決策方式,而后者允許將兩個測試組合在一起。最后,本章將首次介紹文件輸入/
輸出。
6.1 if 語句
當(dāng) C++程序必須決定是否執(zhí)行某個操作時,通常使用 if 語句來實現(xiàn)選擇。if 有兩種格式:if 和 if else。
首先看一看簡單的 if,它模仿英語,如“If you have a Captain Cookie card, you get a free cookie(如果您有一
張 Captain Cookie 卡,就可獲得免費的小甜餅)”。如果測試條件為 true,則 if 語句將引導(dǎo)程序執(zhí)行語句或
語句塊;如果條件是 false,程序?qū)⑻^這條語句或語句塊。因此,if 語句讓程序能夠決定是否應(yīng)執(zhí)行特定
的語句。
if 語句的語法與 while 相似:
如果 test-condition(測試條件)為 true,則程序?qū)?zhí)行 statement(語句),后者既可以是一條語
句,也可以是語句塊。如果測試條件為 false,則程序?qū)⑻^語句(參見圖 6.1)。和循環(huán)測試條件一
樣,if 測試條件也將被強制轉(zhuǎn)換為 bool 值,因此 0 將被轉(zhuǎn)換為 false,非零為 true。整個 if 語句被視
為一條語句。
通常情況下,測試條件都是關(guān)系表達(dá)式,如那些用來控制循環(huán)的表達(dá)式。例如,假設(shè)讀者希望程序計
算輸入中的空格數(shù)和字符總數(shù),則可以在 while 循環(huán)中使用 cin.get(char)來讀取字符,然后使用 if 語句識
166 C++ Primer Plus(第 6 版)中文版
別空格字符并計算其總數(shù)。程序清單 6.1 完成了這項工作,它使用句點(.)來確定句子的結(jié)尾。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qZfLPCHs-1678173837043)(2023-03-06-18-53-41.png)]
### 6.1.1 if else 語句
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WMBeTVa0-1678173837044)(2023-03-06-19-09-01.png)]
條件運算符和錯誤防范
許多程序員將更直觀的表達(dá)式 variable = =value 反轉(zhuǎn)為 value = =variable,以此來捕獲將相等運算符誤
寫為賦值運算符的錯誤。例如,下述條件有效,可以正常工作:
if (3 == myNumber)
但如果錯誤地使用下面的條件,編譯器將生成錯誤消息,因為它以為程序員試圖將一個值賦給一個字
面值(3 總是等于 3,而不能將另一個值賦給它):
if (3 = myNumber)
假設(shè)犯了類似的錯誤,但使用的是前一種表示方法:
if (myNumber = 3)
編譯器將只是把 3 賦給 myNumber,而 if 中的語句塊將包含非常常見的、而又非常難以發(fā)現(xiàn)的錯誤(然
而,很多編譯器會發(fā)出警告,因此注意警告是明智的)。一般來說,編寫讓編譯器能夠發(fā)現(xiàn)錯誤的代碼,比
找出導(dǎo)致難以理解的錯誤的原因要容易得多。
6.2 邏輯表達(dá)式
經(jīng)常需要測試多種條件。例如,字符要是小寫,其值就必須大于或等于’a’,且小于或等于’z’。如果要
求用戶使用 y 或 n 進(jìn)行響應(yīng),則希望用戶無論輸入大寫(Y 和 N)或小寫都可以。為滿足這種需要,C++
提供了 3 種邏輯運算符,來組合或修改已有的表達(dá)式。這些運算符分別是邏輯 OR(||)、邏輯 AND(&&)
和邏輯 NOT(!)。下面介紹這些運算符。
6.2.1 邏輯 OR 運算符:||
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eJyXsdzF-1678173837044)(2023-03-06-19-17-11.png)]
6.2.2 邏輯 AND 運算符:&&
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2lzisQ7f-1678173837045)(2023-03-06-19-18-53.png)]
取值范圍測試
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CIOvmENr-1678173837045)(2023-03-06-19-19-30.png)]
6.2.4 邏輯 NOT 運算符:!
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aA4IHMVD-1678173837046)(2023-03-06-19-20-15.png)]
6.3 字符函數(shù)庫 cctype
C++從 C 語言繼承了一個與字符相關(guān)的、非常方便的函數(shù)軟件包,它可以簡化諸如確定字符是否為大
寫字母、數(shù)字、標(biāo)點符號等工作,這些函數(shù)的原型是在頭文件 cctype(老式的風(fēng)格中為 ctype.h)中定義的。
例如,如果 ch 是一個字母,則 isalpha(ch)函數(shù)返回一個非零值,否則返回 0。同樣,如果 ch 是標(biāo)點符
號(如逗號或句號),函數(shù) ispunct(ch)將返回 true。(這些函數(shù)的返回類型為 int,而不是 bool,但通常 bool
轉(zhuǎn)換讓您能夠?qū)⑺鼈円暈?bool 類型。)
使用這些函數(shù)比使用 AND 和 OR 運算符更方便。例如,下面是使用 AND 和 OR 來測試字符 ch 是不
是字母字符的代碼:
與使用 isalpha( )相比:
isalpha( )不僅更容易使用,而且更通用。AND/OR 格式假設(shè) A-Z 的字符編碼是連續(xù)的,其他字符的編
碼不在這個范圍內(nèi)。這種假設(shè)對于 ASCII 碼來說是成立的,但通常并非總是如此。
程序清單 6.8 演示一些 ctype 庫函數(shù)。具體地說,它使用 isalpha( )來檢查字符是否為字母字符,使用
isdigits( )來測試字符是否為數(shù)字字符,如 3,使用 isspace( )來測試字符是否為空白,如換行符、空格和制
表符,使用 ispunct( )來測試字符是否為標(biāo)點符號。該程序還復(fù)習(xí)了 if else if 結(jié)構(gòu),并在一個 while 循環(huán)中
使用了 cin.get(char)。
i[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xSH5jYPA-1678173837046)(2023-03-06-19-43-52.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ysol9paX-1678173837046)(2023-03-06-19-44-54.png)]
6.4 ?:運算符(三元運算符)
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QFtRUExx-1678173837046)(2023-03-06-19-48-07.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-speOy706-1678173837047)(2023-03-06-20-19-53.png)]
6.5 switch 語句
假設(shè)要創(chuàng)建一個屏幕菜單,要求用戶從 5 個選項中選擇一個,例如,便宜、適中、昂貴、奢侈、過度。
雖然可以擴(kuò)展 if else if else 序列來處理這 5 種情況,但 C++的 switch 語句能夠更容易地從大型列表中進(jìn)行
選擇。下面是 switch 語句的通用格式
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aoAQG3fJ-1678173837047)(2023-03-06-23-10-15.png)]
C++的 switch 語句就像指路牌,告訴計算機接下來應(yīng)執(zhí)行哪行代碼。執(zhí)行到 switch 語句時,程序?qū)⑻?br /> 到使用 integer-expression 的值標(biāo)記的那一行。例如,如果 integer-expression 的值為 4,則程序?qū)?zhí)行標(biāo)簽為
case 4:那一行。顧名思義,integer-expression 必須是一個結(jié)果為整數(shù)值的表達(dá)式。另外,每個標(biāo)簽都必須
是整數(shù)常量表達(dá)式。最常見的標(biāo)簽是 int 或 char 常量(如 1 或’q’),也可以是枚舉量。如果 integer-expression
不與任何標(biāo)簽匹配,則程序?qū)⑻綐?biāo)簽為 default 的那一行。Default 標(biāo)簽是可選的,如果被省略,而又沒
有匹配的標(biāo)簽,則程序?qū)⑻?switch 后面的語句處執(zhí)行(參見圖 6.3)。
switch 語句與 Pascal 等語言中類似的語句之間存在重大的差別。C++中的 case 標(biāo)簽只是行標(biāo)簽,而不
是選項之間的界線。也是說,程序跳到 switch 中特定代碼行后,將依次執(zhí)行之后的所有語句,除非有明確
的其他指示。程序不會在執(zhí)行到下一個 case 處自動停止,要讓程序執(zhí)行完一組特定語句后停止,必須使用
break 語句。這將導(dǎo)致程序跳到 switch 后面的語句處執(zhí)行。
6.6 break 和 continue 語句
break 和 continue 語句都使程序能夠跳過部分代碼??梢栽?switch 語句或任何循環(huán)中使用 break 語句,
使程序跳到 switch 或循環(huán)后面的語句處執(zhí)行。continue 語句用于循環(huán)中,讓程序跳過循環(huán)體中余下的代碼,
并開始新一輪循環(huán)(參見圖 6.4)。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fQKQfZAY-1678173837047)(2023-03-06-23-13-48.png)]
6.8 簡單文件輸入/輸出
有時候,通過鍵盤輸入并非最好的選擇。例如,假設(shè)您編寫了一個股票分析程序,并下載了一個文件,
其中包含 1000 種股票的價格。在這種情況下,讓程序直接讀取文件,而不是手工輸入文件中所有的值,將
方便得多。同樣,讓程序?qū)⑤敵鰧懭氲轿募⒏鼮榉奖?#xff0c;這樣可得到有關(guān)結(jié)果的永久性記錄。
幸運的是,C++使得將讀取鍵盤輸入和在屏幕上顯示輸出(統(tǒng)稱為控制臺輸入/輸出)的技巧用于文件
輸入/輸出(文件 I/O)非常簡單。第 17 章將更詳細(xì)地討論這些主題,這里只介紹簡單的文本文件 I/O。
6.8.1 文本 I/O 和文本文件
這里再介紹一下文本 I/O 的概念。使用 cin 進(jìn)行輸入時,程序?qū)⑤斎胍暈橐幌盗械淖止?jié),其中每個字
節(jié)都被解釋為字符編碼。不管目標(biāo)數(shù)據(jù)類型是什么,輸入一開始都是字符數(shù)據(jù)——文本數(shù)據(jù)。然后,cin
對象負(fù)責(zé)將文本轉(zhuǎn)換為其他類型。為說明這是如何完成的,來看一些處理同一個輸入行的代碼。
假設(shè)有如下示例輸入行:
來看一下使用不同數(shù)據(jù)類型的變量來存儲時,cin 是如何處理該輸入行的。首先,來看使用 char 數(shù)據(jù)
類型的情況:
輸入行中的第一個字符被賦給 ch。在這里,第一個字符是數(shù)字 3,其字符編碼(二進(jìn)制)被存儲在變
量 ch 中。輸入和目標(biāo)變量都是字符,因此不需要進(jìn)行轉(zhuǎn)換。注意,這里存儲的數(shù)值 3,而是字符 3 的編碼。
執(zhí)行上述輸入語句后,輸入隊列中的下一個字符為字符 8,下一個輸入操作將對其進(jìn)行處理。
接下來看看 int 類型:
在這種情況下,cin 將不斷讀取,直到遇到非數(shù)字字符。也就是說,它將讀取 3 和 8,這樣句點將成為
輸入隊列中的下一個字符。cin 通過計算發(fā)現(xiàn),這兩個字符對應(yīng)數(shù)值 38,因此將 38 的二進(jìn)制編碼復(fù)制到變
量 n 中。
接下來看看 double 類型:
在這種情況下,cin 將不斷讀取,直到遇到第一個不屬于浮點數(shù)的字符。也就是說,cin 讀取 3、8、句
點和 5,使得空格成為輸入隊列中的下一個字符。cin 通過計算發(fā)現(xiàn),這四個字符對應(yīng)于數(shù)值 38.5,因此將
38.5 的二進(jìn)制編碼(浮點格式)復(fù)制到變量 x 中。
接下來看看 char 數(shù)組的情況:
在這種情況下,cin 將不斷讀取,直到遇到空白字符。也就是說,它讀取 3、8、句點和 5,使得空格成
為輸入隊列中的下一個字符。然后,cin 將這 4 個字符的字符編碼存儲到數(shù)組 word 中,并在末尾加上一個
空字符。這里不需要進(jìn)行任何轉(zhuǎn)換。
最后,來看一下另一種使用 char 數(shù)組來存儲輸入的情況:
在這種情況下,cin 將不斷讀取,直到遇到換行符(示例輸入行少于 50 個字符)。所有字符都將被存儲
到數(shù)組 word 中,并在末尾加上一個空字符。換行符被丟棄,輸入隊列中的下一個字符是下一行中的第一
個字符。這里不需要進(jìn)行任何轉(zhuǎn)換。
對于輸入,將執(zhí)行相反的轉(zhuǎn)換。即整數(shù)被轉(zhuǎn)換為數(shù)字字符序列,浮點數(shù)被轉(zhuǎn)換為數(shù)字字符和其他字符
組成的字符序列(如 284.53 或?1.58E+06)。字符數(shù)據(jù)不需要做任何轉(zhuǎn)換。
這里的要點是,輸入一開始為文本。因此,控制臺輸入的文件版本是文本文件,即每個字節(jié)都存儲了
一個字符編碼的文件。并非所有的文件都是文本文件,例如,數(shù)據(jù)庫和電子表格以數(shù)值格式(即二進(jìn)制整
數(shù)或浮點格式)來存儲數(shù)值數(shù)據(jù)。另外,字處理文件中可能包含文本信息,但也可能包含用于描述格式、
字體、打印機等的非文本數(shù)據(jù)。
本章討論的文件 I/O 相當(dāng)于控制臺 I/O,因此僅適用于文本文件。要創(chuàng)建文本文件,用于提供輸入,可
使用文本編譯器,如 DOS 中的 EDIT、Windows 中的“記事本”和 UNIX/Linux 系統(tǒng)中的 vi 或 emacs。
也
可以使用字處理程序來創(chuàng)建,但必須將文件保存為文本格式。IDE 中的源代碼編輯器生成的也是文本文件,
事實上,源代碼文件就屬于文本文件。同樣,可以使用文本編輯器來查看通過文本輸出創(chuàng)建的文件。
6.8.2 寫入到文本文件中
對于文件輸入,C++使用類似于 cout 的東西。下面來復(fù)習(xí)一些有關(guān)將 cout 用于控制臺輸出的基本事實,
為文件輸出做準(zhǔn)備。
必須包含頭文件 iostream。
頭文件 iostream 定義了一個用處理輸出的 ostream 類。
頭文件 iostream 聲明了一個名為 cout 的 ostream 變量(對象)。
必須指明名稱空間 std;例如,為引用元素 cout 和 endl,必須使用編譯指令 using 或前綴 std::。
可以結(jié)合使用 cout 和運算符<<來顯示各種類型的數(shù)據(jù)。
文件輸出與此極其相似。
必須包含頭文件 fstream。
頭文件 fstream 定義了一個用于處理輸出的 ofstream 類。
需要聲明一個或多個 ofstream 變量(對象),并以自己喜歡的方式對其進(jìn)行命名,條件是遵守常用
的命名規(guī)則。
必須指明名稱空間 std;例如,為引用元素 ofstream,必須使用編譯指令 using 或前綴 std::。
需要將 ofstream 對象與文件關(guān)聯(lián)起來。為此,方法之一是使用 open( )方法。
使用完文件后,應(yīng)使用方法 close( )將其關(guān)閉。
可結(jié)合使用 ofstream 對象和運算符<<來輸出各種類型的數(shù)據(jù)。
注意,雖然頭文件 iostream 提供了一個預(yù)先定義好的名為 cout 的 ostream 對象,但您必須聲明自己的
ofstream 對象,為其命名,并將其同文件關(guān)聯(lián)起來。下面演示了如何聲明這種對象:
下面演示了如何將這種對象與特定的文件關(guān)聯(lián)起來:
注意,方法 open( )接受一個 C-風(fēng)格字符串作為參數(shù),這可以是一個字面字符串,也可以是存儲在數(shù)組
192 C++ Primer Plus(第 6 版)中文版
中的字符串。
下面演示了如何使用這種對象:
重要的是,聲明一個 ofstream 對象并將其同文件關(guān)聯(lián)起來后,便可以像使用 cout 那樣使用它。所有可
用于 cout 的操作和方法(如<<、endl 和 setf( ))都可用于 ofstream 對象(如前述示例中的 outFile 和 fout)。
總之,使用文件輸出的主要步驟如下。
1.包含頭文件 fstream。
2.創(chuàng)建一個 ofstream 對象。
3.將該 ofstream 對象同一個文件關(guān)聯(lián)起來。
4.就像使用 cout 那樣使用該 ofstream 對象。
程序清單 6.15 中的程序演示了這種方法。它要求用戶輸入信息,然后將信息顯示到屏幕上,再將這些
信息寫入到文件中。讀者可以使用文本編輯器來查看該輸出文件的內(nèi)容。
該程序的最后一部分與 cout 部分相同,只是將 cout 替換為 outFile 而已。下面是該程序的運行情況:
屏幕輸出是使用 cout 的結(jié)果。如果您查看該程序的可執(zhí)行文件所在的目錄,將看到一個名為 carinfo.txt
的新文件(根據(jù)編譯器的配置,該文件也可能位于其他文件夾),其中包含使用 outFile 生成的輸出。如果
使用文本編輯器打開該文件,將發(fā)現(xiàn)其內(nèi)容如下:
正如讀者看到的,outFile 將 cout 顯示到屏幕上的內(nèi)容寫入到了文件 carinfo.txt 中。
程序說明
在程序清單 6.15 的程序中,聲明一個 ofstream 對象后,便可以使用方法 open( )將該對象特定文件關(guān)聯(lián)
起來:
程序使用完該文件后,應(yīng)該將其關(guān)閉:
注意,方法 close( )不需要使用文件名作為參數(shù),這是因為 outFile 已經(jīng)同特定的文件關(guān)聯(lián)起來。如果
您忘記關(guān)閉文件,程序正常終止時將自動關(guān)閉它。
outFile 可使用 cout 可使用的任何方法。它不但能夠使用運算符<<,還可以使用各種格式化方法,如
setf( )和 precision( )。這些方法只影響調(diào)用它們的對象。例如,對于不同的對象,可以提供不同的值:
讀者需要記住的重點是,創(chuàng)建好 ofstream 對象(如 outFile)后,便可以像使用 cout 那樣使用它。
回到 open( )方法:
在這里,該程序運行之前,文件 carinfo.txt 并不存在。在這種情況下,方法 open( )將新建一個名為
carinfo.txt 的文件。如果在此運行該程序,文件 carinfo.txt 將存在,此時情況將如何呢?默認(rèn)情況下,open( )
將首先截斷該文件,即將其長度截短到零——丟其原有的內(nèi)容,然后將新的輸出加入到該文件中。第 17
章將介紹如何修改這種默認(rèn)行為。
194 C++ Primer Plus(第 6 版)中文版
警告:打開已有的文件,以接受輸出時,默認(rèn)將它其長度截短為零,因此原來的內(nèi)容將丟失。
打開文件用于接受輸入時可能失敗。例如,指定的文件可能已經(jīng)存在,但禁止對其進(jìn)行訪問。因此細(xì)
心的程序員將檢查打開文件的操作是否成功,這將在下一個例子中介紹。
6.8.3 讀取文本文件
接下來介紹文本文件輸入,它是基于控制臺輸入的??刂婆_輸入涉及多個方面,下面首先總結(jié)這些
方面。
必須包含頭文件 iostream。
頭文件 iostream 定義了一個用處理輸入的 istream 類。
頭文件 iostream 聲明了一個名為 cin 的 istream 變量(對象)。
必須指明名稱空間 std;例如,為引用元素 cin,必須使用編譯指令 using 或前綴 std::。
可以結(jié)合使用 cin 和運算符>>來讀取各種類型的數(shù)據(jù)。
可以使用 cin 和 get( )方法來讀取一個字符,使用 cin 和 getline( )來讀取一行字符。
可以結(jié)合使用 cin 和 eof( )、fail( )方法來判斷輸入是否成功。
對象 cin 本身被用作測試條件時,如果最后一個讀取操作成功,它將被轉(zhuǎn)換為布爾值 true,否則
被轉(zhuǎn)換為 false。
文件輸出與此極其相似:
必須包含頭文件 fstream。
頭文件 fstream 定義了一個用于處理輸入的 ifstream 類。
需要聲明一個或多個 ifstream 變量(對象),并以自己喜歡的方式對其進(jìn)行命名,條件是遵守常用
的命名規(guī)則。
必須指明名稱空間 std;例如,為引用元素 ifstream,必須使用編譯指令 using 或前綴 std::。
需要將 ifstream 對象與文件關(guān)聯(lián)起來。為此,方法之一是使用 open( )方法。
使用完文件后,應(yīng)使用 close( )方法將其關(guān)閉。
可結(jié)合使用 ifstream 對象和運算符>>來讀取各種類型的數(shù)據(jù)。
可以使用 ifstream 對象和 get( )方法來讀取一個字符,使用 ifstream 對象和 getline( )來讀取一行字符。
可以結(jié)合使用 ifstream 和 eof( )、fail( )等方法來判斷輸入是否成功。
ifstream 對象本身被用作測試條件時,如果最后一個讀取操作成功,它將被轉(zhuǎn)換為布爾值 true,否
則被轉(zhuǎn)換為 false。
注意,雖然頭文件 iostream 提供了一個預(yù)先定義好的名為 cin 的 istream 對象,但您必須聲明自己的
ifstream 對象,為其命名,并將其同文件關(guān)聯(lián)起來。下面演示了如何聲明這種對象:
下面演示了如何將這種對象與特定的文件關(guān)聯(lián)起來:
注意,方法 open( )接受一個 C-風(fēng)格字符串作為參數(shù),這可以是一個字面字符串,也可以是存儲在數(shù)組
中的字符串。
下面演示了如何使用這種對象:
第 6 章 分支語句和邏輯運算符 195
重要的是,聲明一個 ifstream 對象并將其同文件關(guān)聯(lián)起來后,便可以像使用 cin 那樣使用它。所有可用
于 cin 的操作和方法都可用于 ifstream 對象(如前述示例中的 inFile 和 fin)。
如果試圖打開一個不存在的文件用于輸入,情況將如何呢?這種錯誤將導(dǎo)致后面使用 ifstream 對象進(jìn)
行輸入時失敗。檢查文件是否被成功打開的首先方法是使用方法 is_open( ),為此,可以使用類似于下面的
代碼:
如果文件被成功地打開,方法 is_open( )將返回 true;因此如果文件沒有被打開,表達(dá)式!inFile.isopen( )
將為 true。函數(shù) exit( )的原型是在頭文件 cstdlib 中定義的,在該頭文件中,還定義了一個用于同操作系統(tǒng)
通信的參數(shù)值 EXIT_FAILURE。函數(shù) exit( )終止程序。
方法 is_open( )是 C++中相對較新的內(nèi)容。如果讀者的編譯器不支持它,可使用較老的方法 good( )來代
替。正如第 17 章將討論的,方法 good( )在檢查可能存在的問題方面,沒有 is_open( )那么廣泛。
程序清單 6.16 中的程序打開用戶指定的文件,讀取其中的數(shù)字,然后指出文件中包含多少個值以及它
們的和與平均值。正確地設(shè)計輸入循環(huán)至關(guān)重要,詳細(xì)請參閱后面的“程序說明”。注意,通過使用了 if
語句,該程序受益匪淺。
要運行程序清單 6.16 中的程序,首先必須創(chuàng)建一個包含數(shù)字的文本文件。為此,可以使用文本編輯器
(如用于編寫源代碼的文本編輯器)。假設(shè)該文件名為 scores.txt,包含的內(nèi)容如下:
程序還必須能夠找到這個文件。通常,除非在輸入的文件名中包含路徑,否則程序?qū)⒃诳蓤?zhí)行文件所
屬的文件夾中查找。
警告:Windows 文本文件的每行都以回車字符和換行符結(jié)尾;通常情況下,C++在讀取文件時將這兩
個字符轉(zhuǎn)換為換行符,并在寫入文件時執(zhí)行相反的轉(zhuǎn)換。有些文本編輯器(如 Metrowerks CodeWarrior IDE
編輯器),不會自動在最后一行末尾加上換行符。因此,如果讀者使用的是這種編輯器,請在輸入最后的文
本后按下回車鍵,然后再保存文件。
下面是該程序的運行情況:
程序說明
該程序沒有使用硬編碼文件名,而是將用戶提供的文件名存儲到字符數(shù)組 filename 中,然后將該數(shù)組
用作 open( )的參數(shù):
正如本章前面討論的,檢查文件是否被成功打開至關(guān)重要。下面是一些可能出問題的地方:指定的文
件可能不存在;文件可能位于另一個目錄(文件夾)中;訪問可能被拒絕;用戶可能輸錯了文件名或省略
了文件擴(kuò)展名。很多初學(xué)者花了大量的時間檢查文件讀取循環(huán)的哪里出了問題后,最終卻發(fā)現(xiàn)問題在于程
序沒有打開文件。檢查文件是否被成功打開可避免將這種將精力放在錯誤地方的情況發(fā)生。
讀者需要特別注意的是文件讀取循環(huán)的正確設(shè)計。讀取文件時,有幾點需要檢查。首先,程序讀取文
件時不應(yīng)超過 EOF。如果最后一次讀取數(shù)據(jù)時遇到 EOF,方法 eof( )將返回 true。其次,程序可能遇到類
型不匹配的情況。例如,程序清單 6.16 期望文件中只包含數(shù)字。如果最后一次讀取操作中發(fā)生了類型不匹
配的情況,方法 fail( )將返回 true(如果遇到了 EOF,該方法也將返回 true)。最后,可能出現(xiàn)意外的問題,
如文件受損或硬件故障。如果最后一次讀取文件時發(fā)生了這樣的問題,方法 bad( )將返回 true。不要分別檢
查這些情況,一種更簡單的方法是使用 good( )方法,該方法在沒有發(fā)生任何錯誤時返回 true:
然后,如果愿意,可以使用其他方法來確定循環(huán)終止的真正原因:
這些代碼緊跟在循環(huán)的后面,用于判斷循環(huán)為何終止。由于 eof( )只能判斷是否到達(dá) EOF,而 fail( )可
用于檢查 EOF 和類型不匹配,因此上述代碼首先判斷是否到達(dá) EOF。這樣,如果執(zhí)行到了 else if 測試,便
可排除 EOF,因此,如果 fail( )返回 true,便可斷定導(dǎo)致循環(huán)終止的原因是類型不匹配。
方法 good( )指出最后一次讀取輸入的操作是否成功,這一點至關(guān)重要。這意味著應(yīng)該在執(zhí)行讀取輸入
的操作后,立刻應(yīng)用這種測試。為此,一種標(biāo)準(zhǔn)方法是,在循環(huán)之前(首次執(zhí)行循環(huán)測試前)放置一條輸
入語句,并在循環(huán)的末尾(下次執(zhí)行循環(huán)測試之前)放置另一條輸入語句:
鑒于以下事實,可以對上述代碼進(jìn)行精簡:表達(dá)式 inFile >> value 的結(jié)果為 inFile,而在需要一個 bool
值的情況下,inFile 的結(jié)果為 inFile.good( ),即 true 或 false。
因此,可以將兩條輸入語句用一條用作循環(huán)測試的輸入語句代替。也就是說,可以將上述循環(huán)結(jié)構(gòu)替
換為如下循環(huán)結(jié)構(gòu):
這種設(shè)計仍然遵循了在測試之前進(jìn)行讀取的規(guī)則,因為要計算表達(dá)式 inFile >> value 的值,程序必須
首先試圖將一個數(shù)字讀取到 value 中。
至此,讀者對文件 I/O 有了初步的認(rèn)識。
6.9 總結(jié)
使用引導(dǎo)程序選擇不同操作的語句后,程序和編程將更有趣(這是否也能引起程序員們的興趣,我沒
有做過研究)。C++提供了 if 語句、if else 語句和 switch 語句來管理選項。if 語句使程序有條件地執(zhí)行語句
或語句塊,也就是說,如果滿足特定的條件,程序?qū)?zhí)行特定的語句或語句塊。if else 語句程序選擇執(zhí)行
兩個語句或語句塊之一。可以在這條語句后再加上 if else,以提供一系列的選項。switch 語句引導(dǎo)程序執(zhí)
行一系列選項之一。
C++還提供了幫助決策的運算符。第 5 章討論了關(guān)系表達(dá)式,這種表達(dá)式對兩個值進(jìn)行比較。if 和 if else
語句通常使用關(guān)系表達(dá)式作為測試條件。通過使用邏輯運算符(&&、||和!),可以組合或修改關(guān)系表達(dá)式,
創(chuàng)建更細(xì)致的測試。條件運算符(?:)提供了一種選擇兩個值之一的簡潔方式。
cctype 字符函數(shù)庫提供了一組方便的、功能強大的工具,可用于分析字符輸入。
對于文件 I/O 來說,循環(huán)和選擇語句是很有用的工具;文件 I/O 與控制臺 I/O 極其相似。聲明 ifstream
和 ofstream 對象,并將它們同文件關(guān)聯(lián)起來后,便可以像使用 cin 和 cout 那樣使用這些對象。
使用循環(huán)和決策語句,便可以編寫有趣的、智能的、功能強大的程序。不過我們剛開始涉足 C++的強
大功能,下一章將介紹函數(shù)。