1. 程式人生 > >C++ Primer Plus--分支語句和邏輯運算子(六)

C++ Primer Plus--分支語句和邏輯運算子(六)

C++提供了if和switch語句來進行決策,還有邏輯運算子和條件運算子。

6.1 if語句

使用if語句來統計語句中的空格總數,實現如下:

if.cpp

#include <iostream>
using namespace std;
int main()
{
	char ch;
	int spaces = 0;
	int total = 0;
	cin.get(ch);
	while (ch != '.')
	{
		if (ch == ' ')
			spaces++;
		total++;
		cin.get(ch);
	}
	cout <<  spaces << " spaces, " << total ;
	cout << " charachers total in sentence.\n";
	return 0;
}

結果:

The balloonist was an airhead
with lofty goals.
6 spaces, 46 charachers total in sentence.

只要當ch為空格時,語句spaces++才被執行。因為語句total位於if語句的外面,因此每輪迴圈中都被執行。

6.1.1 if else語句

if (test-condition)
	statement1
else
	statement2

如果測試條件為true,則程式將執行statement1,跳過statement2;如果測試條件為false,則程式將跳過statement1,執行statement2。

6.1.2 格式化if else語句

如果操作部分需要多條語句,需要使用大括號將它們括起來,組成一個語句塊。

if (ch == 'z')
{
	zorro++;
	cout << "Another zorro candidate\n";
}
else 
{
	dull++;
	cout << "Not a Zorro candidate\n";
}

6.1.3 if else if else結構

實際中,可能需要程式提供兩個以上的選擇:

if (ch == 'A')
	a_grade++;
else 
	if (ch == 'B')
		b_grade++;
	else 
		soso++;

可以寫成如下形式:

if (ch == 'A')
	a_grade++;
else if (ch == 'B')
	b_grade++;
else 
	soso++;

修改後的格式更為清晰。

ifelseif.cpp

#include <iostream>
using namespace std;
const int Fave = 27;
int main()
{
	int n;
	cout << "Enter a number in the range 1-00 to find my favorite nmber: \n";
	do 
	{	cin >> n;
		if (n > Fave)
			cout <<  "Too high -- guess again:";
		else if (n < Fave)
			cout <<  "Too low -- guess agin: ";
		else
			cout << Fave << " is right!\n";
	}while (n != Fave);
	return 0;
}

結果:
Enter a number in the range 1-00 to find my favorite nmber:
22
Too low – guess agin: 44
Too high – guess again:27
27 is right!

錯誤防範:

表示式variable == value反轉寫成value == varibale。這樣,可以捕獲將相等運算子誤寫成賦值運算子的錯誤。

if (3 = var)

將一個變數賦給一個常量,編譯器將生成錯誤資訊。

if (var = 3)

這樣,將3賦給一個變數,正確的語法,編譯不會報錯,於是會導致程式出錯。

6.2 邏輯表示式

C++提供了三種邏輯運算子,分別是:邏輯OR(||)、邏輯AND(&&)和邏輯NOT(!)。

6.2.1 邏輯OR運算子

如果表示式中的任意一個或全部都為true,則得到的表示式為true。

5 == 5 || 5 == 9 //true
3 <= 5 || 5 >= 3 //true
1 > 2 || 2 > 3 //False

||運算子的優先順序比關係運算符低,因此不需要新增括號。

C++規定,||運算子是個順序點。即,先修改左側的值,再對右側的值進行判定。例如:

i++ < 6 || i == j

假設i越來的值為10,則在對i和j進行比較時,i的值將為11。另外,如果左側的表示式為true,則C++將不會去判定右側的表示式,因為只要一個表示式為true,則整個邏輯表示式為true。

6.2.2 邏輯AND運算子

僅當兩個表示式都為true時,得到的表示式才為true。

5 == 5 && 4 == 4//true
5 < 3 && 3 > 2 //false

&&運算子的優先順序低於關係運算符,因此沒必要新增括號。和||運算子一樣,&&運算子也是順序點,因此將先判定左側,並且在右側判定之前產生所有的副作用。如果左側為false,則整個邏輯表示式為false,這種情況下,C++將不會再對右側進行判定。

6.2.3 用&&來設定取值範圍

&&運算子還允許建立一系列if else if else語句,其中每種選擇都對應一個特定的取值範圍。

if	(age > 17 && age < 35)
	index = 0;
else if (age >= 35 && age < 50)
	index = 1;
else if (age >= 50 && age < 65)
	index = 2;
else
	index = 3;

注意,下面語句:

if (17 < age < 35)

編譯器不會捕獲這種錯誤,因為它仍然是合法的C++語法。<運算子是從左向右結合,因此表示式含義如下:

if ((17 < age) < 35)

但(17<age)的結果要麼為1,要麼為0。不管哪種情況,表示式的值17<age都要小於35,所以整個測試的結果總是true。

6.2.4 邏輯NOT運算子

!運算子將它後面的表示式的真值取反。!運算子的優先順序高於所有的關係運算符和算術運算子。因此,要對錶達式取反,必須使用括號將其括起來,如下:

!( x > 5);
!x > 5; // 該表示式總是為false,!x為1或0,總是小於5

!運算子對於返回true-false值或可以被解釋為true-false值的函式是很有用的。比如:

!strcmp(s1,s2);

下面的程式來篩選可賦給int變數的數字輸入。

not.cpp

#include <iostream>
#include <climits>
using namespace std;
bool is_int(double);
int main()
{
	double num;
	cout << "Enter an integer value:";
	cin >> num;
	while (! is_int(num))
	{
		cout << "Out of range -- please try again:";
		cin >> num;
	}
	int val = int(num);
	cout << "You've entered the integer " << val << endl;
	return 0;
}

bool is_int(double x)
{
	if (x <= INT_MAX && x >= INT_MIN)
		return true;
	else 
		return false;
}

結果:

Enter an integer value:1000000000000000
Out of range -- please try again:-1000000000000
Out of range -- please try again:444
You've entered the integer 444

布林函式is_int()使用了climits檔案中定義的兩個符號常量INT_MIN和INT_MAX來確定int型別的範圍。

6.2.5 邏輯運算子細節

AND和OR運算子的優先順序都低於關係運算符。

!運算子的優先順序都高於所有關係運算符和算符運算子。

邏輯AND運算子的優先順序高於邏輯OR運算子,因此:

age > 30 && age < 45 || weight > 300

被解釋為:

(age > 30 && age < 45) || weight > 300

當然,還可以使用括號來將所希望的解釋告訴程式。例如:

(age > 30 || weight > 300) && donation > 1000

C++確保程式從左向右進行邏輯運算表示式,並在知道了答案立刻停止。

6.2.6 其他表示方式

使用識別符號and、or和not來表示三種邏輯運算子。

| 運算子 | 另一種表示方式 |
|—|
| && | and |
| || | OR |
| ! | NOT |

6.3 字元函式庫cctype

C++繼承了一個與字元相關的、非常方便的函式軟體包,他可以簡化如確定字元是否為大小寫字母、數字、標點符號等工作,這些函式的原型在標頭檔案cctype(老式的風格ctype.h)中定義。

下面使用AND和OR來測試字元ch是不是字母字元的程式碼:

if (ch >= 'a' and ch <= 'z') || (ch >= 'A' && ch <= 'Z')

與使用isalpha()相比:

if (isalpha(ch))

isslpha()不僅更容易使用,而且更通用。

下面程式演示cctype庫函式。

cctypes.cpp

#include <iostream>
#include <cctype>
using namespace std;
int main()
{
	cout << "Enter text for analysis and type @ to terminate input:";
	char ch;
	int whitespace = 0;
	int digits = 0;
	int chars = 0;
	int punct = 0;
	int others = 0;
	cin.get(ch);
	while (ch != '@')
	{
		if (isalpha(ch))
			chars ++;
		else if (isspace(ch))
			whitespace++;
		else if (isdigit(ch))
			digits++;
		else if (ispunct(ch))
			punct++;
		else
			others++;
		cin.get(ch);
	}
	cout <<  chars << " letters, " 
	     <<  whitespace << " whitespace, "
	     << digits << " digits, "
	     << punct << " punctuations, "
	     << others << " others.\n";
	return 0;
}

結果:

Enter text for analysis and type @ to terminate input:
AdrenalVision Internationsl producer Adrienne Vismonger
announced production of their new 3-D film, a remake of
"My Dinner with Andre," scheduled for 2013.
@
123 letters, 23 whitespace, 5 digits, 6 punctuations, 0 others.

cctype中的字元函式:

| 函式名稱 | 返回值 |
|—|
| isalnum() | 如果引數是字母數字,即字母或數字,該函式返回true|
| isalpha() | 如果引數是字母,該函式返回true |
| iscntrl() | 如果引數是控制字元,該函式返回true |
| isdigit() | 如果引數是數字(0~9),該函式返回true |
| isgraph() | 如果引數是除空格之外的列印字元,該函式返回true |
| islower() | 如果引數是小寫字母,該函式返回true |
| isprint() | 如果引數列印字元(包括空格),該函式返回true |
| ispunct() | 如果引數是標點符號,該函式返回true |
| isspace() | 如果引數是標準空白字元,如空格、換行符、回車、製表符,該函式返回true |
| isupper() | 如果引數是大寫字母,該函式返回true |
| isxdigit() | 如果引數是十六進位制,該函式返回true |
| tolower() | 如果引數是大寫字母,則返回小寫字母 |
| toupper() | 如果引數是小寫字母,則返回大寫字母 |

6.4 ?:運算子

C++常用?:運算子來代替if else語句,它C++中唯一的3個運算元的運算子。通用格式如下:

expression1 ? expression2 : expression3

如果expression1為true,則整個表示式的值為expression2;否則,整個表示式的值為expression3。如下:

5 > 3 ? 10 : 12 //5>3為true,所以該表示式的值為19
3 == 0 ? 25 : 18 // 3==0為false,所以表示式的值為18

condit.cpp

#include <iostream>
int main()
{
	using namespace std;
	int a, b;
	cout << "Enter two integers: ";
	cin >> a >> b;
	cout << "The larger of " << a << " and " << b;
	int c = a > b ? a :b;
	cout << " is " <<  c << endl;
	return 0;
}

結果:

Enter two integers: 2 3
The larger of 2 and 3 is 3

將條件表示式巢狀在另一個條件表示式中,如下:

const char x[2][20] = {"Jason ", "at your serviece\n"};
const char * y = "Quillstone ";

for (int i = 0; i < 3; i++)
	cout << ((i < 2) ? !i ? x[i]:y : x[i]);

這是一種費解的方式,他按下面的順序列印3個字串:

Jasn Qullstone at your service

從可讀性來說,條件運算子最適合簡單關係和簡單表示式的值。

6.5 switch語句

使用者從5個選項中選擇一個,雖然可以擴充套件if else if else來處理,但C++的switch語句能夠更容易地從大型列表中進行選擇。switch語句的通用格式:

switch (integer-expression)
{
	case label1: statement(s);
	case label2: statement(s);

	default: statement(s);
} 

switch.cpp

#include <iostream>
using namespace std;
void showmenu();
void report();
void comfort();
int main()
{
	showmenu();
	int choice;
	cin >> choice;
	while (choice != 5)
	{
		switch (choice)
		{
			case 1 : cout << "\a\n";
				break;
			case 2 : report();
				break;
			case 3 : cout << "The boss was in all day.\n";
				break;
			case 4 : comfort();
				break;
			default : cout << "That's not a choce.\n";
		}
		showmenu();
		cin >> choice;
	}
	cout << "Bye!\n";
	return 0;
}

void showmenu()
{
	cout << "Please enter 1,2,3,4,5:\n"
		"1) alarm	 2) report\n"
		"3) alibi	 4) comfort\n"
		"5) quit\n";
}

void report()
{
	cout << "It's been an excellent week for business.\n";
}

void comfort()
{
	cout << "Your employees think you are the fines CEO in the induesty.\n";
}

當用戶輸入5時,while迴圈結束。輸入1到4將執行switch列表中相應的操作,輸入6將執行預設語句。

同時,也可以使用字元(而不是整數)作為選單選項和switch標籤,則可以為大寫標籤和小寫標籤提供相同的語句:

		char choice;
		switch (choice)
		{
			case 'a' :
			case 'A' : cout << "\a\n";
				break;
			case 'b' :
			case 'B' : report();
				break;
			case 'c' :
			case 'C' : cout << "The boss was in all day.\n";
				break;
			case 'd' :
			case 'D' : comfort();
				break;
			default : cout << "That's not a choce.\n";
		}

由於case 'a’後面沒有break語句,因此程式將執行下一行–case 'A’後面的語句。

6.5.1 將列舉用作標籤

使用enum定義了一組相關常量,然後在switch語句中使用這些常量。通常,cin無法識別列舉型別,因此該程式要求使用者選擇選項時輸入一個整數。將switch語句將int值和列舉標籤進行對比時,將列舉型別提升為int。

enum.cpp

#include <iostream>
enum {red, orange, yellow, green, blue, violet, indigo};
using namespace std;
int main()
{
	cout << "Enter color code(0-6):";
	int code;
	cin >> code ;
	while (code >= red and code <= indigo)
	{
		switch(code)	
		{
			case red : cout << "Her lips were red.\n"; break;
			case orange : cout << "Her hair was orange.\n"; break;
			case yellow : cout << "Her sheos were yellow.\n"; break;
			case green : cout << "Her nails were green.\n"; break;
			default : cout << "Others.\n";
		}
		cout << "Enter color code (0-6):";
		cin >> code;
	}
	cout << "Bye!\n";
	return 0;
}

結果:

Enter color code(0-6):0
Her lips were red.
Enter color code (0-6):2
Her sheos were yellow.
Enter color code (0-6):6
Others.
Enter color code (0-6):7
Bye!

6.5.2 switch和if else

switch語句和if else語句都允許程式從選項中進行選擇。if else更通用,它可以處理取值範圍。而switch並不是為處理範圍而設計的,switch語句中的每一個case標籤都必須時一個單獨的值。另外,這個值必須是整數(包括char),因此switch無法處理浮點測試。另外,case標籤值必須是常量。

6.6 break和continue

break和continue語句都是程式能過跳過部分程式碼。可以在switch語句或任何迴圈中使用break語句,使程式跳到switch或迴圈後面的語句處執行。continue語句用於迴圈中,讓程式跳過迴圈體中餘下的程式碼,並開始新一輪迴圈。如下圖:

jump.cpp

#include <iostream>
const int ArSize = 80;
int main()
{
	using namespace std;
	int letter = 0;
	char line[ArSize];
	cout << "Enter a line of text:\n";
	cin.get(line, ArSize);
	cout << "Complete line:\n " << line << endl;
	cout << "Line through first period:\n";
	for (int i = 0; line[i] != '\0'; i++)
	{
		cout << line[i];
		if (line[i] == '.')//遇到句號,結束迴圈
			break;
		if (line[i] == ' ') //只統計字母個數,空格跳過,則下面的語句將不會執行
			continue;
		letter++; //統計字母個數
		
	}
	cout << endl << letter << " letters.\n";
	return 0;
}

結果:

Enter a line of text:
Let's do lunch today. you can pay!
Complete line:
 Let's do lunch today. you can pay!
Line through first period:
Let's do lunch today.
17 letters.

程式說明

雖然continue語句導致該程式跳過迴圈體的剩餘部分,但不會跳過迴圈的更新表示式。在for迴圈中,continue語句使程式直接跳到更新表示式,然後跳到測試表達式。然而,對於while迴圈,continue將使程式直接跳到測試表達式,因此while迴圈中位於continue之後的更新表示式都被跳過。在某些情況下,這是一個問題。

6.7 讀取數字的迴圈

將一系列數字讀入陣列中,並允許使用者在陣列填滿之前結束輸入,利用如下程式碼:

int n;
cin >> n;

如果使用者輸入一個單詞,而不是一個數字,傳送這種型別匹配情況時,將發生4種情況:

  • n的值保持不變
  • 不匹配的輸入將留在輸入佇列種
  • cin物件中的一個錯誤標記被設定
  • 對cin方法的呼叫將返回false

假設編寫一個程式,來計算每天捕獲的魚的重量。這裡假設每天最多捕獲5條魚,因此一個包含5個元素的陣列將足以儲存所以的資料,但也可能沒有捕獲這麼多。如果陣列被填滿或輸入了非數字輸入,迴圈將結束。

cinfish.cpp

#include <iostream>
using namespace std;
const int Max = 5;
int main()
{
	double fish[Max];
	cout << "Please enter the weights of your fish.\n";
	cout << "You may enter up to " << Max << " fish < q to terminate>.\n";
	cout << "fish #1: ";
	int i = 0;
	while (i < Max and cin >> fish[i])
        {
		if (++i < Max)
			cout << "fish # " <<  i+1 << ": ";
	}
	double total = 0.0;
	for (int j= 0; j< i; j++)
		total += fish[j];
	if (i == 0)
		cout << "No fisht.\n";
	else 
		cout << total / i << " average weight of " << i << " fish.\n";
	return 0;
}

結果:

Please enter the weights of your fish.
You may enter up to 5 fish < q to terminate>.
fish #1: 10.2
fish # 2: 2.3
fish # 3: 4.5
fish # 4: q
5.66667 average weight of 3 fish.
[root@localhost ~]# ./a.out
Please enter the weights of your fish.
You may enter up to 5 fish < q to terminate>.
fish #1: q
No fisht.

上述程式中,cin>>fish[i]實際上是一個cin方法函式呼叫,該函式返回cin。如果cin位於測試條件中,則將被轉化為bool型別。如果輸入成功,則轉換後為true,否則為false。

當用戶輸入的不是數字時,該程式將不再讀取輸入。下面再看一個例子,假設程式要求使用者提供5個高爾夫得分,以計算平均分。如果使用者輸入非數字,程式拒絕,並要求使用者繼續輸入數字。可以看到,可以使用cin輸入表示式來檢測輸入是不是數字。程式發現使用者輸入了錯誤內容時,應採取3個步驟:

  • 重置cin以接受新的輸入
  • 刪除錯誤輸入
  • 提示使用者重新輸入

cingolf.cpp

#include <iostream>
const int Max = 5;
using namespace std;
int main()
{
 	int golf[Max];
	cout << "Enter your golf scores.\n";
	cout << "You must enter " << Max << " rounds.";
	for (int i = 0; i < Max; i++)
	{
		cout << "Round# " << i+1 << " : " ;	
		while (!(cin >> golf[i]))
		{
			cin.clear();
			while(cin.get()!='\n')
				continue;
			cout << "Please enter a number: ";
		}
	}
	double total = 0.0;
	for (int i = 0; i< Max; i++)
		total += golf[i];
	cout << total/Max << " = average score " << Max << " rounds.\n";
	return 0;
}

結果:

Enter your golf scores.
You must enter 5 rounds.
Round# 1 : 88
Round# 2 : i
Please enter a number: k
Please enter a number: 4
Round# 3 : 5
Round# 4 : 9
Round# 5 : ?
Please enter a number: 44
30 = average score 5 rounds.

clear()方法重置輸入,如果省略這條語句,程式將拒絕繼續讀取輸入。程式中如下程式碼的作用是:

while(cin.get()!='\n')
	continue;

讀取行尾之前的所有輸入,從而刪除這一行的錯誤輸入。

6.8 簡單檔案輸入/輸出

C++使得將讀取鍵盤輸入和在螢幕上顯示輸出的技巧用於檔案輸入/輸出(檔案I/O)非常簡單。

6.81 文字I/O和文字檔案

使用cin進行輸入時,程式將輸入視為一系列的位元組,其中每個位元組都被解釋為字元編碼。不管目標資料型別是什麼,輸入一開始都是字元資料–文字資料。然後,cin物件負責將文字轉換為其他型別。

char ch;
cin >> ch;

輸入例項為: 38.5 19.2

輸入行中的第一個字元被賦給ch。在這裡第一個字元是數字3,其字元編碼(二進位制)被儲存在變數ch中。輸入和目標變數都是字元,因此不需要進行轉換。注意,這裡儲存的不是數值3,而是字元3的編碼。

int n;
cin >> n;

在這種情況下,cin將不斷讀取,直到遇到非數字符號。也就是說,它讀取3和8,這樣句點將成為輸入佇列中的下一個字元。cin通過計算髮現,這兩個字元對應數字是38,因此將38的二進位制編碼複製到變數n中。

接下來看double型別:

double x;
cin >> x;

在這種情況下,cin將不斷讀取,直到遇到第一個不屬於浮點數的字元。即,cin讀取3、8、句點和5,使得空格成為輸入佇列中的下一個字元。cin通過計算髮現,這四個字元對應數字38.5,因此將38.5的二進位制編碼複製到變數x中。

接下來看看char陣列的情況:

char word[50];
cin >> word;

在這種情況下,cin將不斷讀取,直到遇到空白字元。即,它讀取3、8、句點和5,使得空格成為輸入佇列中的下一個字元。然後,cin將這4個字元編碼儲存到輸入word中,並在末尾加上一個空字元,這裡需要進行任何轉換。

最後,看一下另一種使用char陣列來儲存輸入的情況:

char word[50];
cin.getline(word,50);

在這種情況下,cin將不斷讀取,直到遇到換行符。所有字元都將被儲存到陣列word中,並在末尾新增一個空字元。換行符被丟棄,輸入佇列中的下一個字元是下一行的第一個字元。這裡不進行任何轉換。

對於輸出,將執行相反的操作。即整數被轉換為數字字元序列,浮點數被轉換為數字字元和其他字元組成的字元序列。字元資料不需要做任何轉換。

這裡的要點是:輸入一開始都是文字。因此,控制檯輸入的檔案版本是文字檔案,即每個位元組都儲存了一個字元編碼的檔案。並非所有的檔案都是文字檔案,比如,資料塊和電子表格以數值格式(即二進位制整數或浮點格式)儲存數值資料。

6.8.2 寫入的文字檔案中

檔案輸出:

  • 必須包含標頭檔案fstream;
  • 標頭檔案fstream定義了一個用於處理輸出的ofstream類;
  • 需要宣告一個或多個ofstream變數,並以自己喜歡的方式對其進行命名;
  • 必須指明名稱空間std;
  • 需要將ofstream物件與檔案關聯起來,為此方法之一是使用open()方法;
  • 使用完檔案後,應使用方法close()將其關閉;
  • 可結合使用ofstream和運算子<<來輸出各種型別的資料。

iostream標頭檔案提供了一個預先定義好的名為cout的ostream物件,但您必須宣告自己的ofstream物件,為其命名,並將其同文件關聯。宣告物件如下:

ofstream outFile;

關聯檔案如下:

outFile.open("fish.txt");
char filename[50];
cin >> filename;
outFile.open(filename);

open()接受一個c-風格字串作為輸入,可以是字面字串,也可以是儲存在陣列中的字串。

使用檔案輸出的主要步驟如下:

  • 包含標頭檔案fstream;
  • 建立一個ofstream物件;
  • 將該ofstream物件同一個檔案關聯起來;
  • 將像使用cout那樣使用該ofstream物件。(如:<<,endl和setf()都可用於ofstream物件)。

outfile.cpp

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
	char automobile[50];
	int year;
	double a_price;
	double b_price;
	
	ofstream outFile;
	outFile.open("carinfo.txt");

	cout << "Enter the amke and model of automobile: ";
	cin.getline(automobile, 50);
	cout << "Enter the model year: ";
	cin >> year;
	cout << "Enter the original asing price: ";
	cin >> a_price;
	b_price = 0.913 * a_price;

	cout.precision(5);
	cout.setf(ios_base::showpoint);
	cout << "Make and model: " << automobile << endl;
	cout << "Year: " << year << endl;
	cout << "Was asing: $" << a_price << endl;
	cout << "Now asking: $" << b_price << endl;

	outFile.precision(5);
	outFile.setf(ios_base::showpoint);
	outFile << "Make and model: " << automobile << endl;
	outFile << "Year: " << year << endl;
	outFile << "Was asking: $" << a_price << endl;
	outFile << "Now asking: $" << b_price << endl;
	outFile.close();
	return 0;
}

結果:

在程式執行之前,並不存在carinfo.txt檔案。在這種情況下,open()將新建一個名為carinfo.txt的檔案。如果在此程式執行前,該檔案已存在。預設情況下,open()將首先截斷該檔案,即將其長度截斷為零—丟棄原有的內容,然後將新的輸入加入到該檔案中。

6.8.3 讀取文字檔案

檔案輸入:

  • 必須包含標頭檔案fstream;
  • 標頭檔案fstream定義了一個用於處理輸入的ifstream類;
  • 需要宣告一個或多個ifstream變數,並以自己喜歡的方式對其進行命名;
  • 必須指明名稱空間std;
  • 需要將ifstream物件與檔案關聯起來,為此方法之一是使用open()方法;
  • 使用完檔案後,應使用方法close()將其關閉;
  • 可結合使用ifstream和運算子>>來輸出各種型別的資料;
  • 可以使用ifstream物件和get()方法來讀取一個字元,使用ifstream物件和getline()來讀取一行字元;
  • 可以結合使用ifstream和eof()、fail()等方法來判斷輸入是否成功;
  • ifstream物件本身被用作測試條件時,如果最後一個讀取操作成功,它將轉換為true,否則為false。

ifstream物件的宣告:

ifstream inFile;

關聯檔案:

inFlie.open("bowling.txt");

如果試圖開啟一個不存的檔案用於輸入,這種錯誤將導致後面使用ifstream物件進行輸入時失敗。檢查檔案是否被成功開啟的方法:is_open()。

inFile.open("bowling.txt");
if (!inFile.is_open())
	exit(EXIT_FAILURE);

函式exit()的原型在標頭檔案cstdlib中定義的,在該標頭檔案中,還定義了一個用於同作業系統通訊的引數數值EXIT_FAILURE。函式exit()終止程式。

方法is_open()是C++中比較新的內容。可以使用方法good()來代替。

sumafile.cpp

#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
const int SIZE = 60;
int main()
{
	char filename[SIZE];
	ifstream inFile;
	cout << "Enter name of data file: ";
	cin.getline(filename,SIZE);
	inFile.open(filename);
	if (!inFile.is_open())
	{
		cout << "Could not open the file " << filename << endl;
		cout << "Program terminating.\n";
		exit(EXIT_FAILURE);
	}
	double value;
	double sum = 0.0;
	int count = 0;
	
	inFile >> value;
	while (inFile.good())
	{
		++count ;
		sum += value;
		inFile >> value;
	}
	if (inFile.eof())
		cout << "End of file reached.\n";
	else if (inFile.fail())
		cout << "Input terminatd by data mismatch.\n";
	else 
		cout << "Input terminated for unknown reasion.\n";
	if (count == 0)
		cout << "No data processed.\n";
	else
	{
		cout << "Items read: " << count << endl;
		cout << "Sum: " << sum << endl;
		cout << "Average: " << sum/count << endl;
	}
	inFile.close();
	return 0;
}

結果:

檔案迴圈讀取設計時,需要注意幾點。首先,程式讀取檔案時不應超過EOF。如果最後一次讀取資料時遇到EOF,方法eof()返回true。其次,程式可能遇到型別不匹配,方法fail()返回true(如果遇到EOF,該方法也返回true)。最後,可能出現意外的問題,如檔案損壞或硬體故障。如果最後一次讀取檔案出現了這樣的問題,方法bad()將返回true。不要分佈檢查這些情況,一種更簡單的方式是使用good()方法,該方法在沒有傳送任何錯誤時返回true。同時,可以使用其他方法來確定迴圈終止的原因,如下:

	if (inFile.eof())
		cout << "End of file reached.\n";
	else if (inFile.fail())
		cout << "Input terminatd by data mismatch.\n";
	else 
		cout << "Input terminated for unknown reasion.\n";

方法god()指出最後一次讀取輸入的操作成功與否。標準的做法:

	inFile >> value;
	while (inFile.good())
	{
		++count ;
		sum += value;
		inFile >> value;
	}

由於表示式inFile >> value的結果為inFile,而在需要一個bool值的情況下,inFile的結果為inFile().good(),即true或false。於是,兩條輸入語句用一條用作迴圈測試的語句代替。因此可以簡化上面標準做法,如下:

while(inFile >> value)
{
	sum += value;
	++count;
}

6.9 總結

if語句、if else語句和switch語句

邏輯運算子

檔案輸出和輸入