從頭讀《C++ Primer Plus》(5)

第六章 分支語句和邏輯運算符

小目錄:

  • if語句
  • if else語句
  • 邏輯運算符:&&、||和!
  • 字符方法的cctype庫
  • 問號表達式
  • switch語句
  • continue和break語句
  • 數字讀入循環
  • 基本文件輸入輸出

if和if else語句

if語句用在程序需要判斷是否執行特定語句的情況。C++的if語句有兩種:if和if else。

if語句格式:

if (test-condition)
    statement

測試語句值爲true則程序就會執行其下的語句(一條語句或一個代碼塊)。而測試語句值爲false則程序會跳過其下的語句。與循環的測試相同,測試語句的值會被強轉爲bool,非零爲true,零爲false。整個if指令算作一條語句。

if else語句格式:

if (test-condition)
    statement1
else
    statement2

如果測試語句值爲true,則執行if下的語句,若測試語句值爲false,則執行else下的語句。兩條語句都可以是一條語句或一個代碼塊。一整個if else結構算作一條語句。

if else if else結構

有時程序面臨的選擇並不只有兩個選項。而if else結構算作一條語句,所以我們可以寫出以下代碼:

if (ch == 'A')
    cout << "A.";
else
    if (ch == 'B')
        cout << "B.";
    else
        cout << "...";

而C++的自由格式允許將以上代碼重新組織成更容易閱讀的格式:

if (ch == 'A')
    cout << "A.";
else if (ch == 'B')
    cout << "B.";
else
    cout << "...";

這看起來似乎是一個新的if else if else結構,但實際上這就是一個if else在另一個if else的裏頭。這一整個都算作一條語句。


邏輯表達式

經常地程序需要同時檢查多個測試值。比如一個字符需要是小寫字母,也即是它要大於等於‘a’的同時小於等於‘z’。爲了滿足這些需求,C++提供了三個邏輯運算符來組合表達式:或"||"、與"&&"、非"!"。

或“||”

這個運算符將兩個表達式組合爲一個,如果兩個表達式之一或者二者都爲true或非零,則整個表達式值爲true,否則爲false。

或運算符的優先級比關係運算符低,所以兩側的表達式不需要加括號。

C++將或運算符定義爲一個序列點,也即是,對於左側表達式的值的任何修改都必須在或運算符之前完成。比如:

i++ < 6 || i == j

假如i的初始值是10.則在i==j執行前,i的值是11.另外,如果左側的表達式值爲true,則C++就不會執行右側的表達式,因爲左側表達式爲true就已經決定了整個表達式的值爲true。

與“&&”

這個運算符同樣把兩個表達式組合,當兩個表達式的值都是true時整個表達式值爲true,否則爲false。

和或運算符相同,與運算符也有着比關係運算符更低的優先級,且它也是一個序列點。而如果左側表達式值爲false,則整個表達式的值一定爲false,右側表達式就不會被執行。

非“!”

非運算符會把跟在其後的表達式的值翻轉。即 !true = false, !false = true。

邏輯運算符優先級

上方提到或和與運算符優先級比關係運算符低。所以可以寫出以下代碼:

x > 5 && x < 10     //等於(x > 5) && (x < 10)

而非運算符則有着比關係運算符更高的優先級:

!x < 5  //等於(!x) < 5

另外,與運算符優先級比或運算符更高。故有:

x > 5 || x < 1 && y == 10 //等於x > 5 || (x < 1 && y == 10)

可選擇的替代

不是所有鍵盤都有||或&&這種符號,所以C++提供了可選擇的替代。那就是用"and"、"or"和"not"代替“&&”、“||”和“!”。這三個詞是C++的保留字,也就是你不能用着三個詞作爲變量名。


字符方法庫cctype

C++從C繼承了關於字符的方法庫,方法原型都定義在cctype頭文件中。方法表如下:

cctype字符方法
方法名 返回值
isalnum() 如果參數是一個數字或一個字母,返回true
isalpha() 如果參數是一個字母,返回true
isblank() 如果參數是一個空格或一個水平縮進,返回true
iscntrl() 如果參數是一個ctrl字符,返回true
isdigit() 如果參數是一個十進制數字(0-9),返回true
isgraph() 如果參數是一個除空格以外的打印字符,返回true
islower() 如果參數是一個小寫字母,返回true
isprint() 如果參數是一個包括空格在內的打印字符,返回true
ispunct() 如果參數是一個標點字符,返回true
isspace() 如果參數是一個標準空白格字符(也即是空格、換頁符、換行符、回車、水平縮進、垂直縮進),返回true
isupper() 如果參數是一個大寫字母,返回true
isxdigit() 如果參數是一個十六進制數字(0-9,a-f或A-F),返回true
tolower() 如果參數是一個大寫字母,返回對應的小寫字母。否則,原樣返回
toupper() 如果參數是一個小寫字母,返回對應的大寫字母。否則,原樣返回

問號表達式

問號表達式常用與代替if else語句。格式:

expression1 ? expression2 : expression3

如果第一個表達式的值爲true,則整個問號表達式的值和第二個表達式的值相同。否則問號表達式的值等於第三個表達式。例:

5 > 3 ? 10 : 1 //表達式值爲10
5 < 3 ? 10 : 1 //表達式值爲1

switch語句

格式:

switch(integer-expression)
{
    case label1: statement(s)
    case label2: statement(s)
    case label3: statement(s)
    ...
    default: statement(s)
}

switch語句用於指出程序跳轉位置。當執行switch語句時,程序會跳轉到與整數表達式的值相對應的標籤的行。比如integer-expression的值是4,程序就會跳轉到case 4的一行。整數表達式必須是值爲整數的表達式,而標籤則必須是整數常量表達式。一般來說,標籤都是簡單的int或char常量,比如1或者'q',或者枚舉類型。如果整數表達式的值找不到相匹配的標籤,那麼程序就會跳轉到default標籤。default標籤是可選的。如果沒有default標籤,沒有匹配標籤的情況下程序就會直接跳轉到switch語句的結束。

C++的switch裏的標籤僅僅是一個行標籤,而不是一個邊界。也就是當程序跳轉到一個標籤後,程序會從該標籤一直執行到switch最後一行,而不是執行到下一個標籤停止。如果要程序在特定的位置退出switch,就需要用到break語句。


break和continue語句

break和continue允許程序跳過部分代碼。break可以用在switch或者任意循環中,它會讓程序跳轉到switch或循環之後的下一條語句。而continue可以用在循環中,它會讓程序跳過當前循環的剩餘循環體,直接開始下一個循環。


讀數循環

比方說程序要讓用戶輸入一串數字,並讓用戶決定何時結束。一種方法是使用cin的特性。看如下代碼:

int n;
cin >> n;

當用戶輸入的不是數字,發生不適配情況,將會出現下列四個狀況:

  1. n的值不變;
  2. 不適配的輸入留在輸入隊列中;
  3. cin對象報error;
  4. 對cin方法的調用,如果被轉爲bool,則返回false。

返回false意味着你可以用非數字輸入來終止讀數循環。看以下示例:

#include <iostream>
int main()
{
    using namespace std; 
    int counts = 10;
    int a[counts];
    int i = 0;
    while (i < counts&&cin >> a[i]){
    	cout << "a[" << i << "]:" << a[i++] << endl;
    }
}

注意while循環的測試。左邊表達式是限制輸入數量。當左側表達式值爲false,代表數組已滿,程序就不會執行右側表達式,防止數組越界情況出現。而右側表達式從cin讀入數字並賦值給數組對應位置,然後返回是否賦值成功。如果輸入不是數字,右側表達式值爲false,退出while循環。

注意上面的程序在非數字輸入後就不再讀入了,所以沒有出現問題。但實際在上文說過,非數字輸入會被留在輸入隊列中,且cin對象會報error。如果在這之後要繼續從鍵盤讀入,就要用cin.clear()重置cin對象讓其可以接收新的輸入,然後通過空置讀入將留在輸入隊列中的不適配輸入讀出來丟棄。


簡單文件輸入輸出

C++的文件輸入輸出和已經講過的鍵盤輸入輸出非常相近。17章將會更詳細地講解。

文本輸入輸出和文本文件

當使用cin進行輸入時,程序將輸入視爲一系列的byte,每個byte是一個字符。無論最終目標的讀入數據類型是什麼,輸入最開始都是讀入爲文本數據。然後cin對象會把文本翻譯爲其他類型。以下是對於同樣輸入不同代碼的處理方式。

比如輸入是:

38.5 19.2

對於代碼:

char ch;

cin >> ch;

程序會讀入第一個字符,並賦值給ch。對於上述輸入,程序會讀入數字3,然後將字符'3'賦值給ch。(注意ch的值不是3,而是字符3的字符碼)

而對於代碼:

int n;

cin >> n;

這個情況下,cin會一直讀到第一個非數字字符,也就是讀入一個3,,再讀入一個8,把小數點留在輸入隊列中。然後cin算出兩個字符對應的數值爲38.然後值38被複制給n。

然後對於代碼:

double x;

cin >> x;

這個情況下,cin會一直讀到第一個不是浮點數部分的字符。也就是讀入一個3,一個8,一個小數點,一個5,然後把空格留在讀入隊列中。然後cin算出對應的數值爲38.5,然後38.5的值被複制給x。

接下來是字符數組:

char c[50];

cin >> c;

這個情況下,cin一直讀到空白格字符。也就是讀一個3,一個8,一個小數點,一個5,把空格留在輸入隊列中。然後cin逐個字符將輸入存入字符數組中並在末尾加上空字符。

最後是變種的字符數組讀入:

char c[50];

cin.getline(c, 50);

這個情況下,cin一直讀到換行符(因爲示例輸入長度小於讀入長度上限)。一整行的字符都會被讀入並存入字符數組,最後再加上空字符。換行符將被丟棄,讀入隊列中的第一位是下一行的首個字符。

對於輸出,就會出現與上述過程對應的反向轉換。

寫入文本文件

輸出到文件,C++使用了類似的cout。先來看看用cout對控制檯輸出需要做的準備。

  • 引用iostream頭文件
  • iostream頭文件定義了一個ostream類用於處理輸出;
  • iostream頭文件聲明瞭一個ostream變量,或對象,叫cout;
  • 使用std命名空間;
  • 使用cout對象通過<<操作符輸出。

而輸出到文件則非常相近:

  • 引用fstream頭文件
  • fstream頭文件定義了一個ofstream類用於處理輸出;
  • 程序要聲明一個或多個ofstream變量或對象,自由命名,當然要遵守常規命名規則;
  • 使用std命名空間
  • 將特定ofstream對象與特定文件關聯,一個辦法是使用open()方法
  • 使用ofstream對象通過<<操作符進行輸出

示例程序:

#include <fstream>
int main()
{
	using namespace std; 
    ofstream of;
    of.open("a.txt");
    
    of << "hello world" << endl;
    
    of.close();
}

從文本文件讀入

同樣,先看從控制檯讀入的必要準備:

  • 引用iostream頭文件
  • iostream頭文件定義了istream類用於處理輸入
  • iostream頭文件聲明瞭一個istream變量或對象,稱爲cin
  • 使用std命名空間
  • 可以使用cin通過>>操作符讀入
  • 可以使用cin通過get方法讀入單個字符,還有通過getline方法讀入一整行字符
  • 可以使用cin通過eof()方法和fail()方法來顯示讀入請求是否成功
  • 當cin自身作爲測試變量,它的返回值會轉爲布爾值,讀入成功就返回true,否則返回false

文件讀入是相近的:

  • 應用fstream頭文件
  • fstream頭文件定義了ifstream類用於處理輸入
  • 程序要聲明一個或多個ifstream變量或對象,自由命名,但要遵循常規命名規則
  • 使用std命名空間
  • 將特定ifstream對象和特定文件關聯,可以使用open()方法達成
  • 當完成對文件的讀入後,使用close方法關閉文件
  • 可以使用ifstream對象通過>>操作符讀入數據
  • 可以使用ifstream對象通過get方法滴入單個字符和通過getline方法讀入一整行字符
  • 可以使用ifstream對象通過eof方法和fail方法顯示讀入請求是否成功
  • ifstream對象本身作爲測試變量會返回布爾值作爲讀入是否成功的結果

示例程序:

#include <fstream>
#include <iostream>
int main()
{
	using namespace std; 
    ifstream ifs;
    ifs.open("a.txt");
    char ch[50];
    ifs.getline(ch, 50);
    cout << ch;
}

總結

C++提供了if語句,if else語句,switch語句來進行選擇管理。

C++還提供了操作符來幫助做選擇。第五章討論了關係表達式,用於比較兩個值。if和if else語句一般用關係表達式作爲測試。使用邏輯運算符(&&,||,!)可以組合或修改關係表達式來實現更多樣的測試。

問號表達式提供了一種更簡潔的二選一的方式。

cctype庫提供了多種關於字符操作的方法。

循環和選擇語句是進行文件輸入輸出的有效工具。文件輸入輸出與控制檯輸入輸出非常相近。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章