第一章:
1、C++的基本数据类型:
整型(int)、浮点型(float)、字符型(char)、布尔型(bool:只有false和true两个值)、字符串(string)、复数(complex number)、向量(vector)、列表(list)。
注:使用string必须有#include
使用vector必须有#include
vector: 表示创建一个能够存放字符串元素的向量类型。
如 “vector title(20)” 表示title向量中可以存放20个字符串类型的元素。
2、#Include<***.h>与#include<***>的区别:
#include<****.h>:以该形式定义头文件后无须用unsing namespace std 即可在程序中调用该函数。
#include<***>:以该形式定位头文件后必须使用using namespace std才能使用该函数。
#include <iostream>
using namespace std;
int main(){
int iterations=0;
bool continue_loop=true;
while (continue_loop!=false)
{
iterations++;
cout<<"the while loop has executed"<<iterations<<"times\n";
if(iterations==5)
{
continue_loop=false;
}
}
return 0;
}
注:头文件中iostream 没加后缀,所以需要加上using namespace std,若加上后缀.h,即可不写using namespace std。
3、输入输出流(iostream )库:
- 标准输入-----cin
- 标准输出----cout
- 注:若要输出bool类型的true 或 false,则在输出bool类型前加入boolalpha。如cout <<boolalpha<<bool对象。
- 注:若要输出bool类型为0(false)或1(true),则在输出bool类型前加入noboolalpha或者缺省直接输出。如 cout<<noboolalpha<<bool对象。
- 注:setw(int n)用来控制输出间隔
- 标准错误----cerr
注:输出操作符-----“<<”,换行符-----‘\n’或endl,输入操作符----“>>”。
//例子:
string file_name;
cout<<"please input the file to be opened:";
cin >> file_name;
4、动态对象内存的分配和释放
new函数:返回一个地址
- new表达式不返回实际被分配的对象,而是返回这个对象的地址,对象的所有操作均是通过这个地址来间接的完成,并且当对象完成了使命时,我们必须通过delete把对象的内存返还给空闲存储区。
- *int pint=new int (1024);---->表示分配一个没有名字的int类型的对象,对象初始值为1024,表达式返回该对象的地址给pint。
- *int pia =new int [4];---->表示分配一个包含四个int型数据的数组,表达式返回该数组的第一个元素的地址
delete函数:
- delete pint;----->表示删除单个对象
- delete [ ] pia;---->表示删除一个对象数组。
5、基于对象设计的类的一般形式:
class classname{
public:
//公有操作集合
private:
//私有实现代码
};
注:class、public和private是C++语言的关键字,classname是用户定义的标识符。
- 类头:由class与类名构成
- 类体:由花括号括起来,以分号结束;其包含成员定义,访问标签(public和private)。
- 类的成员包括“该类能执行的操作”和“代表类抽象所必需的数据”------->成员函数。
6、变量的初始化:
- 显示语法:int ival = 1024;
- 隐式语法:int ival (1024);
- 全局变量会自动初始化为0,局部变量则不会。
7、指针
- 在解除指针的引用之前(即取出指针所指向的值之前),应当用 if(指针) 测试它是否指向了某个对象,以防止指针指向的地址为0.
8、const限定修饰符
-
const 类型可以把一个对象转换成常量(即 该对象是只读的,不能修改)。如 const int bufsize=512;
-
因为常量定义后不能修改,所以在定义是必须初始化。
-
若我们定义一个指针指向该常量对象的地址,那我我们仍然可以通过解引用该指针间接的改变对象的值。
-
若定义一个指向某类型的 const 对象的指针(const double *p;) ,指向任何一个常量或非常量对象,我们可以在初始化p后继续对其赋其他值,但不能修改其指向的对象的值
/*3、指针指向常量对象*/ const int bufsize=512; int *p =& bufsize; *p += 500; /*4、常量指针*/ const double *p,*q;//p,q是指向double类型的,定义成const的对象的指针 const double minwage=9.60; double maxwage=100.00; p=&minwage; q=maxwage; *p=6.90;//错误,不能修改 *q=99.0;//错误,不能修改
-
若定义一个指向某类型的const指针(int *const cur;),则我们不能在初始化cur后给它赋其它值,但可以修改cur指向的对象的值。
int err=0; int err1=1; int *const cur=&err;//对cur初始化 *cur=10;//将err=10;正确 cur=&err1;//错误,不能再次对cur赋值
-
若定义一个指向const对象的const指针(const double *const p;),则我们不能在初始化p之后对其进行赋值,也不能改变其指向的对象的值。
const double pi=3.14159; const double *const p=π//初始化p *p=3.14;//错误,不能更改 p=&pii;//错误,不能更改9、
9、引用类型
-
定义:引用类型由类型标识符和一个取值操作符构成,引用必须被初始化(一旦引用被定义后,就不能再指向其他对象)。
int ival=1024; int &refVal=ival;//对引用初始化,引用refVal指向ival。 int *&refval=&ival;//定义了一个指针引用,指向ival。
-
引用的所有操作都是应用在它所指的对象上。
-
每个引用的定义都必须从“&”开始,如:int &rval1,&rval2;
-
const int ival=1024; const int *&pi_ref=&ival;//错误,引用pi_ref指向定义为const的int类型对象的指针,而不是指向一个常量指针,所以该引用不能初始化为一个const对象的地址。 /*正确做法*/ const int *const &pi_ref=&ival;//正确。
-
引用和指针的区别是:引用必须指向一个对象。
例子: /*指针*/ int *pi=0;//用0初始化pi,pi没有指向任何一个对象。 /*引用*/ const int &ri=0;//在内部发生了一下变换: int temp=0; const int &ri=temp;
10、枚举
-
枚举类型定义:enum 枚举类型名{枚举成员列表};在缺省(即没有给任何枚举成员赋值)的情况下,第一个枚举成员赋值为0,后面的每个成员比前面的大1。
-
若只给了部分枚举成员赋值,则未赋值的枚举成员比前一个枚举成员大1。
例如:enum points{point1=2, point2, point3=3,point 4};
其中,point2=point1+1=3;point4=point3+1=4。
11、数组
-
字符串常量包含一个终止空字符。
例如:const char ch[6]="Daniel"是错误的,数组维数应为7。
而const char ch[6]={‘D’,‘a’,‘n’,‘i’,‘e’,‘l’}是正确的。
12、泛型程序设计-------模板函数
-
所需头文件:template
-
在定义模板函数时,参数类型设置为elemType
#include <iostream> template <class elemType> void print(elemTpye *pbegin,elemType *pend)//模板函数 { while(pbegin != pend) { cout << *pbegin<<' '; pbegin++; } } int main() { int ia[9]={0,1,2,3,4,5,6,7,8}; double da[4]={3.14,6.28,12.56,25.12}; string sa[3]={"piglet","eeyore","pooh"}; print(ia,ia+9); print(da,da+4); print(sa,sa+3); }
13、vector容器类型
-
所需头文件:#include
-
定义方式:vector<类型标识符> 向量名(元素个数);
-
初始化vector的方式:
-
vector ivec(10,-1):表示ivec包含10个int类型的元素,每个元素被初始化为-1。
-
vector ivec(ia+m,ia+n):用数组ia中地址为 [ ia+m,ia+n) 之间的(n-m)个元素来初始化ivec,其中 ia+n 为要拷贝的末元素的下一个地址。
-
可以用另外一个vector来初始化,也可以将当前vector赋值给另外一个vector。
vector <string> svec; void main() { vector <string> ivec(svec);//用svec来初始化ivec; svec=ivec;//将ivec赋值给svec; }
-
-
size( )操作返回vector中元素的个数:元素个数=ivec.size( );
-
push_back( )操作表示在vector后面插入一个元素:ivec.push_back( );
example: const int size=7; int ia[size]={0,1,2,3,4,5,6}; vector<int> ivec(size);//ivec包含7个元素。 for(int ix=0;ix<size;ix++) { ivec.push_back(ia[ix]);//在ivec的后面,从第8位开始插入元素。 } //程序结束时ivec中包含14个元素。
-
访问vector中的元素:
-
普通迭代:
vector<int> ivec(10); for(int ix=0;ix<ivec.size();ix++) { cout<<ivec[ix]<<' '; } cout<<endl;
-
使用vector操作集中的begin()和end()所返回的迭代器(iterator):
vector<int> ivec(10); for(vector<int>::iterator it=ivec.begin();it!=ivec.end();it++) { cout<<*it<<' '; } cout<<endl;
注:iterator是标准库中的类,具有指针的功能。
-
-
vector向量排序:库函数sort():
- 头文件:#Include
- 原型:void sort( .begin(), .end() )
14、复数(complex)
-
所需头文件:#include
-
定义方式:complex<类型标识符> 复数名(实部,虚部)
-
纯虚数( 0+7i ):complex purei(0,7);
-
3+0i:complex real_num(3);
-
0+0i:complex zero;
-
用另一个复数来初始化一个复数对象:complex purei2( purei );
-
复数对象的数组:complex conjugate[2]={
complex (2,3)
complex (2,-3)
};
-
声明指针或引用:complex *ptr =&conjugate[0];
complex &ref =*ptr;
-
-
成员访问语法:读取复数的实部(“real( )”)或虚部(“imag( )”)。
complex<double> a; /*第一种访问方式*/ double re=a.real();//读取复数a的实部 double im=a.imag();//读取复数a的虚部 /*第二种访问方式*/ double re=real(a);//读取复数a的实部 double im=imag(a);//读取复数a的虚部
-
复数的输出是由一对由括号括起的且由逗号分隔的序列对(实部,虚部)。
15、typedef
-
格式:typedef 类型标识符 自定义标识符;
-
一个难点:
typedef char *cstring;//已知这个 //下面的声明中,cstr的类型是? extern const cstring cstr; /*答案:cstr是一个指针,const修饰cstr,所以这个定义声明了cstr是一个指向字符的const指针。即 char *const cstr*/ //网上的解释:cstring是指针类型,对一个指针加const,当然是const型指针。
16、volatile限定修饰符
- 用法:与const相似,在定义每个对象前加 volatile。如 volatile int num ;表示num是一个int型的volatile对象。
- 目的:提示编译器,该对象的值可能在编译器未监听到的情况下被改变。
17、pair类型
-
所需头文件:#include
-
定义:在单个对象内部把相同类型或不同类型的两个值关联起来。
例:pair <string,string> author (“James”,“Joyce”); 创建了一个pair对象,对象名为author,包含两个字符串,分别被初始化为“James”和“Joyce”。
-
引用pair中的单个元素:成员访问符号first或者second
如:author.first ----->James; author.second------>Joyce;
-
pair类型的对象赋值:
pair<int,int> result;
result=pair<int,int>(3,4);
-
make_pair( )函数:无需写出型别, 就可以生成一个pair对象
18、文件的输入和输出
-
所需头文件:#include
-
为了打开一个输出文件,我们必须声明一个ofstream类型的对象:
ofstream outfile( “文件名”,打开模式 );
-
打开模式:(如果该文件名所示的文件不存在,则会自动创建一个新的文件;缺省时默认输出模式)
输出模式(ios_base::out);若在输出模式下打开已经存在的文件,则所有存储在该文件中的数据将被丢弃;
附加模式(ios_base::app);若以附加模式打开文件,则原有数据会保存,我们从文件结尾开始写入数据。
-
若打开成功则 outfile 返回1,否则返回0;
ofstream outfile("copy.txt"); ofstream outfile("copy.txt",ios_base::out);//以输出模式打开copy.txt文件 ofstream outfile("copy.txt",ios_base::app);//以附加模式打开
-
打开文件后,在写入之前要检测是否已成功打开。
ofstream outfile("copy.txt",ios_base::app); if(!outfile) { cerr<<"cannot open the file!"; exit(-1); }
-
所有ostream(输出)操作都可以应用到一个ofstream类对象上;
char ch=' '; outfile.put('1').put(')').put(ch); outfile<<"1+1="<<(1+1)<<endl;
-
-
为了打开一个文件供输入,我们必须声明一个ifstream类型的对象:
ifstream infile( “文件名” ,打开模式);
-
打开模式:默认是 ios_base::in
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZcYqpNdo-1589382040740)(E:\重邮硕士\学习笔记\C++\文件输入模式.jpg)]
-
若打开成功则 infile 返回1,否则返回0;
-
-
打开一个文件后,要记得通过close( )关闭文件。
ofstream file("1.txt",ios_base::out); //.... file.close();//关闭文件
-
eof( )发现读到文件结束标志EOF(即-1)时并不会立刻返回true, 而是比较后知后觉。此时需要再读一下,这时eofbit才被设置(并且设置其他的bit,如goodbit),等下次调用eof()时才返回true。
-
可以通过**seekg( )或seekp( )**成员函数对fstream类对象重新定位(g表示为了获取字符而定位,用于ifstream类对象;而p表示为放置字符而定位,用于ofstream类对象)。
-
设置到文件中固定的位置上:seekg( pos_type current_position );
----->当前位置被设置为由current_position指定的某个固定的位置,这里0是文件的开始。
//文件中有abc def ghi jkl io.seek(6);//把io重新定位到字符位置6,即f位置
-
从当前位置向某个方向进行偏移:seekg(off_type offset_position, ios_base::seekdir dir);
---->使用一个偏移重新定位文件,该偏移值或者是从当前位置开始计算,或者是到文件开始出的偏移,或者是从文件尾部倒退向后计算,这是有第二个实参dir指定的,dir可以指定为下列选项之一:
- ios_base::beg,文件的开始
- ios_base::cur,文件的当前位置
- ios_base::end,文件的结尾
-
-
fstream文件中的当前位置由**tellg( )或tellp( )**返回(tellg用在ifstream中,tellp用在ostream中)。
第二章 ------表达式
1算数操作符
- 取余操作符“%”:应用该操作符的操作数只能是整数类型(char、short、long、int)。
- 强制类型转换符:static_cast<类型标识符>(操作对象名)。
2 sizeof操作符
- 作用:返回一个对象或类型名的字节长度。
- 用法:sizeof(type name);或sizeof(object);或sizeof object;
- 返回值类型:size_t
- 所需头文件:#include
- 应用在指针类型上的sizeof操作符返回的是包含该指针类型地址所需要的内存长度(字节),而应用在引用类型上的sizeof操作符返回的是包含被引用对象的内存长度。
3 bitset操作
操 作 | 功 能 | 用 法 |
---|---|---|
text(pos) | pos位是否为1 | a.test(4) |
any( ) | 任意位是否为1 | a.any( ) |
none( ) | 是否没有位为1 | a.none( ) |
count( ) | 值是1的位数 | a.count( ) |
size( ) | 位元素的个数 | a.size( ) |
[pos] | 访问pos位 | a[4] |
flip( ) | 翻转所有位 | a.flip( ) |
flip(pos) | 翻转pos位 | a.flip(4) |
set( ) | 将所有位置1 | a.set( ) |
set(pos) | 将pos位置1 | a.set(4) |
reset( ) | 将所有位置0 | a.reset( ) |
reset(pos) | 将pos位置0 | a.reset(pos) |
注:any( ):当bitset对象的各位中,有1则返回true,否则返回false。
-
所需头文件:#include
-
声明方式:
-
bitset<位数> 自定义类名;
-
bitset<位数>自定义类名(无符号参数);
/*第一种声明方式*/ bitset<32> bitvec;//声明了一个含有32个位的bitset对象,在缺省的情况下,所有位都被初始化为0. /*第二种声明方式*/ //将bitvec1的低16位置1. bieset<32> bitvec1(0xffff); //通过0和1的集合的字符串参数构造bitset对象 string bitval("1010"); bitset<32> bitvec2(bitval);//将bitvec2的第1位和第3位置1。 //标记用来初始化bitset的字符串范围 string bitval("111111110101010001110"); bitset<32> bitvec3(bitval,6,4);//从位置6开始,长度为4:0001;若‘4’缺省,则初始化字符的范围有指 定的位置一直到末尾。
-
-
两个成员函数:to_string( )和to_ulong( )
-
to_string:将任意bitset对象转换成string表示。
如:string bitval( bitvec.to_string( ) );
-
to_ulong:将任意bitset对象转换成unsigned long型的整数表示。
如:unsigned long bitval( bitvec.to_ulong( ) );
-
4 类型转换
-
算数转换中,不同的类型提升到当前出现的最宽的类型,以便保留精度。
-
强制类型转换符:static_cast<类型标识符>,const_cast<类型标识符>,dynamic_cast<类型标识符>,reinterpret_cast<类型标识符>。
注:const_cast<类型标识符>将转换掉表达式的常量性(以及volatile对象的volatile性)。
5 栈类
- 栈就是一个向量,我们把元素存储在一个向量(vector)中,向量名字为_stack。
- 基本操作:向栈中压入(push)、弹出(pop)(即获得最后压入的那个值)、查询栈是否满full( )或空empty( )、以及判断栈的长度size( )(即包含多少个元素)、显示栈中的元素display( )。
- 代码实现(当前仅学习支持int型元素的栈iStack):
/*size( )函数的代码实现*/
inline int iStack::size() { return _top; }//_top含有下一个可用槽的值,其当前值反映了栈中元素的个数。
/*empty()和full()函数的代码实现*/
inline int iStack::empty()
{
return _top ?false:true;
}
inline int iStack::full()
{
return _top < _stack.size()?false:true;
}
/*pop()和push()函数的代码实现*/
bool iStack::pop(int &top_value)
{
if(empty())
return false;
top_value=_istack[_pop-1];
cout<<"iStack::pop:"<<top_value<<endl;
return true;
}
bool iStack::push(int value)
{
cout << "iStack::push("<<value<<")\n";
if(full())
return false;
_stack[_pop++]=value;//_pop++表示先将value压入_stack[_pop],然后_pop加1。
return true;
}
/*display()函数的代码实现*/
void iStack::display()
{
if(!size())
{
cout<<"(0)\n";
return;
}
cout<<"("<<size()<<")( bot: ";
for(int ix=0;ix<_top;ix++)
{
cout<<_istack[ix]<<" ";
}
cout << ": top )\n";
}
第三章------抽象容器类型
前言:
- 顺序容器拥有由单一类型元素组成的一个有序集合,主要的顺序容器是list(链表)、vector和deque;
- vector:表示一段连续的内存区域,每个元素被顺序存储在这片区域中。
- deque:表示一段连续的内存区域,但它支持高效的在其首部插入和删除元素,它通过两级结构来实现,一级表表示实际的容器,第二级指向容器的首与尾。
- list:表示非连续的内存区域,通过一对指向首尾元素的指针双向连接起来。
- 关联容器支持查询一个元素是否存在,并且可以有效地获取元素,基本的关联容器类型是map(映射)和set(集合)。
- map:是一个键/值(key/value)对,键用于查询,值包含我们希望使用的数据。
- set:包含一个单一键值,有效支持关于元素是否存在的查询。
1、vector和list的选择
- 若我们需要随机访问一个容器,则vector比list好得多;
- 若我们已知要存储元素的个数,则vector比list好;
- 若我们需要的不只是在容器两端插入和删除元素,则list比vector好;
- 若我们需要在容器首部插入和删除元素,则deque比vector好;
2、vector如何自己增长
- 容量:在容器下一次需要增长自己之前能够被加入到容器中的元素的总数,可通过调用vector的成员函数capacity()操作求容量。
- 长度:容器当前拥有的元素个数,通过调用vector的成员函数size()操作求长度。
3、顺序容器
- 成员函数 reserve(参数1,参数2)可以通过参数1将容器的容量设置成一个显式指定的值,其增加的新元素的值可由该函数的参数2指定。
- 容器的比较是指两个容器的元素之间成对进行比较,如果所有元素相等且两个容器含有相同数目的元素,则两个容器相等;否则不相等,第一个不相等元素的比较决定了两个容器的大于或小于关系。
4、迭代器(iterator)
-
作用:对顺序或关联容器类型中的每个元素进行连续访问。
- 假设iter为任意容器类型的一个iterator,则++iter向前移动迭代器,使其指向容器的下一个元素,而*iter返回iterator指向元素的值。(iter相当于一个指针)
-
每种容器类型都提供一个begin()和end()成员函数。
- container.begin()返回一个iterator,指向容器的第一个元素;
- container.end()返回一个iterator,指向容器的末元素的下一个位置。
/*一对iterator的定义,指向一个内含string元素的vector*/ vector<string> vec; vector<string>::iterator iter=vec.begin(); vector<string>::iterator iter_end=vec.end(); /*若我们希望从中间开始访问元素,则可进行标量算术运算*/ vector<string>::iterator iter=vec.begin()+vec.size()/2;//将iter指向中间元素
-
每种容器类型都提供一个rbegin( )和rend( )的成员函数,从末元素到首元素遍历容器的反向iterator。
//反向遍历一个vector,我们可以这么写 vector<type> vec0; vector<type>::reverse_iterator r_iter; for(r_iter=vec0.rbegin();//将r_iter绑定到末元素 r_iter!=vec0.rend();//不等于首元素的下一元素 r_iter++) //递减反向iterator一个元素 { /*........*/ }
-
**
注:标量算术运算只适用于vector和deque,list的元素由于不是连续存储的,因此不能用算术运算。
5、顺序容器操作
- 成员函数:push_back()、insert()、erase()
- push_back(参数)表示将参数插入到容器的最后一个位置
- insert()用法:
- 将一个元素插入到容器中:insert(参数1,参数2):参数1表示插入的位置,参数2是被插入的值;
- 将多个相同元素插入到容器中:insert(参数1,参数2,参数3):参数1表示位置,参数2表示插入的数量,参数3表示被插入的值;
- 将一段范围内的元素插入到容器中:insert(参数1,参数2,参数3):参数1表示位置,参数2表示插入元素的范围的首地址,参数3表示末地址。
- erase()用法:
- erase(被删元素的位置):删除容器中指定位置的元素;
- erase(被删元素范围的首地址,末地址):删除容器中指定范围的元素;
6、map关联容器
-
所需头文件:#include
-
定义形式:map<类型表示符1,类型标识符2> 对象名;
其中,类型表示符1:表示map对象的键的类型,且为map对象的索引;
类型标识符2:表示map对象的值的类型。
//例: map<string,int> word_count; //表示定义了map对象word_count,它由string作为索引,并拥有一个相关的int值。
-
给map对象赋值,加入键/值元素对:
-
通过一个map对象初始化另一个map对象:
//第一种方法:初始化时赋值 map<string,int> word_count1; map<string,int> word_count2(word_count1); /*第二种方法:初始化后赋值*/ map<string,int> word_count1; map<string,int> word_count2; word_count2.insert(word_count1.begin(),word_count1.end());
-
直接插入单个元素对的方法:
map<string,int> word_count; word_count.insert(map<string,int>::value_type (string("Anna"),1)); //注意:map<string,int>::value_type表示一个类型,所以也可改为以下形式: typedef map<string,int>::value_type valType; word_count.insert(valType(string("Anna"),1));
-
-
查找并获取map中的元素:有两种方法能够发现一个键元素是否存在:
//例: map<string,int> word_count; /*第一种方法:用count()函数查询,返回非0表示该元素存在*/ int count=0; if(word_count.count("wrinkles")) count=word_count["wrinkles"];//将键值索引“wrinkles”对应的值赋值给count /*第二种方法:用find()函数查询,如果不存在则返回等于end()的iterator,否则返回指向该键值索引的iterator*/ int count=0; map<string,int>::iterator it=word_count.find("wrinkles"); if(it!=word_count.end()) count=(*it).second;//将键值索引“wrinkles”对应的值赋值给count
-
从map中删除元素:用erase()函数进行删除,其有三种形式
- erase(参数1):参数1为一个键值或iterator,用于删除一个独立的元素;
- erase(参数1,参数2):参数1、参数2为一对iterator;用于删除一列元素;
7、set关联容器类型
-
所需头文件:#include
-
定义形式:set<类型标识符> 对象名;
//例: #include <set> set<string> exclusion_set;
-
给set对象赋值:
- 插入单个元素:exclusion_set.insert(“the”);
- 可以向insert()提供一对iterator来插入一个元素序列。
-
查询set对象中一个值是否存在用find( )和count( ):
- find( ):若元素存在,则find()返回指向这个元素的iterator,否则返回一个等于end()的iterator。
- cout( ):若元素存在,则count()返回非0值(具体看有几个相同元素存在),否则返回0。
-
set容器会自动排序和去重,排序函数可以由自己进行编写。
-
可以通过定义结构体(或类),并在其中重载()运算符,来自定义排序函数。然后,在定义set的时候,将结构体加入其中。
struct intComp { bool operator() (const int& lhs, const int& rhs) const{ return lhs > rhs; } }; int a[] = {10, 20, 30, 40, 50}; set<int, intComp> s1(a, a + 5);
-
8、multimap和multiset
-
所需头文件:#include
-
equal_range( )可以用来提供iterator对,第一个iterator指向该值的第一个位置,第二个iterator指向最后一个该值的下一个元素。(如果最后一个元素是末元素,则第二个iterator是end( ))
typedef multimap<string,string>::iterator iterator; pair<iterator,iterator> pos; /*pos.first指向第一个出现,pos.second指向值不再出现的位置*/ pos=authors.equal_range(search_item);
-
multimap不支持下标操作
9、栈
-
所需头文件:#include
-
栈容器支持的操作
操 作 功 能 empty( ) 如果栈为空,则返回true,否则返回false size( ) 返回栈中元素的个数 pop( ) 删除,但不返回栈顶元素 top( ) 返回,但不删除栈顶元素 push(item) 放入新的栈顶元素 -
定义形式:stack<类型标识符> 对象名;
//例: #include <stack> stack<int> intStack;//定义intStack为一个整型元素的空栈。
-
栈类型被称为容器适配器,我们可以在定义栈的时候定义第二个参数为某种顺序容器类型,缺省情况下默认顺序容器类型为deque。
//例 stack<int,list<int>> intStack;
-
同一类型的两个栈可以比较相等、不相等、大于、小于、小于等于以及大于等于的关系,栈中元素被依次比较,第一对不相等的元素决定了关系。
10、队列和优先级队列
-
标准库提供了两钟风格的队列:FIFO队列(称作queue,先入先出),priority_queue队列(优先级队列)
-
所需头文件:#include
-
priority_queue允许用户为队列中包含的元素项建立优先级。
-
队列和priority_queue支持的操作如下:
操 作 功 能 empty() 如果队列为空,则返回true,否则返回false size() 返回队列中元素的个数 pop() 删除,但不返回队首元素;在priority_queue中,队首元素代表优先级最高的元素 front() 返回,但不删除队首元素。只能应用在一般队列上 back() 返回,但不删除队尾元素。只能应用在一般队列上 top() 返回,但不删除priority_queue的优先级最高的元素。只能应用在priority_queue上 push(item) 在队尾放入一个新元素。对于priority_queue,将根据优先级排序 -
priority_queue的元素被强加了顺序关系,即优先级关系;在缺省情况下,元素的优先级由底层元素类型相关的小于操作符执行。(详情后面再说明)
11、list容器操作
-
list::merge( ):用第二个有序的list合并一个有序的list。
- 根据底层元素类型的小于操作符或用户指定的比较操作,合并两个已经排序的list的元素(注意调用merge()时,rhs的元素被移到list对象中,在该操作后,rhs是空的)。
void list::merge(list rhs);//根据底层元素类型的小于操作符排序的list template <class Compare> void list::merge(list rhs,Compare comp);//根据用户指定的比较操作排序后的list //例 int array1[10]={34,0,8,3,1,133,2,5,21,1}; int array2[5]={377,89,233,55,144}; list<int> ilist1(array1,array1+10); list<int> ilist2(array2,array2+5); //merge要求两个list已经排序 ilist1.sort(); ilist2.sort(); //应用merge()后,ilist2是空的,ilist1含有升序的前15个元素 ilist1.merge(ilist2);
-
list::remove( ):删除等于某个值的元素
- remove()操作删除指定值的全部实例;
void list::remove(const elemType &value); //例 ilist1.remove(1);
-
list::remove_if( ):删除满足某个条件的元素
- remove_if( )操作删除所有满足指定条件为真的元素;
template <class Predicate> void list::remove_if(Predicate pred); //例 class Even{ public: bool operator()(int elem){return !(elem%2);} }; ilist1.remove_if(Even());//删除ilist1中的所有偶数元素
-
list::reverse( ):将list中元素反向排列
- reverse()操作反向排列list元素;
void list::reverse(); //例 ilist1.reverse();
-
list::sort( ):排序list的元素
- 参数缺省情况下,sort()操作根据底层元素类型的小于操作符以升序放置list元素;也可以将一个替换的比较操作符指定为实参。
void list::sort(); template <class Compare> void list::sort(Compare comp); //例 ilist1.sort();//缺省情况,以底层元素类型的小于操作符以升序排列 ilist1.sort(greater<int>());//用大于操作符以降序排列
-
list::splice( ):把一个list的元素移到另一个list中
- 把一个list的全部元素搬移到另一个中去;
- 把一个list中包含的一组元素搬移到另一个中去;
- 把一个list中的单个元素搬移到另一个中去;
oid list::splice(iterator pos,list rhs);//pos:插入位置,rhs:移出元素的list void list::splice(iterator pos,list rhs,iterator ix);//pos:插入位置,rhs:移出元素的list,ix:要移动的rhs中的一个元素的iterator void list::splice(iterator pos,list rhs,iterator first,iterator last);//pos:插入位置,rhs:移出元素的list,first(last):iterator要移动的rhs中的一组元素的首(末)位置 /*以上三种形式都给出了一个指出插入一个或一组元素的位置的iterator,即pos*/ //例 int array[10]={0,1,2,3,4,5,6,7,8,9}; list<int> ilist1(array,array+10); list<int> ilist2(array,array+2);//包含0和1 /*将一个元素从一个list移到另一个list*/ ilist2.splice(ilist2.end(),ilist1,ilist1.begin());//将ilist1的第一个元素移到ilist2中,此时ilist1中不在包含0,ilist2中包含元素0,1,0 /*将一组元素从一个list移到另一个list*/ list<int>::iterator first,last; first=ilist1.find(2); last=ilist1.find(6); ilist2.splice(ilist2.begin;ilist1,first,last);//此时,元素2,3,4,5被从ilist1移到ilist2的前部,现在ilist1中:0,1,6,7,8,9; /*将一个list的全部元素移到另一个list*/ ilist2.splice(ilist2.end(),ilist1);//此时ilist1为空
-
list::unique( ):删除某个相邻的连续重复元素
- 在参数缺省时,使用底层类型的等于操作符;也可以用一个替换的比较操作符作为实参;
void list::unique(); template <typename BinaryPredicate> void list::unique(BinaryPredicate); //例 ilist.unique();//缺省参数,使用底层类型的等于操作符 class EvenPaie{ public: bool operator()(int val1,int val2) { return !(val2%val1); } }; ilist.unique(EvenPair());//用EvenPair()比较操作符作为实参
第四章------函数
1、函数的参数表
-
重载函数:两个函数可能同名,但是参数表不同。(参数表成为函数的符号特征,被用来区分函数的不同实例)
-
引用和指针的关系:
- 区别:引用必须被初始化指向一个对象,一旦初始化后就不能再指向其他对象;指针可以指向一系列不同的对象也可以什么都不指向。
- 若一个参数可能在函数中指向不同的对象,或者该参数可能不指向任何对象,则必须使用指针参数。
-
缺省实参
-
调用包含缺省实参的函数时,我们如果提供了实参,则它将覆盖缺省的实参值;否则,函数将使用缺省实参值。
//例如: char *screenInit(int height=24,int width=80,char background=' ');//包含缺省实参函数的声明 //各种调用形式 char *cursor; cursor=screenInit();//缺省实参,函数使用缺省的实参值;等价于screenInit(24,80,' '); cursor=screenInit(66);//缺省部分实参,等价于screenInit(66,80,' '); cursor=screenInit(66,256);//缺省部分实参,等价于screenInit(66,256,' '); cursor=screenInit(66,256,'#');//提供全部实参,覆盖缺省的实参值;
-
函数调用的实参按位置解析。
-
函数声明可以为全部或部分参数指定缺省实参。在左边参数的任何缺省实参被提供之前,最右边未初始化参数必须被提供缺省实参。
//example: char *screenInit(int height=24,int width,char background=' ');//错误,在指定height前,width必须有一个缺省实参。
-
一个参数只能在一个文件中被指定一次缺省实参。
//例: //ff.h头文件中声明一次 int ff(int = 0); //ff.c中定义一次 #include "ff.h" int ff(int i=0){...}//error,缺省实参被指定两次
-
2、函数的返回值
-
缺省情况下,函数的返回值是按值传递的。(当返回值是大型类对象是,按值传递由于需要先拷贝再传递,所以效率低)
//例: Matrix gow(Matrix* p) { Matrix val; return val;//缺省,按值传递 }
-
非缺省情况下,函数可以被声明为返回一个指针或一个引用。当返回一个引用时,调用函数接收val的左值,即调用函数可以修改val或取它的地址。
//例 Matrix& grow(Matrix* p) { Matrix *res; return *res; }
-
若返回值是一个大型类对象,用引用(或指针)返回类型比按值返回类对象效率要高得多
3、inline函数
-
定义:若一个函数被指定为inline函数,则它将在程序中每个调用点上被“内联地”展开。
//例: /*定义一个内联函数*/ inline int min(int v1,int v2) { return (v1<v2?v1:v2); } /*调用*/ int minVal=min(i,j); //在编译是上式被展开为int minVal=i<j?i:j;
-
在函数声明或定义中的函数返回类型前加上关键字inline,即可把该函数定义为内联函数。
4、链接指示符—external “C”
-
作用:告诉编译器,该函数使用其他的程序设计语言编写的。
-
两种形式:
-
单一语句:由关键字extern后跟一个字符串常量以及一个“普通”的函数声明构成。
//例: extern "C" void exit(int);//表示exit是用C语言编写的函数
-
复合语句:多个函数声明用花括号包含在链接指示符复合语句中。
//例 extern "C" { int printf(const char*...); int scanf(const char*...); }//表示这两个函数都是由C语言编写的 extern "C" { #include <cmath> }//表示这个头文件中声明的函数都是C语言编写的
-
-
链接指示符不能出现在函数体中。
5、指向函数的指针
-
int (*pf) (const string &,const string &);声明了pf是一个指向函数的指针。
-
初始化和赋值
-
当一个函数名没有被调用操作符修饰时,会被解释成指向该类型函数的指针;将取值操作符作用在函数名上也能产生指向该函数的指针。
int lexicoCompare(const string &,const string &); //lexicoCompare和&lexicoCompare表示指向该函数的指针int (*)(const string &,const string &)。
-
指向函数的指针初始化:
int (*pfi)(const string &,const string &)=lexicoCompare; int (*pfi2)(const string &,const string &)=&lexicoCompare; //或者如下被赋值 pfi=lexicoCompare; pfi2=pfi;
-
只有当赋值操作符左边指针的参数表和返回类型与右边函数或指针的参数表和返回类型完全匹配时,初始化和赋值才是正确的。
-
函数指针可以用0来初始化或赋值,以表示该指针不指向任何函数。
-
-
调用
-
指向函数的指针可以被用来调用它所指向的函数。调用函数时,不需要解引用操作符。无论是用函数名直接调用函数,还是用指针间接调用函数,两者写法一致。
#include <iostream> int min(int *ia,int sz) { int minVal=ia[0]; for(int ix=1;ix<sz;ix++) if(minVal>ia[ix]) minVal=ia[ix]; return minVal; } int (*pf)(int *,int)=min;//pf为指向函数min的指针 int main() { ;//函数体 } /*调用1*/ pf(ia,iaSize); /*调用2*/ (*pf)(ia,iaSize);
-
-
函数指针的数组
-
声明一个函数指针的数组:int (*testCases[10])( );将testCases声明为一个拥有10个元素的数组,每个元素都是一个指向函数的函数指针。
int (*testCases[10])();// 1 typedef int (*PFV)(); PFV testCases[10];// 2 //1和2两个表达式等价。
-
初始化:用一个初始化列表来初始化,表中每个初始值都代表了一个与数组元素类型相同的函数。
//例 int lexicoCompare(const string &,const string &); int sizeCompare(const string &,const string &); int (*testCases[2])(const string &,const string &)= { lexicoCompare, sizeCompare };
-
调用数组中的函数的方法:testCases[ i ];i 为数组中函数的索引。
-
第五章------域和生命期
1、全局对象和函数
-
在全局域中定义的对象,如果没有指定显式的初始值,则该存储区被初始化为0;
-
extern声明不会引起内存分配,若一个对象没有在当前的文件中定义,而在当前程序的其他文件中定义了,则我们就可以在当前文件中声明该对象。(当需要声明的对象是一个全局对象时,我们可以将声明包含在头文件中,然后引用该头文件即可)
- extern int ix = 1024;这是一个定义,而不是一个声明,因此会分配内存空间。
-
头文件:头文件中不应该含有非inline的函数或对象的定义;但可以含有符号常量对象和inline函数,因为它们可以被定义多次。
-
最好把常量的初始化移到某一个程序文本文件中。
//-----头文件------- const int buf_chhunk=1024; extern char *const bufp; //------程序文本文件--------- char *const bufp=new char[buf_chunk]; //若bufp在头文件中被初始化,那么它将在每个包含它的文件中被定义,这会浪费空间。
-
2、局部对象
三种局部对象:自动对象、寄存器对象、局部静态对象
-
自动对象:所在存储区从声明它的函数被调用开始,一直到该函数结束为止。
-
由于与自动对象相关联的存储区在函数结束是被释放,所以自动对象的地址不应该被用作函数的返回值,因为函数一旦结束了,该地址就指向了一个无效的存储区。
//例 #include "Matrix.h" Matrix* trouble(Matrix *pm) { Matrix res; ;// return &res;//对象res的存储区在trouble()完成是被释放。 }
-
解决方案:把局部对象声明为static。
-
-
寄存器对象:支持对其值的快速存取。
-
局部静态对象:所在存储区在该程序的整个执行期间一直存在。
- 静态局部对象的值在函数调用之间保持有效,但其名字的可视性仍限制在其局部域内。
- 未经初始化的静态局部对象会被程序自动初始化为0。
3、动态分配的对象
定义:允许程序员完全控制它的分配与释放;被分配在程序的空闲存储区的可用内存池中;程序员用new表达式创建动态分配的对象。
-
new表达式:
-
形式:new 类型标识符;例 new int;表示从空闲存储区分配了一个int对象。
-
空闲存储区中分配的对象没有名字,new表达式返回的是指向该对象的指针,对该对象的所有操作通过该指针完成。
-
空闲存储区的内存是未初始化的,它是程序运行前该内存上次被使用留下的结果。
-
new表达式的初始化,在其后加一个括号表示初始值。
//例 int *pi=new int(0);//表示pi指向一个int对象,该对象值为0。 /*关于pi和pi指向对象的生命期: 1、指针pi本身是一个在全局域中生命的全局对象,所以pi是一个全局指针,指向一个动态分配的int型对象 2、pi指向的对象是在new表达式后才被创建的,当程序运行时遇到delete时,pi指向的内存就被释放了,但是指针pi的内存及其内容并没有收到delete的影响,此时pi就称作空悬指针,即指向无效内存的指针。 3、空悬指针是程序错误的一个根源,我们应该在指针指向的对象被释放后,将该指针设置为0。*/
-
空闲存储区的资源是有限的,当new表达式不能得到要求的内存,通常会抛出一个bad_alloc异常。
-
-
delete表达式:
- 形式:delete new产生的指针;例 delete pi;释放了pi指向的内存。
-
auto_ptr:
-
auto_ptr对象被初始化为指向由new表达式创建的动态分配对象;当auto_ptr对象的生命期结束时,动态分配的对象被自动释放;
-
所需头文件:#include
-
auto_ptr对象的定义形式:
-
auto_ptr<类型标识符> 对象名( new 表达式 );
-
auto_ptr<类型标识符> 对象名( auto_ptr对象名 ):用另一个auto_ptr对象初始化当前auto_ptr对象,此时后者指向“前者指向的对象“,前者则不再指向指向原对象。
-
auto_ptr<类型标识符> 对象名;
//例: /*第一种形式:*/ auto_ptr<int> pi(new int(1024));//pi被初始化为由new表达式创建的对象的地址,且该对象初始化为1024 /*第二种形式:*/ auto_ptr<string> pstr_auto(new string("Brontosaurus")); auto_ptr<string>pstr_auto2(pstr_auto);//用另一个auto_ptr对象pstr_auto初始化当前auto_ptr对象pstr_auto2,此时pstr_auto2指向“pstr_auto指向的对象“,而auto_pstr不再指向指向原对象。 /*与第二种形式类似的情况:*/ auto_ptr<int> p1(new int(1024)); auto_ptr<int> p2(new int(2048)); p1=p2;//在赋值之前,p1指向的对象被删除;赋值之后,p1拥有int型auto_ptr对象,该对象值为2048;p2不再被用来指向该对象。 /*第三种形式:未初始化*/ auto_ptr<int> p_auto_int;//没有初始化指向一个对象,所以其内部指针值被设置为0;
-
-
auto_ptr对象的成员函数:get()、reset()
-
get()函数可以返回auto_ptr对象的内部的底层指针,判断该对象是否指向了一个对象;
-
reset()函数可以设置一个auto_ptr对象的指针。
//例: auto_ptr<int> p_auto_int; if(p_auto_int.get()==0)//判断p_auto_int是否指向了底层对象 { p_auto_int.reset(new int(1024));//若p_auto_int未指向任何对象,则设置一个对象给它。 }
- 不能再auto_ptr对象被定义后,再用new表达式创建对象的地址来直接向其赋值。
//例 auto_ptr<int> pi; pi=new int(5);//错误
- 为了重置一个auto_ptr对象,我们必须使用reset()函数;我们可以向reset()传递一个指针。若不希望设置该auto_ptr对象的话,可以传递一个0值。
//例 auto_ptr<string> pstr_auto(new string("Brontosaurus")); //在重置之前,首先会删除pstr_auto指向的对象"Bront...."; pstr_auto.reset(new string("Long-neck")); /*由于重置之后仍是string类型,所以我们可以用assign()函数对原对象重新赋值:*/ pstr_auto->assign("Long-neck");
-
-
使用auto_ptr对象时需要注意:
-
不能用一个指向"内存不是通过应用new表达式分配的"指针来初始化或赋值auto_ptr对象。
-
不能让两个auto_ptr对象拥有空闲存储区内同一对象的所有权。有两种犯该错误的情况:
//第一种情况是用同一个指针初始化或赋值两个auto_ptr对象 //第二种情况是通过使用get()操作。 auto_ptr<string> pstr_auto(new string("Brontosaurus")); auto_ptr<string> pstr_auto2(pstr_auto.get());//错误 /*release()操作允许将一个auto_ptr对象的底层对象初始化或赋值给第二个对象,而不会是两个auto_ptr对象同时拥有同一对象的所有权。release()返回底层对象的地址,同时释放了该对象的所有权。*/ auto_ptr<string> pstr_auto2(pstr_auto.release());//正确
-
-
-
数组的动态分配与释放:
-
数组分配形式:new表达式后必须有一对方括号,里面的维数是数组的长度,返回指向数组的第一个元素的指针。
int *pi=new int[1024];//分配一个含有1024个元素的数组,pi指向数组的第一个元素 int (*pia)[1024]=new int[4][1024];//分配一个含有4*1024个元素的二维数组,pia指向一个由四个1024个元素的数组的第一个元素----即pia指向一个有1024个元素的数组。
-
一般的,在空闲存储区上分配的数组不能给出初始化集;我们只能通过for循环一个一个的初始化。
-
由new表达式分配的数组的维数(只有第一维)可以被指定为一个在运行时刻才被计算出来的值(即不需要是一个常量);但是第一维不能省略不写。
-
用来释放数组的表达式:
int *pi=new int[1024]; delete[] pi;
-
-
常量对象的动态分配与释放:
-
使用new表达式在空闲存储区内创建一个const对象;如下
const int *pci=new const int(1024);
-
const对象必须初始化;用new表达式返回的值作为初始值的指针必须是一个指向const类型的指针。
-
该const对象仍可以用delete操作来释放。
-
-
定位new表达式:
-
定义:通过new表达式将对象创建在已经被分配好的内存中。
-
所需头文件:#include
-
形式:new (待创建对象所在的内存地址) 新对象;
//例 #include <new> class Foo{ public: ;// private: ;// }; char *buf=new char[sizeof(Foo)*16]; Foo *pb=new(buf) Foo;//在buf中创建一个Foo对象;pb指向该对象。 delete[] buf;//释放buf指向的内存
-
因为定位new表达式不分配内存,所以没有与之匹配的delete表达式。
-
4、名字空间定义
-
定义:以关键字namespace开头,后面是名字空间的名字,接着是由花括号括起来的声明块。
//例 namespace cplusplus_primer{ class matrix{/*.......*/}; void inverse(matrix &); matrix operator+(const matrix &m1,const matrix &m2){/*.......*/} const double pi=3.1416; }
- 名字空间cplusplus_primer中的类的调用方式:cplusplus_primer::matrix;
- 名字空间cplusplus_primer中的函数的调用方式:cplusplus_primer::inverse();
- 名字空间cplusplus_primer中的常量的调用方式:cplusplus_primer::pi;
-
名字空间定义不一定是连续的,而是可累积的。
//例 namespace cplusplus_primer{ class matrix{/*.......*/}; void inverse(matrix &); } namespace cplusplus_primer{ matrix operator+(const matrix &m1,const matrix &m2){/*.......*/} const double pi=3.1416; }
-
域操作符(::):名字空间后面加上域操作符,再加上成员名。
-
在名字空间定义之外定义名字空间成员:
//----------primer.h------------ namespace cplusplus_primer{ namespace MatrixLib{ class matrix{/*......*/}; const double pi=3.1416; matrix operator+(const matrix &m1,const matrix &m2); void inverse(matrix &); } } //若我们在名字空间定义之外定义operator+()函数,则可以如下定义: #include "primer.h" cplusplus_primer::MatrixLib::matrix cplusplus_primer::MatrixLib::operator+(const matrix &m1,const matrix &m2) { /*........*/; }
-
未命名的名字空间
- 定义:以关键字namespace开头,后面接花括号包含声明块。
- 未命名的名字空间成员只在当前文件中可见,且调用时不用加与操作符。
5、使用名字空间成员
-
名字空间别名:以关键字namespace开头,后面跟一个较短的别名,然后是赋值操作符,最后是原来的名字空间名。
//例 namespace International_Business_Machines { /*....*/; } namespace IBM=International_Business_Machines;//定义一个别名IBM;
-
using声明:通过是名字空间成员的名字可见,来在程序中用该名字的非限定修饰方式引用这个成员,而不用前缀的与操作符“::”(用户不能再using声明中为一个函数指定参数表)。
//例 namespace cplus_primer{ namespace MatrixLib{ class matrix{/*...*/}; //.... } } using cplus_primer::MatrixLib::matrix;//使得成员matrix的名字可见,后面定义matrix类的对象就可以直接用matrix而不用加限定修饰符 matrix m1;//若没有上一句using,则该定义须写成:cplus_primer::MatrixLib::matrix m1;
-
using指示符:以关键字using开头,后面是关键字namespace,然后是名字空间名。using指示符允许我们让来自特定名字空间的所有名字的简短形式都可见,即这些成员都是可以被直接使用。
//例 //----------primer.h------------ namespace cplusplus_primer{ class matrix{/*......*/}; const double pi=3.1416; matrix operator+(const matrix &m1,const matrix &m2); void inverse(matrix &); } //---------user.c----------- #include "primer.h" using namespace cplusplus_primer;//使得cplusplus_primer中的所有成员变成可见的 matrix operator+(const matrix &m1,const matrix &m2) { /*.......*/; }
补充:
-
isalpha(): 如果参数是一个英文字母,则返回值为true。 头文件为:#include <ctype.h>
-
cin在输入时会略过空格符,我们可以用cin的成员函数cin.get(ch)读取ch中的空格符
注:cin.get( )是用来获取当前输入的字符,可以用来判断是否按下回车。
while(1) { cin>>a[i++]; if(cin.get()=='\n') break; }
-
cin.putback(ch):将刚刚读取字符放回到输入流ch中,下一次读取仍然读取到这个字符。
-
case后必须为整数值常量表达式:
- const int ival=10; case ival: 是正确的
- enum{ival=1,dval,cval}; case dval: 是正确的
-
两个string对象进行比较,是从左往右比较每一个字符的ASCII码的大小,直到遇到第一个不同的字符就结束。
-
goto语句不能向前跳过没有被语句块包围的声明语句。
-
vector,list的成员函数 push_back() 在其最后添加一个元素(参数为要插入的值),而push_front( )表示在其开始插入元素(参数为要插入的值)
-
substr()操作生成现有的string对象的字串的拷贝。其第一个参数指明开始的位置,第二个可选的参数指明字串的长度(若省略第二个参数,将拷贝字符串的余下部分)。
//第8点例子: string textline;//假设textline为一个已知的字符串 string words; words=textline.substr();//括号中填位置,长度信息c
-
rfind( )函数:查找最后(即最右)的指定字串的出现,返回最后出现指定字串的索引值。
//例: string river("Mississippi"); string::size_type first_pos=river.find("is"); string::size_type last_pos=river.rfind("is"); //find()返回索引值1,rfind返回索引值4
-
find()返回被查找元素在容器中的位置,若查询失败则返回string::nops。(字符串对象的成员函数)
- 基本形式:find(查找范围首地址,末地址,被查找元素)
-
find_first_of( )函数:查找与被搜索字符串中任意一个字符相匹配的第一次出现,返回其索引位置。(字符串对象的成员函数)
- 假设被查找容器为vec,vec.find_first_of(被搜索字符串);
- 假设被查找容器为vec,vec.find_first_of(被搜索字符串,起始查找位置);
-
find_first_not_of( )函数:查找第一个不与被搜索字符串的任意字符相匹配的字符,返回其索引位置。(字符串对象的成员函数)
-
erase()在在字符串中的用法:
- 对象名.erase(参数1,参数2):参数1指定要删除字符的位置,参数2指定删除个数。(若第二个参数缺省,则将会删除后面所有字符)
-
tolower( )函数:
- 作用:接受一个大写字母作为参数,并返回与之等价的小写字母。
- 头文件:#include <ctype.h>
-
replace()函数:
-
作用:用一个或多个替换字符来替换字符串中的一个或多个字符。
-
格式:有很多,我只列了一种格式
replace(参数1,参数2,参数3);其中
参数1:开始位置, 参数2:被替换字符串的长度, 参数3:新的字符串
-
-
compare()函数:
-
作用:比较两个字符串是否相同,相同则返回0。
-
格式:string对象1.compare(string对象2);
-
返回值:若对象1大于对象2,返回一个正值;
若对象1小于对象2,返回一个负值;
若对象2等于对象2,返回一个0。
-
-
assign( )和append( )函数:
-
assign(参数1,参数2,参数3)函数可以顺次的把一个string对象的部分字符串拷贝到另一个string对象上。
参数1:被拷贝的string对象
参数2:拷贝的起始位置
参数3:拷贝的长度
-
append( )函数可以顺次的将一个string对象连接到另一个string对象。
//例: string s1("Mississippi"); string s2("Annabelle"); string s3; //拷贝s1的前4个字符 s3.assign(s1,0,4);//此时s3的值为“Miss” //连接s2的前4个字符 s3+=' '; s3.append(s2,0,4);//此时s3的值为“Miss Anna”
-
-
copy( )函数:
- copy(参数1,参数2,参数3):前两个参数是iterator或者指针,标记了要拷贝元素的范围;第三个元素是iterator或指针,指向目标容器中这些元素要被放置的起始处。
-
*声明:int &v1;的含义:从右往左读,v1是一个引用,它引用一个指针,指针指向int型的对象。
-
getline()的原型是istream& getline ( istream &is , string &str , char delim );
- 其中 istream &is 表示一个输入流,譬如cin;string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为’\n’,也就是回车换行符(遇到回车停止读入)。
-
const容器只能被绑定在const iterator上。
-
**strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1==str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。 **
-
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行
-
全局域解析操作符是“ :: ”
-
二维数组可以用一维vector数组表示,每一个vector是一个向量容器。且vector向量可以push_back()向后插入 元素。
-
memset(数组名,value,数组字节数);将数组的每一个元素初始化为value;value只能为0或-1。
-
一个字符串s 可以通过sort(s.begin(),s.end())进行排序,按字典序排序。也可以用自己写的cmp排序规则进行排序,将cmp传入参数即可。需要头文件:#include
-
#inlcude <> 首先 只搜索系统目录,不会搜索本地目录.比如你自己写一个头文件,你用#include <>会出错.
#inlude ""首先搜索本地目录,如果本地目录没有才会搜索系统目录.
对象1大于对象2,返回一个正值;
若对象1小于对象2,返回一个负值;
若对象2等于对象2,返回一个0。
-
assign( )和append( )函数:
-
assign(参数1,参数2,参数3)函数可以顺次的把一个string对象的部分字符串拷贝到另一个string对象上。
参数1:被拷贝的string对象
参数2:拷贝的起始位置
参数3:拷贝的长度
-
append( )函数可以顺次的将一个string对象连接到另一个string对象。
//例: string s1("Mississippi"); string s2("Annabelle"); string s3; //拷贝s1的前4个字符 s3.assign(s1,0,4);//此时s3的值为“Miss” //连接s2的前4个字符 s3+=' '; s3.append(s2,0,4);//此时s3的值为“Miss Anna”
-
-
copy( )函数:
- copy(参数1,参数2,参数3):前两个参数是iterator或者指针,标记了要拷贝元素的范围;第三个元素是iterator或指针,指向目标容器中这些元素要被放置的起始处。
-
*声明:int &v1;的含义:从右往左读,v1是一个引用,它引用一个指针,指针指向int型的对象。
-
getline()的原型是istream& getline ( istream &is , string &str , char delim );
- 其中 istream &is 表示一个输入流,譬如cin;string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为’\n’,也就是回车换行符(遇到回车停止读入)。
-
const容器只能被绑定在const iterator上。
-
**strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1==str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。 **
-
assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行
-
全局域解析操作符是“ :: ”
-
二维数组可以用一维vector数组表示,每一个vector是一个向量容器。且vector向量可以push_back()向后插入 元素。
-
memset(数组名,value,数组字节数);将数组的每一个元素初始化为value;value只能为0或-1。
-
一个字符串s 可以通过sort(s.begin(),s.end())进行排序,按字典序排序。也可以用自己写的cmp排序规则进行排序,将cmp传入参数即可。需要头文件:#include
-
#inlcude <> 首先 只搜索系统目录,不会搜索本地目录.比如你自己写一个头文件,你用#include <>会出错.
#inlude ""首先搜索本地目录,如果本地目录没有才会搜索系统目录.