第六章 语句
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的升序排列
程序员