《C++Primer》學習筆記(6-10章)

第六章 語句

1. if (int i = 3) // i轉化成bool值true; 迄今爲止,在全部用過的類型中,IO類型能夠用做條件,vector和string類型通常不可用做條件
上面,出了if後,i不可訪問,下面出了while以後一樣不可訪問
while (int i = fun(j)) // 每次循環要執行i的建立和撤銷過程
2. 每一個case不必定非要另起一行
case 1: case 2: case 3: case 4: case 5:
++i;
break;
case值必須是整型常量表達式
有兩個case值相同則編譯錯
良好的程序要定義default: 即便沒有什麼要作的,;空語句也行
switch內部的變量定義:規定只能在最後一個case以後或default以後定義變量,要爲某個case定義變量,那麼要加{}。這樣是爲保證這個變量在使用前被定義一初始化(若直接執行後面case,且用到了這個變量 ,因爲做用域可見,但未定義就使用了)
3. t6_12.cpp 尋找出現次數最多的單詞,要求程序從一個文件中讀入
4. do{}while();以;結束
5. 在設計良好的程序中, 異常是程序錯誤處理的一部分
異常是運行時出現的異常

#include<stdexcept>
try {
if (true)
throwruntime_error(「error!」);
} catch (runtime_error err) {
cout << err.what() << endl;
}

先在當前代碼中找catch,若沒有匹配的,則一上層調用函數中尋找,若仍沒找到,則一直找下去,最終由#include <exception>中定義的terminate終止程序執行

若程序在沒有try catch的地方出現異常,則由terminate自動終止程序的執行

bitset的to_ulong操做,若提供的位數大於unsigned long的長度32位時,就異常overflow_error,查看t6_23

bitset<33> ib;

ib[ib.size()-1] = 1; // 最高位是1

try{

ib.to_ulong();

}catch (overflow_error err) {

cout<< "overflow" << endl;

cout<< err.what() << endl; // what返回const chat*

}catch (runtime_error err) {

cout<< "runtimeerror" << endl;

cout << err.what() << endl;

}

6. 異常類 #include <stdexcept>

exception // 最多見異常類

runtime_error // 下面幾個運行時錯

range_error // 生成的結果超出了有意義的值域範圍

overflow_error // 上溢

underflow_error // 下溢

logic_error // 可在運行前檢測到的問題,下面幾個邏輯錯

domain_error // 參數的結果值不存在

invalid_argument // 不合適的參數

length_error //超出該類型最大長度

out_of_range //使用一個超出有效範圍的值

#include <new>

bad_alloc

#include <type_info>

bad_cast

以上紅色的三個只有默認構造函數,不使用string初始化

7. 使用預處理器編寫調試代碼

#ifndef NDEBUG

cerr << 「oh,shit!」 << endl;

#endif

不少編譯器執行時

$ CC –DNDEBUG main.C

至關於在main.c開頭提供#define NDEBUG預處理命令

8. 預處理宏assert #include <cassert>

assert(expr)與NDEBUG配合使用的

只要NDEBUG沒有定義,則執行assert,若爲false則輸出信息並終止程序的執行

測試不可能發生的條件

異常是處理預期要發生的錯誤,而斷言是測試不可能發生的事情

一旦開發和測試完成,程序就已經創建好,並定義了NDEBUG。成品代碼中,assert不執行,所以沒有運行時代價,沒有運行時檢查。

assert僅用於檢查肯定不可能的條件,只對程序的調試有幫助,不能用來代替運行時的邏輯檢查logic_error,也不能代替對程序可能產生的錯誤runtime_error的檢查

9. 百度百科中:

編寫代碼時,咱們老是會作出一些假設,斷言就是用於在代碼中捕捉這些假設,能夠將斷言看做是異常處理的一種高級形式。斷言表示爲一些布爾表達式,程序員相信在程序中的某個特定點該表達式值爲真。

使用斷言能夠建立更穩定,品質更好且易於除錯的代碼。當須要在一個值爲FALSE時中斷當前操做的話,可使用斷言。單元測試必須使用斷言

除了類型檢查和單元測試外,斷言還提供了一種肯定各類特性是否在程序中獲得維護的極好的方法。

使用斷言使咱們向按契約式設計更近了一步。

我這樣理解,一座橋,有護欄,人們正常行走在上面,

assert(有我的翻越護欄跳進河)

assert(橋斷了) // 這些都是咱們認爲不可能的,假設真的

上面是不可能發生的狀況;

try {

if (護欄壞掉)

} catch(runtime_error err) {

cout << err.what() << endl;

}

while(cin >> s) {

assert(cin); // 多餘的

}

string s;

while(cin >> s && s != sought) {}

assert(cin);

解釋:在打開調試器的狀況下,該循環從標準輸入讀入一系列單詞,直到讀入的單詞與sought相等或遇到文件結束符。若是遇到EOF,則執行assert並終止程序。

若是關閉調試器,則assert不作任何操做

第七章 函數

1. 最大公約數

int a,b;

while (b) {

inttemp = b;

b =a % b;

a =temp;

}

return a;

2. 函數必須指定返回類型

3. 指針形參,不改變實參指針值,但能夠改變它們共同指向的對象

4. 形參使用引用能夠避免複製。有些類不能複製。應該將不須要修改的引用形參定義爲const引用。普通的非const引用形參不能用const對象初始化,也不能用字面值或產生右值的表達式,以及須要進行類型轉換的對象做爲實參初始化,只能與徹底同類型(short給int引用會出錯)的非const對象關聯!

5. void ptrswap(int *&p1, int*&p2) // 傳值(指針值)調用,函數裏面交換兩個指針的值,這樣的話,實參指針也交換了值

6. 何時應該將形參定義爲引用:修改實參,大型對象不能複製,沒法複製的類

7. 一般函數不該該有vector或其餘容器類型的形參,傳遞迭代器就能夠了(模板實現)

8. 數組形參

因爲不能複製數組,因此沒法編寫使用數組類型形參的函數。數組能夠自動轉化成指針 ,因此一般經過操縱指向數組中的元素的指針來處理數組。

如下三個等價:都看做是指向數組元素的指針

void fun(int*)// 最好

void fun(int[]) // ok

void fun(int[10])



數組實參

數組實參若以非引用形式傳遞,則會悄悄的轉成指針,非引用類型的形參會初始化爲相應的的副本,實參是第一個元素的地址,而形參複製的是這個地址的副本,操做的是這個副本,因此不會修改實參指針的值,可是能夠修改它們共同指向的對象內容。

因此,數組非引用實參是指針的值傳遞!

若是不修改數組元素(保護數組)時,那麼應該定義爲指向const對象的指針

void fun(const int*)



數組引用形參

void printValues(int (&arr)[10]) { ...... } // 括號是必須的

這個時候,數組實參不會轉成指針了,而是傳遞數組引用自己

必須寫大小,實參的大小必須與10匹配

t16_16,模板實現,容許傳遞指向任意大小的引用形參


多維數組的傳遞

void printValues(int (*matrix)[23], int rowSize) { .... } void printValues(int matrix[][23], introwSize); // 其實是指針

9. t7_15

#define NDEBUG // 必須放在第一行

#include <iostream>

using namespace std;

//#define NDEBUG // 移到第一行去

int main(int argc, char** argv) {

assert(argc== 33);

cout<< "sum=" << (atof(argv[1]) + atof(argv[2])) <<endl;

system("pause");

return0;

}

10. 非void函數必須返回的特殊狀況,main函數最後的reutn 0不是必須的

main函數不能遞歸,不能調用自身

main函數不能重載

#include<cstdlib>定義了兩個預處理器變量,說明程序執行成功或失敗:

EXIT_FAILURE

EXIT_SUCCESS

11. 函數返回值

返回值用於初始化在調用函數處建立的臨時對象temporary object

若是返回非引用類型,使用局部對象來初始化臨時對象

若是返回引用類型,則不要返回局部對象的引用,

也不要返回局部對象的指針

返回引用的函數:沒有複製返回值,返回的是對象自己

const string &shorterStr(const string&, conststring&);

若是不但願返回的對象被修改,加const(不能做爲左值了)

引用返回左值:返回引用的函數返回一個左值

inlinensaddr_t& pkt_src() { return pkt_src_; }

main函數中:

pkt_src()= 實參值;

若是不但願引用值被修改,返回值應該聲明爲const:

inline cosnt nsaddr_t& pkt_src() { return pkt_src_; }

該引用是被返回元素的同義詞

12. 考題

int &max(int a, int b) { // 返回引用.cpp

returna > b ? a : b;

}

int main() {

inti = 1, j = 2;

max(i,j)= 3;

cout<< "i=" << i << ",j=" << j <<endl; // i=1,j=2

// 由於形參不是引用,不會改變j的值,改變的是局部b的值

system("pause");

return0;

}

13. 函數聲明

變量和函數都聲明在頭文件中,定義在源文件中

源文件包含聲明函數的頭文件,進行匹配檢查

聲明在頭文件中的好處是確保在全部文件中聲明一致,修改方便

14. 默認實參,:若是有一個形參有默認實參,那麼它後面的全部形參都要有

使用最頻繁使用的排在最後

默認實參能夠是表達式或有返回值的函數調用

在頭文件中聲明默認實參(別人包含後纔是有效的),在源文件中定義的時候就不要寫默認實參了,不然出錯,因規定一個文件中默認實參只能聲明一次(定義也是聲明呀)

15. 自動對象

只有當定義它的函數調用時才存在的對象

通常指形參和局部變量,它們在定義它們的語句塊結束時撤銷

靜態局部對象

在第一次通過它的定義語句時建立,程序結束時撤銷

size_t count() {

static size_t c = 0; // 只執行一次

return++c;

}

int main() {

for(size_t ix = 0; ix != 20; ++ix) {

cout<< count() << 「 」;

}

return 0;

}

輸出1,2,3,4,5.....

16. const string &shorterStr(const string&,const string&);

定義它的好處:易讀,易改,保證統一,code reuse

壞處,慢!怎麼辦 inline!!!!

對於內聯函數,編譯器要展開代碼,僅看到原型是不夠的,

內聯函數應該在頭文件中定義,在頭文件中加入或修改內聯函數時,使用該頭文件的全部源文件必須從新編譯!

17. 成員函數

每一個成員函數都有一個this形參,是調用該函數的對象的地址

對象實例調用本身的成員函數,將本身傳給這個成員函數與之進行綁定

this指針是隱含的,不能明式出如今形參表中



常成員函數bool same_isbn(constSales_item&)const;

total.same_isbn(trans);調用時,則這個this是指向total的const Sales_item*類型的指針, 是個指向const對象的指針,因此這個函數不能改變數據成員

const對象、指向const對象的指針或引用只能用於調用其const成員函數!!反過來,非const的這幫東西能夠調用const的成員函數(並不是必須是const的對象才能調用)

換句話:const對象不能調用非const成員函數

對於成員函數,聲明與定義必須一致,若是要const那麼二者都要同時有const

18. 對象若是在全局做用域或定義爲局部靜態對象,那麼成員初始化爲0,若是對象在局部做用域中定義那麼沒有初始化

若是類成員有內置類型或複合類型(用其餘定義的類型,如引用,指針,數組,容器)成員,那麼最好本身定義默認構造函數,不要合成的

19. 做業t7_31 Sales_item.h

20. 函數返回類型,最右邊形參具備默認實參,以及const的非引用形參不能做爲重載的區別標誌

int fuc1(int*);

int fuc1(const int*); //重複聲明 ,沒有error

//對於第二個,實參便可以是const int*也能夠是非const int*的普通指針,因此沒區別,都是值傳遞,對副本操做

補充,若形參是const &int那麼區別了,是重載!此時,若實參是const對象則調用帶有const的那個函數,若調用另外一個是須要轉換的故而不優,由此區分!若實參是非const對象,則兩個均可以調用,優先選擇調用不帶const的那個(調用帶有const的也須要轉換);指針也相似的狀況(若是實參是const對象,則調用帶有const*類型形參的函數,不然若是實參不是const對象,將調用帶有普通指針形參的函數)

f(int*)

f(const int*)// 能夠重載

而下面的

f(int*)

f(int*const) //不能重載(值傳遞,副本傳遞) // 這裏是const指針,只有指向const對象的指針做形參才能實現重載

再補充:僅當形參是引用或指針時,形參是否爲const纔有影響

int fuc2(int, int);

int fuc2(int, int b = 2); //重複聲明

p229 建議:什麼時候不重載函數名

21. 函數重載的前提是函數彼此間做用域相同,不然就是屏蔽關係

局部聲明函數是個壞習慣,通常都有要聲明在頭文件中

C++中,名字查找發生在類型檢查以前,因此,在局部做用域內找到名字對應的函數後,再也不去外層找了,即便類型不是最合適的。

重載肯定

找與實參最佳match

void f(int)

void f(double, double = 3.21)

調用f(3.2); 將選擇下面那個,由於精確匹配優於須要類型轉換的匹配。編譯器將自動將默認實參提供給被忽略的實參,所以這個調用函數擁有的實參可能比顯式給出的多

void f(int, int);

void f(double,double)

調用f(2, 3.24);有二義性

設計形參儘可能避免實參類型轉換

注意,較小的整型提高爲int型。小的提高爲int,優於形式上合適的char類型的匹配!

void f(int)

void f(short)

ff(‘a’) // match上面第一個

還有,類型提高優於其餘標準轉換!

例如:char到double優於到unsigned char的轉換

void f(unsigned char) // 若去掉unsigned則選擇第一個

void f(double)

調用f(‘a’) //二義

參數匹配與枚舉類型

枚舉類型的對象只能用同種枚舉類型的另外一對象或一個枚舉成員進行初始化

整數對象即便有與枚舉元素相同的值也不能用於調用指望得到枚舉類型實參的函數,可是能夠將枚舉值傳遞給整型形參(129的時候提高爲int,而不是unsigned char)

22. 函數指針:bool (*pf)(int); //指向函數的指針

而指針函數:bool *pf(int); // 返回值是指向bool指針

使用typedef簡化函數指針

typedefbool (*pf)(int); //pf是一個種指向函數的指針的名字,它所指向的函數有一個int參數,返回值是bool類型

函數指針的初始化和賦值: (三種,0、函數名、&函數名)

第一種:pf fuc1 = 0;

//等於bool (*fuc1)(int)= 0; // 藍色部分就是類型

第二種:使用函數名

注意:bool setAge(int); 其中setAge除了用於函數調用外,其餘任何使用都將解釋爲指針: bool(*)(int);

pf fuc2 = setAge; // 使用函數名進行初始化

fuc1 = fuc2; //或賦值

上面直接使用函數名setAge等於在函數名上取地址操做

pffuc2 = setAge;

pffuc2 = &setAge; // 兩個等價

而使用 pf fuc3(3); // 直接初始化是錯的

指向不一樣類型函數的指針不存在轉換

能夠經過函數指針調用函數

fuc2 = setAge;

調用:fuc2(32); // 前提是這個函數指針已經初始化,如果0或未初始化不行

函數指針做形參

voidsamplefuction(const string&, bool(int));

//函數類型的形參,對應實參將被自動轉換爲相應的函數指針

voidsamplefuction(const string&, bool (*)(int));

//函數指針類型的形參,與上面聲明等價

返回類型是指向函數的指針(返回類型能夠是函數指針類型,但不能夠是函數類型) 後補充:函數ff的返回類型是一個指向」外圍」函數的指針

bool (*ff(int))(int*, int) // 藍色部分是類型 這句話用在這裏是在聲明ff這個函數

ff(int)函數返回一個函數指針,它的類型是bool (*)(int*, int)

使用typedef使用該定義更加簡明易懂

typedefbool (*PF)(int*, int)

PFff(int); // 聲明ff這個函數

舉例:

typedef int func(int*, int);

void f1(func); // ok,函數類型能夠做形參,對應實參將自動轉成函數指針

func f2(int); // error!! 返回類型不能是函數類型,不能自動轉成函數指針

func *f3(int); // ok, 返回類型是函數指針

指向重載函數的指針

必須精確匹配

extern void ff(double);

extern void ff(int); // ok,重載

void (*pf)(double)= &ff; // ok, 精確匹配,對應第一個

int(*pf)(double) = &ff; // error, 返回值不匹配

第八章 IO

1. #include <iostream>

#include <sstring> // 從iostream繼承

#include <fstream> // 從iostream繼承

2. 國際字符支持

char有相應的wchar_t

wostream wistream wiostream <iostream>

wifstream wofstream wfstream <fstream>

wistringstream wostingstream wstringstream <sstream>

3. IO對象不能複製或賦值

不以放在vector或其餘容器中

不能做爲形參,必須是引用或指針(返回值也要是引用)

形參也是非const的,由於IO對象的讀寫會改變狀態

4. 條件狀態:

strm::iostate

strm::good 0 000

strm::badit 1 001 系統級

strm::failbit 2 010 可恢復

strm::eofbit 3 011

s.eof()

s.bad()

s.fail()

s.good()

s.clear() // 恢復全部

s.clear(f)

s.setstate(f) // 置爲某條件發生

s.rdstate() // 返回當前條件 返回類型strm::iostate

5. testFile.cpp

做業

t8_3.cpp get.hpp

t8_6.cpp get.hpp



cout << 「abc」 << flush;

cout << 「abc」 << ends;

cout << 「abc」 << endl;

調bug時,根據最後一條輸出肯定崩潰的位置。多使用endl而不是’\n’,儘量地讓它在崩潰前將該刷新的輸出出來

6. 交互式程序cin與cout綁定:任何cin讀操做都會首先刷新cout關聯的的緩衝區

tie函數,一個流調用tie將本身綁定在傳過來的實參流上,則它的任何IO操做都會刷新實參所關聯的緩衝區

cin.tie(&cout);

ostream *old_tie = cin.tie();

cin.tie(0); // 釋放tie

cin.tie(&cerr);

cin.tie(0);

cin.tie(old_tie); // 從新與cout綁定

7. 文件流

ifstream infile(filename.c_str());



ifstream infile;

infile.open(filename.c_str());

if (!infile)
infile.close(); // 打開另外一個前要關閉

infile.open(filename2.c_str());
若是要重用文件流讀寫多個文件,則在讀另外一個文件前要

infile.close();

infile.clear();

若是infile定義在while之中,那麼每次都是乾淨的狀態,不用clear均可以

8. vector中存放在着多個文件的名字

讀出來

t8_8.cpp

if (!input) {

cerr<< "error: can not open file: " << *it << endl;

input.clear();

++it;

continue;

}

//在vs提示符下d:/dev_projects/c++primer>c++primer < data/8_8

9. t8_9.cpp讀取文件內容,每一個做爲一個元素放到vector<string>中

ifstreaminfile(fileName.c_str());

if(!infile) {//打開文件失敗

return1;

}

stringstr;

while(getline(infile, str)) { // 行做爲元素

//while(infile >> str) { // 單詞做爲元素 8-10

svec.push_back(str);

}

10. 文件模式

in // ifstream和fstream , ifstream默認以in打開

out // ofstream fstream 會清空數據至關於也打開了trunc

ofstream默認以out打開

app // ofstream 追加

ate 打開後定位在尾

trunc // ofstream 清空數據

binary // 打開後以字節的形式重,不解釋字符

ofstream outfile("data/testfile", ofstream::app);

fstream inout;

inout.open(「data/filename」, fstream::in |fstream::out);

ifstream& open_file(ifstream &infile,const string &filename) {

infile.close();

infile.clear();

infile.open(filename.c_str());

//if(!infile) // 不做判斷

return in;

}

調用open_file()

ifstream infile;

if(! open_file(infile, fileName)) {

cout<< "error: can not open file:" << fileName << endl;

system("pause");

return-1;

}

get(infile);// 讀取輸出

get的實現

while (in >>ival, !in.eof()) {

if (in.bad()) {

throw runtime_error("IO streamcorrupted");

}

if (in.fail()) {

cerr << "bad data, tryagain!";

in.clear();

continue;

}

cout << ival << "";

}

11. 字符串流

while (getline(cin, line)) {

istringstreamistrm(line);

while(istrm >> word) { // 處理這行中的每一個單詞

.....
}

}

stringstream strm;

stringstream strm(s);

strm.str(); // 返回那個string對象

strm.str(s);
stringstream能夠提供轉換和格式化

可以使自動格式化

teststringstream.cpp

int val1 = 21, val2 = 23;

ostringstream out ;

out << "val1:" << val1<< "\nval2:" << val2 << "\n";

cout << out.str() << endl;
cout <<"=======================\n" << endl;
istringstream in(out.str()); // 關聯到這行字符val1:21\nval2:23
string dump;
int a,b;
in >> dump >> val1 >> dump>> val2; // 換成a和b就不行

//忽略所取數據周圍的符號,用dump

cout << val1 << " "<< val2 << endl;
cin.clear(istream::failbit); 在我機器上無論用

要使用cin.clear()

12. 文件讀入,每行做爲一個元素放到vector<string>中,再istringstream對象初始化爲每一個元素,處理每一個單詞,輸出; 這都是很簡單的程序

istringstream istr;

string word;

for (vector<string>::const_iterator it= svec.begin();

it != svec.end(); ++it) {

istr.str(*it);

while (istr >> word) {

cout << word << 「 」 ;

}

istr.clear(); // 定義在外面,因此將流設置爲有效狀態

}


第九章 順序容器

1. vector.swap(): 兩我的換家,家裏東西不搬動

vector<string>sv1(10);

vector<string>sv2(32);

sv1.swap(sv2);// 不會使迭代器失效, 還指向原來的元素,常數時間內交換,沒有移動元素

cout<< sv1.size() << endl; // 32

cout<< sv2.size() << endl; // 10

2. 9-28 不一樣類型容器間的賦值

char *sa[] = {"hello","good", "nihao", "leimng"};

list<char*> slst(sa, sa + 4);

vector<string>svec;

svec.assign(slst.begin(), slst.end());

3. size是已經有的,capacity是再分配以前的容量,一般大於size, reserve(n), 其中n>capacity,則改變的是capacity=n不會改變size
while (ivec.size() != ivec.capacity()) ivec.push_back(0); // 只要還有剩餘的容量就不會從新分配

ivec.push_back(0); 此時再查看一下size和capacity,知道庫的分配策略了。

4. 刪除大寫字母

for (string::iterator it = str.begin(); it !=str.end(); ++it) {

if(isupper(*it)) {

str.erase(it); // erase操做使it後移到被刪元素的下一位置,而for中有++it,因此,下一步還原回來

--it; // 使迭代器指向被刪除元素的前一位置

}
}

用while寫可提升效率:

string::iterator it = str.begin();

while (it != str.end()) {

if(isupper(*it)) {

str.erase(it);

} else {

++it;

}

}

5. const vector<int> ivec(12);

vector<int>::iterator it = ivec.begin();// error,const類型迭代器不能賦給非const類型的it

改正:vector<int>::const_iteratorit = ivec.begin();

const vector<int>::iterator it =&ivec[0]; //error迭代器雖是指針,但不能這樣賦值

6. 任何無效迭代器的使用都會致使運行時錯誤 ,沒法檢查出來

向vector添加元素,若是空間不夠,則從新加載,原迭代器所有失效。

容器能夠調整大小resize(n),有可能使迭代器失效。 對於vector,deque,有可能所有失效; 對全部的容器,若是壓縮,則可能使被刪除元素的失效

7. 元素類型size_type value_type, reference等同於value_type& 引用 ,寫泛型程序很是用有

const_reference: value_type&

例子:vector<int>::size_type size = ivec.size(); / ivec.max_size();

ivec.resize(100,3); // 調整大小爲100,新加元素爲3

8. 向容器添加元素都是添加原值的副本

9. list容器前插法

while (cin >> word)

iter= ilst.insert(iter.begin(), word);

等同於:ilst.push_front(word);

10. 兩個容器能夠大小比較,實際上是其元素在做比較,若是元素不支持,則容器也不支持

ivec1 < ivec2

要求徹底匹配,即容器類型與元素類型都相同,且元素類型支持<操做

11. 訪問元素

list<int>::referenceval = *ilst.begin(); // begin操做返回迭代器,實際上是指針

list<int>::reference val2 =ilst.front(); // front和back操做返回元素的引用

ivec<int>::reference val3 = ivec[3]; 或 ivec.at(3); 隨機訪問類型的容器

12. 刪除元素:

c.erase(p);

c.erase(b, e); // 返回下一元素的迭代器

pop_back(); 刪除最後一個元素並返回void

pop_front 不返回被刪除元素的值,想拿到這個值,就要在刪以前調用front或back函數

清除clear

13. list是雙向鏈表實現的 deque: 能夠隨機訪問,中間插入元素代價高,可是在首尾刪增元素代價小,且在首部增刪元素不會使迭代器失效(固然刪掉的就失效了)

若是讀入的時候要在中間插,則能夠先讀入到list中,再拷到vector中,排一下序(書上說在拷以前排序)

14. string與vector不一樣的是,不支持棧方式操做容器,沒有front, back, pop_back

15. vector<char> cvec初始化string str(cvec.begin(), cvec.end())

對於一個string對象,要一次輸入一百個字符,則先str.reserve(101);改一下capacity

16. 如下是string的一些操做,構造,assign, erase, insert, append, replace, substr, find等等,使用的時候查



string構造另外方式:

string(c_array, n); //c_array能夠是char *和char []的C風格字符串

string(s, pos2); //string類型s的下標pos2開始

string(s, pos2, len2);
替換str.assign(b, e); str.assign(n, t); //使用副本替換 返回string, 對於vector返回void
str.assign(s);// 以s的副本替換str
str.assign(c_array);
str.assign(s, pos2, len)
str.assign(cp, len)
str.erase(pos,len); // pos就是下標
str.insert(pos,cp); // 插入以NULL結尾的C風格串
str.insert(pos, s); // 插入s
str.insert(pos, s, pos2, len);
str.insert(pos, cp, len);
子串

str.substr(pos, n);

str.substr(pos);

str.substr(); // 返回str的副本ios


一系列的append和replace

查找:各類find, 返回類型string::size_type

find() // 找第一次出現

rfind() // 反向查找

find_first_of() // 任意字符的第一次出現 「0123456789」 , 能夠用來查找串中全部數字

find_last_of

find_first_not_of

find_last_not_of

沒有找到if (find() != string::npos)


17. 容器適配器

#include <stack>

#include <queue>



stack與queue默認是創建在deque之上,這種狀況能夠改變,經過第二類型實參來指定:

stack<string, vector<string> > str_stk; // 先後string確定同樣啦

queue是隊列,不能創建在vector之上,由於沒有pop_front()操做

priority_queue默認創建在vector之上,也能夠用deque,不能用list,它要求隨機訪問

適配器能夠比較 > < =



優先隊列也像棧同樣有top操做,它是返回具備最高優先級的值,但沒有back和front操做

優先隊列在push操做的時候,自動插入到適當位置

對於容器這幾章,建議使用的時候認真閱讀primer書和參考文檔



補充第九章:

1. 容器元素類型約束:賦值和複製運算。 不能是引用類型,不能IO類型

2. 支持隨機訪問的容器(vector, deque)的迭代器,支持it與數字的加減、it間的加減,it間的<>比較

3. 逆序輸出ilist元素:

Ilist<int>::iterator it = ilist.end();

While (it != ilist.begin()) {

Cout << *(--it) << endl;

}

第十章 關聯容器

1.pair在#include <utility>

pair<int, string> p1 = make_pair(2, 「good」);

pair<int, string> p2(3, 「hello」);

p1 < p2; 先比第一個,若相等,則比較第二個

p1.first 這兩個成員都是公有成員

p1.second

利用typedef pair<int, string> auther;

auther p3(4, 「nihao」);
因爲是公胡成員,因此能夠cin >> p1.first >> p1.second;

2. map類型

map的元素類型map<k, v>::value_type是一個pair<constk, v>類型, first元素是const map<k,v>::key_type, second是map<k,v>::mapped_type

map<string, int>::iterator map_it =word_count.begin();

map<string, int>::key_type str = map_it->first; // 鍵值const只能讀不能改,跟set同樣
word_count[「leiming」] = 1; // 直接插入
while(cin >> name) {

++word_count[name];// 若是沒有,則直接++爲1

}

pair<map<string,int>::iterator, bool> mp;

mp = word_count.insert(p1); //返回的pair是pair<map<string,int>::iterator,bool>類型

if (!mp.second) {

cout << 「沒有插入」 << endl;

++mp.first->second;

}
在map中讀而不插入元素

if (word_count.count(「fool」)){ // 返回0或1

occurs= word_count[「fool」];

}

或者

mpa<string, it>::iterator it =word_count.find(「fool」); // find返回指向按k索引的迭代器

if (it != word_count.end()) {

occurs= word_count[「fool」];

}

erase操做c++


erase(k) // 返回0,1
erase(p) // void
erase(b,e) // void
遍歷輸出word_count的時候,按字典順序輸出單詞,很神奇!在使用迭代器遍歷map容器時(別的時不行),迭代器指向的元素按key的升序排列
程序員

相關文章
相關標籤/搜索