C++濃縮(一)

四、複合類型:

* 複合類型(類除外)
* new和delete以及如何使用它們來管理數據
* string類(另外一種處理字符串的途徑)ios

4.1 數組

聲明數組的通用格式是:git

arrayType arrayName[arraySize]

arraySize必須是可知數據,可使用 new 運算符來避開這種限制;程序員

【注:】express

一、編譯器不會檢查使用的下標是否有效。若對無效的下標進行賦值,編譯器不會指出錯誤。
但程序運行後,賦值可能引起問題,它可能破壞數據或代碼,也可能致使程序異常終止。so,必須確保只使用有效的下標值。編程

二、數組

sizeof是返回類型或者數據對象的長度(單位:字節);
若是sizeof用於數組名,獲得的是整個數組的字節數;
若是用於數組元素,獲得是元素的長度(單位:字節);函數

數組初始化的規則:工具

1. 只有在定義數組時能夠初始化;然而,可使用下標的方式來進行賦值;
2. 若是沒有對定義的數組進行初始化,則元素的值是不肯定的,意味着元素的值爲之前駐留在該內存單元中的值;
3. 初始化時,若僅對一部分元素進行賦值,則其餘的元素值爲0;
4. 所以將數組中全部元素的值賦值爲0,僅須要arrayName[500] = {0};
5. 若是初始化數組時,[]內的值爲空,那麼編譯器將計算元素個數;測試

4.2 字符串編碼

C++處理字符串的兩種方式:

* C-風格字符串;
* string類;

1、C-風格字符串:

C-風格字符串有一個特殊的規則:以空字符串結尾,空字符串被寫做\0,其ASCII碼值爲0,用來標記字符串的結尾。

char dog[8] = {'b', 'e', 'a', 'u', 'x', '', 'I', 'i'};
char cat[8] = {'f', 'a', 't', 'e', 's', 's', 'a', '\0'};//只有這個是字符串

C++有不少字符串處理函數,好比cout,它們逐個處理字符串中的字符,直至遇到空字符
cout顯示cat將顯示7個字符,遇到空字符串結束;
cout顯示dog顯示8個字符,並接着講內存中隨後各個字節解釋爲要打印的字符,直至遇到空字符結束

so,不該將不是字符串的char數組看成字符串來處理。

一種更好的方法,將字符數組初始化爲字符串-這種字符串稱爲字符串常量或字符串字面值;

char birds[11] = "Mr. Cheeps";
char fish[] = "Bubbles";

這種初始化字符串的方式將隱式包含空字符串。

另外,各類C++輸入工具經過鍵盤輸入,將字符串都入到char數組時,將自動加上空字符做爲結尾;
固然,應當確保數組足夠大,可以存儲字符串的全部字符-包括空字符;
讓數組比字符串長沒有什麼害處, 只是會浪費一些空間,由於字符串的函數根據空字符串的位置[遇到空字符則中止處理],而不是數組長度進行處理。

注:不能將'S' 和 "S"互換:
'S'是字符常量,是83的另外一種寫法,是字符串編碼的簡寫表示。
"S"是字符串常量,表明字符S和\0組成的字符串,另外,「S」實際上表示的是字符串所在的內存地址。

4.2.1 拼接字符串常量

任何兩個由空白(空格、製表符和換行符)分隔的字符串常量將自動拼接成一個。【拼接時不會在被鏈接的字符串之間添加空格】

4.2.2 在數組中使用字符串

將字符串存儲在數組中,兩種方法:

* 將數組初始化爲字符串常量
* 將鍵盤或者文件都入到數組中,經過cin

char name1[15] = "Basicman" ;
char name2[15] = "C++owboy";
strlen(name1);
sizeof(name1);

sizeof指出整個數組的長度:15個字符;strlen返回存儲在數組中的字符串的長度:8(strlen只計算可見的字符,而不把空字符計算在內),但數組長度須要strlen()+1;
另外,對於name2,若執行該操做,name2[3]='\0';這使得該字符串在第3個字符的時候即結束,雖然數組中還有其餘的字符。

4.2.3 字符串輸入

#include<iostream>
int main() {
    using namespace std;
    const int ArySize = 20;
    char name[ArySize];
    char dessert[ArySize];
    cout << "Enter your name:\n";
    cin >> name;
    cout << "Enter your favorite dessert:\n";
    cin >> dessert;
    cout << "I have some desicious dessert " << dessert ;
    cout << " for you " << name << endl;
    return 0;
}

具體輸出狀況是:

Enter your name:
Jason Yang
Enter your favorite dessert:
I have some desicious dessert Yang for you Jason

因爲不能經過鍵盤輸入空字符串\0,所以cin使用空白(空格、換行符或製表符)來肯定字符串的結束位置。這意味着cin在獲取字符數組輸入時只讀取一個單詞。讀取該單詞以後,cin將該單詞放入數組中,並自動添加空字符。這樣實際結果是,cin吧Jason做爲第一個字符,並將它放到name中,把Yang放到輸入隊列中。當cin在輸入隊列中搜索甜點時,發現了Yang,所以讀取Yang,將Yang放入到數組dessert中。

另外一個問題是,輸入字符串的長度可能大於目標數組長度,那麼,該怎麼辦呢?這須要使用cin的更高級特性。在17章進行介紹。

4.2.4 每次讀取一行字符串輸入

面向行的輸入:

* cin類的getline
* cin類的get

getline丟棄換行符,get將換行符放入到輸入隊列中;

一、面向行的輸入:getline()

經過回車輸入的換行符來肯定字符串的結束;

* 有兩個參數,第一個參數表示要輸入的數組名稱,第二個參數代碼要輸入的字符串的長度;
* 若是參數爲20,則該函數僅接受19個字符,剩餘的一個字符用來存儲在結尾處自動添加的空字符;
* getline在讀取指定數目的字符或者遇到換行符的時候中止;

二、面向行的輸入:get()

使用方式與getline相同,不一樣點:get讀取換行符並保留在輸入隊列中。

cin.get(name, ArSize);
cin.get(dessert, ArSize);

第一次調用,將換行符留在輸入隊列中,所以第二次調用看的到第一個字符就是換行符,且認爲已經達到行尾。

get有一種變體,cin.get()可讀取下一個字符(即便是換行符)。

cin.get(name, ArSize);
cin.get();
cin.get(dessert, ArSize);

另外一種使用get的方式是將兩個類成員函數鏈接起來:

cin.get(name, ArSize).get();

由於cin.get(name, ArSize)返回一個cin對象;

下面的語句將輸入的兩行語句分別讀入到數組name和dessert中。

cin.getline(name, ArSize).getline(dessert, ArSize);

三、爲何使用get而不是getline呢?

* 由於老式實現沒有getline;
* 怎麼肯定中止讀取的緣由是由於換行符或者是數組已經滿了呢?查看下一個輸入符,若是是換行符,說明已經讀取了整行;若是不是換行符說明數組已經滿了,該行還有其餘的輸入。

4.2.5 混合輸入字符串和數字

#include<iostream>
int main() {
    using namespace std;
    cout << "Enter the year:" << endl;
    int year;
    cin >> year;
    cout << "Enter the address: \n";
    char address[80];
    cin.getline(address, 80);
    cout << "year: " << year << endl;
    cout << "address: " << address << endl;
    return 0;
}

運行結果是:

Enter the year:
2000
Enter the address:
year: 2000
address:

用戶根本沒有輸入地址的機會,由於cin讀取年份時,將回車鍵生成的換行符放在了輸入隊列中。cin.getline看到換行符後,認爲是一個空行,將空字符串賦值給address。

解決方法:丟棄換行符。

方法:
* 沒有任何參數的cin.get()
* 使用一個char參數的cin.get(ch);

C++ 一般使用指針而不是數組來處理字符串。咱們再介紹指針以後,在介紹字符串方面的特性。

下面介紹一種新的字符串處理方式:string類。

4.3 String類介紹

要使用string類,必須包含頭文件string,string類位於命名空間std中。須要添加using編譯指令;

string類與使用數組字符串有不少類似之處:
* 可使用C-字符串風格來初始化string對象
* 可使用cin將鍵盤輸入存儲到string對象
* 可使用cout來顯示string對象
* 可使用數組表示法來訪問存儲在string對象中的字符

string對象與數組字符串的主要區別就是:
能夠將string聲明爲簡單變量;
類設計讓程序自動處理string的大小;

4.3.2 賦值、拼接和附加

能夠將一個string對象的值賦值給另外一個string對象;可使用+將兩個字符串鏈接起來,可使用+=將字符串附加到string對象的末尾;

4.3.3 string類的其餘操做

在有string類以前,對於C-風格字符串,使用C語言庫中的函數來完成,頭文件ctring提供了這些函數。

eg:

* strcpy()將字符串賦值到字符數組
* strcat()將字符串附加到字符數組中

不一樣之處:

賦值:

* string,賦值操做:str2 = str1;
* C-風格字符換,賦值操做:strcpy(ch2, ch1);

附加:

* string,附加操做:str2 += " Boy";
* C-風格字符串,附加操做:strcat(ch2, " Girl");

另外,使用字符數組,老是存在目標數組長度太小,沒法存儲指定信息的危險。

函數strcat若是試圖將所有12個字符複製到數組site中,這將覆蓋相鄰的內存。這可能致使程序種植,或者程序繼續運行,但數據被損壞。

string具備自動調節大小的功能。

獲取長度:

* strlen(ch2)
* str2.size()

4.3.4 string類I/O

* 使用cin >> 將輸入存儲到string對象中
* 使用cout << 顯示string對象

其句法與C-風格字符串類似。但每次讀取一行而不是一個單詞時,使用的句法不一樣。

* cin.getline(charr, 20);
* getline(cin, strr);

代碼以下:

#include<iostream>
#include<string>
#include<cstring>
int main() {
    using namespace std;
    char charr[20];
    string strr;
    cout << "the length of charr is: " << strlen(charr) << endl;
    cout << "the length of strr is: " << strr.size() << endl;   

    cout << "Enter the charr: " << endl;
    cin.getline(charr, 20);

    cout << "Enter the strr: " << endl;

    getline(cin, strr);

    cout << "the length of charr is: " << strlen(charr) << endl;
    cout << "the length of strr is: " << strr.size() << endl;   

    return 0;
}

運行結果以下:

1. 未初始化的數組內容是未定義的;其次,strlen從數組的第一個元素開始計算字節數,直至遇到空字符;

2. 未初始化的string對象長度自動被設置爲0;

3. C-風格字符串getline用法,cin.getline(charr, 20);

4. string getline用法,getline(cin, strr); 代表getline不是類方法,將cin做爲參數,指出要到哪裏查找輸入,未指定長度,string對象會自動調整大小;

問題:爲什麼一個getline是類方法,一個不是呢?

4.4 結構簡介

結構:用戶定義類型,能夠存儲多種類型的數據。

使用:

1. 定義結構描述--描述標記可以存儲在結構中的各類數據類型

2. 按照描述建立結構變量

struct student {
        int age;
        string name;
 };

* 定義結構以後,就能夠建立這種類型的變量了;

* C++ 容許在聲明結構變量時省略struct關鍵字,結構標記的用法和基本類型的用法相同;

* 可使用成員訪問符(.)來訪問成員;

eg:聲明和初始化(逗號分割,並用花括號括起)

student stu1 = {
        24,
        "cql"
  };

4.4.1

定義結構類型的位置很重要:

* 定義在main函數中,內部聲明僅能夠被該聲明所屬的函數使用;

* 放到main的外面,位於函數外面的稱爲外部變量,外部聲明能夠被後面的全部函數訪問;

C++ 也容許定義外部變量,但不提倡聲明外部變量,提倡外部聲明結構,另外,外部聲明符號常量一般更合理。

4.4.3 

C++ 結構體容許將string做爲成員嗎?能夠,只要能夠編譯經過。

4.4.4 其餘結構屬性

* 能夠將結構做爲參數進行傳遞,以及讓函數返回一個結構;

* 使用賦值運算符(=)將結構賦值給另外一個結構,即便結構中包含數組;這種賦值被稱爲成員賦值;

* 能夠同時完成定義結構和聲明結構變量

struct student {
        int age;
        string name;
    } stu1, stu2;

甚至能夠以這種方式既聲明又初始化:

struct student {
        int age;
        string name;
    } stu1 = {
        24,
        "cql"
    };

另外,C++的結構不只僅能夠有成員變量以外,還能夠有成員函數。這點將在類中介紹

4.4.5結構數組

建立元素爲結構的數組;

struct student {
        int age;
        string name;
    } stu1 = {
        24,
        "cql"
    };

初始化結構數組的規則能夠結合初始化數組和初始化結構的規則。

因爲數組中的每一個元素都是結構,所以可使用初始化結構的方式來提供值。最終結果爲一個逗號分割,花括號括起來的列表。

4.5 共用體

一種數據格式,能夠存儲多個不一樣的數據類型,但同時只能存儲其中的一種。

union one4all {
int int_val;
double double_val;
string string_val;
};

one4all能夠存儲int、double、string類型,但條件是在不一樣的時間;

    one4all onetest;
    onetest.int_val = 10;
    cout << onetest.int_val << endl;
    onetest.double_val = 13.8; (int_val has lost)
    cout << onetest.double_val << endl;

因爲共用體能夠每次只可能存儲一個值,所以它必須有足夠的空間來存儲最大的成員。因此,共用體的最大程度爲其最大成員的長度。

4.6 枚舉

。。。。。。

4.7指針和自由存儲空間

計算機在存儲數據時必須跟蹤的3種基本屬性;

* 信息存儲在何處;

* 存儲的值是多少;

* 存儲的信息類型;

實現上述策略的方法:

* 定義一個簡單變量

* 使用指針

 

* 指針是一種變量,存儲的是值的地址,而不是值自己;

* 獲取常規變量的地址方法:使用地址運算符&

* 使用常規變量時,值是指定的量,而地址是派生量

* 使用指針時,地址是指定的量,而值是派生量

* *運算符,將其應用於指針,能夠獲得該地址處存儲的值

指針策略(C++ 內存管理編程理念的核心):

int updates = 6;
int * p_updates;
p_updates = &updates;
cout << "the value of updates is: " << updates << endl;
cout << ", *p_updates is: " << *p_updates << endl;
cout << "the address of updates is: " << &updates << endl; 
cout << ", p_updates is: " << p_updates << endl;
*p_updates = *p_updates + 1;
cout << "the value of updates is: " << updates << endl;

其實,p_updates和updates只不過是硬幣的正反面:

* p_updates表示地址,使用*可得到值;

* updates表示值,使用&可得到地址;

因爲p_updates指向updates,所以,*p_updates和updates是等價的,能夠像使用int變量那樣使用*p_updates,甚至能夠賦值給*p_updates,這樣將修改指向的值,即updates;

4.7.1 聲明和初始化指針

計算機須要跟蹤指針指向的值的類型,例如,char與double的地址看上去沒有什麼區別,char和double使用的字節數不一樣,內部表示格式也不一樣,所以,在聲明指針時,須要指明指針指向的數據的類型。

* int*是一種複合類型,是指向int的指針

聲明方式以下均可以:

* int *ptr
* int* ptr
* int*prt
* int * ptr

使用一樣的語法來聲明其餘類型的指針變量:

char * char_ptr;
double * dou_prt;

雖然char_ptr和 dou_prt指向兩種長度不一樣的數據類型,可是這兩個變量自己的長度一般是相同的。

地址須要2個字節仍是4個字節(取決於具體的計算機系統)(有些系統可能須要更大的地址,系統能夠針對不一樣類型使用不一樣長度的地址)。

4.7.2 指針的危險

C++在建立指針時,將分配用來存儲地址的內存,但不會分配用來存儲地址指向的值得內存。

int * fellow;

*fellow = 223344;

fellow指向哪裏呢?並無將地址賦值給fellow,那麼223344將放在哪裏呢?

因爲fellow沒有被初始化,它裏面可能有任何值,無論是什麼,都將它解釋爲存儲223344的地址。

好比,fellow碰巧值爲1200,那麼1200存儲的值就是223344,即便恰巧1200存儲的是代碼的地址。

so,警告:必定要在指針使用*運算符以前,將指針初始化爲一個肯定的、適當的地址。

4.7.3 指針的數字

4.7.4 使用new來分配內存

4.7.5 使用delete釋放內存

4.7.6 使用new來建立動態數組

。。。。。。。。。。

5

5.1 for循環

5.1.1 for循環的組成部分

其中注意,測試表達式的值不必定爲true或者false,可使用任意表達式,C++將把結果強制轉換成true或者false;

若爲0,爲false;若非零,爲true;

C++程序會在須要整數值的時候將true和false轉換爲1和0,在須要bool值的地方將0和非零轉換成false和true;

一、表達式和語句

(任何值)或者(任何有效的值和運算符的組合)都是表達式;每一個表達式都有值

eg:十、22+2七、x=22;x=22這個表達式的值爲22;

x = y = z = 0;(賦值運算符從右到左執行)

    int x;
    cout << "1: " << (x = 1000) << endl;
    cout << "2: " << (x < 3) <<endl;
    cout << "3: " << (x > 3) <<endl;
    cout.setf(ios::boolalpha);

    cout << "2: " << (x < 3) <<endl;
    cout << "3: " << (x > 3) <<endl;

輸出結果:

一般,cout在現實bool值以前會將他們轉換成int,但cout.setf(ios::boolalpha);函數設置了一個標記,

該標記命令cout顯示true或者false,而不是1或者0;(固然,前提是運算結果是bool)

從表達式到語句的轉換:只須要加上分號便可。

二、非表達式和語句

* 對任何表達式加上分號均可以成爲語句

* 但語句去掉分號並不同是表達式

三、修改規則

5.1.2 回到for循環

5.1.3 改變步長

5.1.4 使用for循環訪問字符串

5.1.5 遞增運算符(++)和遞減運算符(--)

5.1.6 反作用和順序點

5.1.7 前綴和後綴格式

前綴和後綴對執行速度有細微的差異;

* 前綴是將值加1,返回結果;

* 後綴首先複製一個副本,將值加1,返回副本;

相比而言,前綴效率比後綴效率高;

5.1.8 遞增\遞減運算符和指針

將*和++同時用於指針;怎麼處理,取決於運算符的位置和優先級。

* 前綴遞增、前綴遞減和*優先級相同;從右到左的方式進行結合;

* 後綴遞增、後綴遞減的優先級比前綴運算符的優先級高;從左到右的方式進行結合;

int age[10] = {10, 20, 30, 40, 50};
int *p;
p = age;
cout << *p << endl;
*p++;// 將p的地址+1,而後獲取值,age[1] 
cout << *p << endl;
++*p;// 獲取age[1]的值,而後+1
cout << *p << endl;

注意:

指針遞增和遞減遵循指針算數規則。所以,若是p指向數組的第一個元素,++p將修改p,使之指向第二個元素。

5.1.9 組合賦值運算符

-= += *=  /= %=

5.1.10 複合語句(語句塊)

多條語句使用花括號括起來;

* 複合語句有一個有趣的特性,語句塊中定義一個新的變量,則當程序執行該語句塊中的語句時,該變量才存在。

執行完該語句塊,變量將被釋放。這代表此變量僅在該語句塊中才是有用的。

* 若語句塊中聲明一個變量,外部聲明也有一個重名的變量,該怎麼處理呢?

* 在聲明位置到內部語句塊結束的範圍以內,新變量隱藏舊變量

5.1.11 其餘語法技巧---逗號運算符

逗號運算符容許將兩個表達式放到只容許放一個表達式的地方。

    string word;
    char temp;
    cin >> word;
    for (int i = 0, j = (word.size()-1); i < j; i++, j--) {
        temp = word[i];
        word[i] = word[j];
        word[j] = temp;
    }
    cout << word << endl;

到目前爲止,逗號運算符最多見的用途是將兩個或者更多的表達式放到一個for循環表達式中。

另外,

* 逗號運算符先計算第一個表達式,在計算第二個表達式

    int m, n, p;
    p = (m = 2, n = 2 * m);
    cout << p << endl;

* 其次,逗號表達式的值是第二部分的值,如上,值爲4;

* 逗號運算符的優先級是最低的;

5.1.12 關係表達式

C++提供了6種關係運算符來對數字進行比較。因爲字符用其ASCII碼錶示,所以也能夠進行關係比較。

不能將它們用於C-風格字符串,但能夠用於string類對象。

< <= == >  >= !=

5.1.13 賦值、比較和可能犯的錯誤

使用=賦值,使用==比較

5.1.14 C-風格字符串比較

假設要知道字符數組中的字符串是否是mate,word是數組名。

word="mate"

注:數組名是數組的地址,字符串常量"mate"也是其地址。這就是判斷兩個字符串是否存儲在相同地址上

使用strcmp()函數。

接受兩個字符串地址做爲參數,意味着參數能夠是指針、字符串常量或者字符數組名。

若兩個字符串相同,返回0;

若第一個字符串按字母排序排在第二個字符串以前,返回負值;

若第一個字符串按字母排序排在第二個字符串以後,返回正值;

實際上,按「系統排列順序」比按「字母排列順序」更準確。這意味着字符是根據字符的系統編碼來比較的。

C-風格字符串經過空字符來定義,而不是其所在數組的長度。這意味着,即便兩個字符串被存儲在不一樣長度的數組中,也多是相同的。

雖然不能使用關係運算符來比較字符串,但卻能夠來比較字符,由於字符實際上就是整型。

5.1.15 比較string類字符串

類設計可以使用關係運算符進行比較。

之因此可行,是由於類函數重載了這些運算符。具體在12章介紹。

string類重載運算符!=使用條件:至少有一個操做數爲string對象,另外一個操做數能夠是string對象或者C-風格字符串。

5.2 while循環

5.2.1 for 與while循環

5.2.2 等待一段時間,編寫延時循環

。。。。

5.3 do和while循環

5.4 基於範圍的for循環(C++11)

5.5 循環和文本輸入

cin對象支持3中不一樣模式的單字符輸入,其用戶接口各不相同

5.5.1 使用原始的cin進行輸入

cin忽略空格和換行符

    char a;
    int count = 0;
    cin >> a;
    while(a != '#'){
        count++;
        cin >> a;
    }
    cout << count << endl;

5.5.2 使用cin.get(char)進行補救

可以讀取包括空格、製表符和換行符;

若是熟悉C語言,可能覺得這個程序存在嚴重的錯誤。

cin.get(ch)調用將一個值放到ch邊兩種,意味着改變該變量的值。

C語言中,要修改變量的值,必須將變量的地址傳遞給函數。

但cin.get(ch),傳遞的是ch,而不是&ch。在C語言中,這樣的代碼無效,但在C++中,這樣的代碼有效。

只要函數將參數聲明爲引用便可。第8張介紹。

另外,一般,在C++中傳遞的參數的工做方式與C語言相同。而後,cin.get(ch)並非這樣;

    char a;
    int count = 0;
    cin.get(a);
    while(a != '#'){
        count++;
        cin.get(a);
    }
    cout << count << endl;

5.5.3 使用哪個cin.get()

cin.get()的三種使用方法:

    cin.get(arrayName, arraySize);
    cin.get();
    cin.get(ch);

函數重載,函數重載容許建立多個同名函數,條件式參數列表不一樣;

函數以不一樣的方式或針對不一樣類型執行相同的任務;

5.5.4 文件尾條件

。。。。。。。。。。。

5.6 嵌套循環和二維數組

5.6.1 初始化二維數組

5.6.2 使用二維數組

在此,僅介紹下聲明城市數組的集中方式;

char 指針

   const char * cities[5] = {
        "Beijing",
        "Shanghai",
        "Henan",
        "Tianjin",
        "Ganchazhuang"
    };
    cout << cities[0] << endl;

char數組的數組:

    const char cities[5][25] = {
        "Beijing",
        "Shanghai",
        "Henan",
        "Tianjin",
        "Ganchazhuang"
    };
    cout << cities[0] << endl;

string對象數組:

 const string cities[5] = {
        "Beijing",
        "Shanghai",
        "Henan",
        "Tianjin",
        "Ganchazhuang"
    };
    cout << cities[0] << endl;

6 分支語句與邏輯運算符

* 條件運算符;

* 邏輯運算符;

* 文件輸入\輸出;

6.1 if語句

和循環測試條件同樣,if測試條件也被將值轉換爲bool值,所以0將被轉換爲false,非零爲true。

6.1.1 if else 語句

6.1.2 格式化if else語句

對多條語句添加大括號;

6.1.3 if else if else 結構

6.2 邏輯表達式

邏輯OR || 邏輯AND && 邏輯NOT !

6.2.1 邏輯OR ||

    char yourchoice;
    cout << "Enter your choice: " << endl;
    cin >> yourchoice;
    if (yourchoice == 'Y' || yourchoice == 'y')
        cout << "you choose" << endl;
    else if (yourchoice == 'N' || yourchoice == 'n')
        cout << "you don't choose'" << endl;
    else
        cout << "no choice" << endl;

因爲程序只讀取一個字符,所以只讀取響應的第一個字符。意味着用戶能夠用NO進行回答,程序只讀取N.

然而,若是程序後面再讀取輸入時,將從O開始讀取,O已經進入的輸入隊列了。

6.2.2 邏輯AND &&

char * ch_ptr = "my god";
cout << ch_ptr << endl;

程序正常運行,但該方式不建議使用,已經被棄用

6.2.3 用&&來設置取值範圍

6.2.4 邏輯NOT運算符!

6.2.5 邏輯運算符細節

邏輯OR和邏輯AND運算符優先級 < 關係運算符

!運算符優先級> 全部關係運算符和算術運算符>邏輯OR和邏輯AND

6.2.6 其餘表示方式

* C++ 可用and 、or 和not;

* C可用and、or和not,前提:包含頭文件iso646.h

6.3 字符函數庫cctype

cctype:與字符相關的、方面的函數軟件包;

函數名稱返回值isalnum()若是參數是字母數字,即字母或數字,該函數返回trueisalpha()若是參數是字母,該函數返回真isblank()若是參數是空格或水平製表符,該函數返回trueiscntrl()若是參數是控制字符,該函數返回trueisdigit()若是參數是數字(0~9),該函數返回trueisgraph()若是參數是除空格以外的打印字符,該函數返回trueislower()若是參數是小寫字母,該函數返回trueisprint()若是參數是打印字符(包括空格),該函數返回trueispunct()若是參數是標點符號,該函數返回trueisspace()若是參數是標準空白字符,如空格、進紙、換行符、回車

、水平製表符或者垂直製表符,該函數返回true

isupper()若是參數是大寫字母,該函數返回trueisxdigit()若是參數是十六進制的數字,即0~九、a~f、A~F,該函數返回truetolower()若是參數是大寫字符,則返回其小寫,不然返回該參數toupper()

若是參數是小寫字母,則返回其大寫,不然返回該參數

什麼是控制字符?

什麼是打印字符?

6.4 ?:運算符

6.5 switch語句

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

integer-expression必須是一個結果爲整數值的表達式。

每一個標籤都必須是整數常量表達式。

最多見的標籤是int或char常量、枚舉量。

6.5.1 將枚舉量用做標籤

cin沒法識別枚舉類型(它不知道程序員是如何定義他們的)。所以要求用戶輸入一個整數。

當switch語句將int值和枚舉量標籤進行比較時,將枚舉量提高爲int。

另外,在while循環測試條件中,也會將枚舉量提高爲int類型。

enum {red, green};
    int code;
    cin >> code;
    while(code >= red && code <= black) {
        switch(code){
            case red:
                cout << "oh,red." << endl;
                break;
            case green:
                cout << "oh,green." << endl;
                break;   
        }
        cin >> code;
    }

6.5.2 switch 和 if else

switch和if else相比,if else更通用。

switch的每一個case標籤值必須是單獨的值且必須是整數(包括char)。

6.6 break和continue語句

6.7 讀取數字的循環

假設要編寫一個將一系列數字讀入到數組中的程序,並容許用戶在數組填滿以前結束輸入。

若是用戶輸入一個單詞,而不是一個數字,狀況將如何呢?發生這種類型不匹配的狀況時,將發生4中狀況:

* n值保持不變;

* 不匹配的輸入將被留在輸入隊列中;

* cin對象中的一個錯誤標記被設置;

* 對cin方法的調用將返回false(若是被轉換爲bool類型);

方法返回false意味着能夠用非數字輸入來結束讀取數字的循環。

非數字輸入設置錯誤標記意味着必須重置該標記,程序才能繼續讀取輸入。clear方法重置錯誤輸入標記,同時也重置文件尾(EOF條件)。輸入錯誤和EOF都將致使cin返回false。

   while(i < MAX && cin >> fishes[i]){
        cout << fishes[i] << endl;
        i++;
    }
    cin >> fishes[i] ;

是一個cin方法函數調用,該方法返回cin。若是cin位於測試條件中,則將被轉換爲bool類型。

若是輸入成功,則轉換後的值爲true,不然爲false。

當用戶輸入的不是數字時,該程序再也不讀取輸入。

可使用cin輸入表達式的值來檢測輸入是否是數字。程序發現用戶輸入了錯誤內容時,應採起3個步驟:

1. 重置cin以接受新的輸入

2. 刪除錯誤輸入

3. 提示用戶再輸入

double fishes[MAX];
    int i = 0;
    while(i < MAX){
        while(!(cin >> fishes[i])){
            cin.clear();
            while(cin.get()!='\n')
                continue;
            cout << "error input, please go on: " << endl;
         }
        cout << fishes[i] << endl;
        i++;
    }
    return 0;

6.8 簡單文件輸入/輸出

6.8.1 文件I/O和文本文件

使用cin輸入時,程序將輸入視爲一系列的字節,其中每一個字節都被解釋爲字符編碼。無論目標數據類型是什麼,輸入一開始都是字符數據--文本數據。而後,cin對象負責將文本轉換爲其餘類型。

對於輸出,將執行相反的轉換,即整數被轉換爲數字字符序列,浮點數被轉換爲數字字符和其餘字符組成的字符序列(如284.53或-1.58E+06)。字符數據不須要作任何轉換。

6.8.2 寫入到文本文件中

對於文件輸入,C++ 使用相似於cout的東西。

* 必須包含頭文件iostream

* 頭文件iostream定義了一個用處理輸出的ostream類;

* 頭文件iostream 聲明瞭一個名爲cout的ostream變量(對象)。

* 必須指明命名空間std;

* 能夠結合使用cout和<<來顯示各類類型的數據。

文件輸出與此及其類似。

* 必須包含頭文件fstream

* 頭文件fstream定義了一個用於處理輸出的ofstream類。

* 須要聲明一個或多個ofstream變量(對象)

* 必須指明命名空間std

* 須要將ofstream對象與文件關聯起來,爲此,方法之一是使用open()方法。

* 使用完文件後,應使用方法close()將其關閉

* 可結合ofstream對象和運算符<<來輸出各類類型的數據。

    char filename[20];
    cout << "Enter the filename: " << endl;
    cin >> filename;
    ofstream infile;
    infile.open(filename);
    double test = 12.5;
    infile << test;
    infile.close();

* 重要的是,聲明一個ofstream對象並將其同文件關聯起來後,即可以像使用cout那樣使用它。全部可用於cout的操做和方法(如<< 、 endl和self())均可以用於ofstream對象。

* 另外,close不須要使用文件名做爲參數,由於infile已經同文件關聯起來。若是忘記關閉文件,程序正常終止時將自動關閉它。

* infile可以使用cout可以使用的任何方法。不但能使用<<還可使用各類格式化方法,如self()和precision(),這些方法隻影響調用它們的對象。

* open(),若文件不存在,將新建;若文件已經存在,丟棄原有內容,重寫文件。

6.8.3 讀取文本文件

接下來介紹文本文件輸入,它是基於控制檯輸入的,控制檯輸入涉及多個方面:

* 必須包含頭文件iostream

* 頭文件iostream定義了一個用於處理輸入的istream類

* 頭文件iostream聲明瞭一個名爲cin的istream對象

* 必須指明命名空間std

* 結合使用cin和>>來讀取各類類型的數據

* 可使用cin和get()方法讀取一個字符,使用cin和getline()來讀取一行字符

* 能夠結合使用cin和eof() fail() 方法來判斷輸入是否成功

* 對象cin自己被用做測試條件時,若是最後一個讀取操做成功,它將被轉換爲布爾值true,不然被轉換爲false

文件輸出與此及其類似:

* 必須包含頭文件fstream

* 頭文件fstream定義了一個用於處理輸入的ifstream類。

* 須要聲明一個或多個ifstream對象

* 必須指明命名空間std

* 須要將ifstream與文件關聯起來,方法之一使用open()方法

* 使用完文件後,使用close()方法將其關閉

* 可結合使用ifstream對象和get()方法來讀取一個字符,使用ifstream對象和getline()來讀取一行字符。

* 能夠結合使用ifstream和eof()、fail()等方法來判斷輸入是否成功

* ifstream對象自己被用做測試條件時,若是最後一個讀取操做成功,它將被轉換爲布爾值true,不然被轉換爲false

    ifstream outfile;
    outfile.open(filename);   
    double test;
    outfile >> test;
    char test2[20];
    outfile >> test2;
    cout << test << endl;
    cout << test2 << endl;
    outfile.close();

若是打開一個不存在的文件用於輸入,將致使使用ifstream對象使用輸入時失敗。檢查文件是否成功打開的首先方法就是使用is_open()。

    outfile.open(filename);   
    if (!outfile.is_open())
        exit(EXIT_FAILURE);

若是文件被成功打開,方法is_open()返回true,不然,返回false;

函數exit原型在頭文件cstdlib中定義的,在該頭文件中,還定義了一個用於同操做系統通訊的參數值EXIT_FAILURE。函數exit()終止程序。

is_open是C++相對較新的內容。若是編譯不過,可以使用較老的方法good()來代替。不過,方法good在檢查可能存在的問題方面,沒有is_open()那麼普遍。

    ifstream outfile;
    outfile.open(filename);   
    if (!outfile.is_open())
        exit(EXIT_FAILURE);

    int sum = 0;
    int number;

    outfile >> number;
    while(outfile.good()){
        outfile >> number;   
        sum += number;
    }

    if(outfile.eof()) {
        cout << "eof" << endl;
    } else if (outfile.fail()) {
        cout << "fail" << endl;
    } else {
        cout << "other" << endl;
    }
    outfile.close();

檢查文件是否成功打開相當重要,好比:

* 指定的文件不存在;

* 文件可能位於另外一個目錄中;

* 訪問被拒絕;

* 輸錯了文件名或省略了文件擴展名。

程序讀取文件時不該超過EOF。

* 首先,若是最後一次讀取數據時遇到EOF,方法eof()返回true。

* 其次,程序可能遇到類型不匹配的狀況,方法fail()返回true(若是遇到了EOF,該方法也返回true)。

* 最後,可能出現意外問題,如文件受損或者硬盤故障。

* 若是最後一次讀取文件時放生了這樣的問題,方法bad()將返回true。

不要分別檢查這些狀況,一個更簡單的方法是使用good()方法,該方法在沒有發生任何錯誤時返回true;

若是願意,可使用其餘方法來肯定循環終止的真正緣由:

    if(outfile.eof()) {
        cout << "eof" << endl;
    } else if (outfile.fail()) {
        cout << "fail" << endl;
    } else {
        cout << "other" << endl;
    }

eof()只能判斷是否到達EOF;

fail()能夠檢查是EOF仍是類型不匹配;

方法good()指出最後一次讀取輸入的操做是否成功,這一點相當重要。這意味着在執行讀取輸入的操做後,馬上應用這種測試。爲此,一種標準的方法是,在循環以前放置一條輸入語句,並在循環的末尾放置另外一條輸入語句。

    outfile >> number;
    while(outfile.good()){
        ++count;
        outfile >> number;   
        sum += number;
    }

可對上述語句進行精簡;

表達式outfile>>number的結果爲outfile,而在須要一個bool值得狀況下,outfile的結果爲outfile.good()即,true或者false;

所以,能夠改形成以下:

while(outfile >> number){
        ++count;
        sum += number;
}
相關文章
相關標籤/搜索