一.命名空间的using声明
std::cin的意思是使用命名空间std中的名字cin,这种方式很繁琐,使用using声明(最安全的方法),无须专门的前缀,也能使用所需的名字,形式:using namespace::name;(main函数之前声明);每个名字都需要独立的using声明,可以一行放多条using声明,之间用分号;隔开.
头文件不应包含using声明:头文件的内容会被拷贝到所有引用它的文件中
二.标准库类型string
1.string表示可变长的字符序列,使用string类型必须首先包含string头文件即"using std::string;"
2.定义和初始化string对象
string s1 | 默认初始化,s1是一个空串 |
string s2(s1) | s2是s1的副本 |
string s2=s1 | 等价于s2(s1) |
string s3("value") | s3是字面值“value”的副本(除了字面值最后的那个空字符外) |
string s4(n,'c') | 把s4初始化为由连续n个字符c组成的字符串 |
直接初始化和拷贝初始化:使用等号(=)初始化一个变量是拷贝初始化,反之不使用等号是直接初始化;
2.string对象上的操作:一个类除了要规定其对象的方式外还要定义对象上所能执行的操作。
os<<s | 将s写到输出流os当中,返回os |
is>>s | 从is中读取字符串赋给s,字符串以空白分隔,返回is |
getline(is,s) | 从is中读取一行赋给s,返回is |
s.empty() | s为空返回ture,否则返回false |
s.size() | 返回s中字符个数 |
s[n] | 返回s中第n个字符的引用,位置从0计起 |
s1+s2 | 返回s1和s2连接后的结果 |
s1=s2 | 用s2的副本代替s1中原来的字符 |
s1==s2 | 判断s1和s2中字符是否完全一样,若完全相等返回true,否则返回false(大小写敏感) |
s1!=s2 | 同理,不相等返回true,否则返回false |
<,<=,>,>= | 类似 |
<1>string对象会自动忽略开头的空白并从第一个真正的字符开始读起,直到遇到下一处空白为止。eg:若程序输入"hello world",则输出将是"hello"(string s ;cin>>s;cout<<s<<endl;);string对象的输入输出操作和内置类型一样,返回运算符左侧的运算对象作为其结果,故可以多个输入或输出连写eg:输入“ hello world ”,输出将是"helloworld”;(string s1,s2;cin>>s1>>s2;cout<<s1<<s2<<endl;)<2>getline函数:参数是一个输入流和一个string对象,函数从给定的输入流中读取内容直到遇到换行符为止(换行符也被读进来但是实际上被丢弃了,一遇换行符就结束),然后将所读内容存入的string对象(没有换行符);若输入的一开始就是换行符,则所得结果是空string。 <3>size函数:size函数返回的是string::size_type类型的值,是一个无符号类型的值(无符号整型数:若一条表达式里有size函数就不要使用int,避免混淆),且足够存放任何string对象的大小。<4>string对象的比较:长度不同的:若短的和长的每个对于位置的字符相同则长的大;其余情况:从第一个位置开始比较,第一对相异字符中大的那个字符所在字符串大; <5>字面值和string对象相加:必须确保每个运算符的两侧的运算对象至少一个是string,不能把字面值直接相加,字符串字面值与string是不同的类型(eg: string s1=“hello” ;string s2=s1+",";(正确) string s3="hello"+",";(错误))
3.处理string对象中的字符
在cctype头文件中定义了一组标准库函数处理字符
isalnum(c) | 当c是字母或数字时为真 |
isalpha(c) | 当c是字母或数字时为真 |
iscntrl(c) | 当c是字母时为真 |
isdigit(c) | 当c是数字时为真 |
isgraph(c) | 当c不是空格但可打印时为真 |
islower(c) | 当c是小写字母时为真 |
isupper(c) | 当c是大写字母时为真 |
isprint(c) | 当c是可打印字符时为真(c是空格或c具有可视形式) |
ispunct(c) | 当c是标点符号时为真 |
isspace(c) | 当c是空白时为真(即c是空格、回车符、换行符、制表符、进纸符的一种) |
isxdigit(c) | 当c是十六进制数字时为真 |
tolower(c) | 若c是大写字母,输出对应的小写字母;否则原样输出 |
toupper(c) | 若c是小写字母,输出对应的大写字母;否则原样输出 |
<1>使用基于范围的for语句:for(declaration:expression)
statement expression部分是一个对象,用以表示一个序列,declaration部分负者定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,declaration部分的变量将会化为expression部分的下一个元素值。eg: string s("hellow world!!!"); decltype(s.size()) punct_cnt=0; //punct_cnt类型和s.size返回类型一样 for(auto c:s)//使用auto让编译器决定c的数据类型,对于s中的每个字符 if(ispunct(c)) ++punct_cnt; cout<<punct_cnt<<"punctuation characters in"<<s<<endl; 输出结果是:3 punctuation characters in hello world!!!
若想改变string对象中字符的值需把循环变量定义成引用类型eg:for(auto &c:s) c=toupper(c);//c是一个引用,故此赋值语句会改变c中字符的值,实际改变c绑定的字符的值即s中字符的值
<2>访问string对象中的单个字符: 1.使用下标:下标运算符接收的输入参数是string::size_type类型的值,下标从0开始计,不能超过范围,下标的值称为"索引"或"下标"(hexdigits="0123456789ABCDEF",result+=hexdigits[n]//十进制n转换为16进制数) 2.使用迭代器
三.标准库类型vector(容器)
1.vector:表示对象的集合,其中所有对象的类型都相同,因为vector容纳‘其他对象’,常称为容器
2.使用要求包含适当头文件:#include<vector> using std::vector c++既有类模板又有函数模板,vector是一个类模板,模板本身不是类或函数,可看作为编译器生成类或函数编写的一份说明;编译器根据模板创建类或函数的过程称为实例化 ,使用模板时需指出编译器把类或函数实例化为何种类型(eg:vector<int>ivec //ivec保存int类型的对象);引用不是对象故不存在包含引用的vector,vector生成的类型必须包含vector 中元素的类型
3. 定义和初始化vector对象
vector<T> v1 | v1是一个空vctor,潜在元素是T类型,执行默认初始化 |
vector<T> v2(v1) | v2中包含有v1所有元素的副本 |
vector<T> v2=v1 | 等价于v2(v1) |
vector<T> v3(n,val) | v3包含n个重复的元素,每个元素的值都是val |
vector<T> v4(n) | v4包含n个重复地执行了值初始化的对象 |
vector<T> v5{a,b,c...} | v5包含了初始值个数的元素,每个元素被赋予相应的初始值 |
vector<T> v5={a,b,c..} | 等价于v5{a,b,c...} |
允许把vector对象的元素拷贝个另一个,但对象的类型必须相同;若提供的是一个类内初始值,则只能使用拷贝初始化(=)或使用花括号的形式初始化;若提供的是初始元素值的列表,只能放在花括号里初始化 vector<int> v1(10); //v1中有10个元素每个的值都是0 vector<int>v1{10}; //v2有一个元素值为10 vector<string>v3{"hi"}; //列表初始化;v5有一个元素 vector<string>v4("hi"); //错误,不能用字符串字面值构建vector对象 vector<string> v5{10}; //v7有10个默认初始化的元素(使用花括号但提供的值不能列表初始化则构建vector对象)
4.向vector对象中添加元素(push_back)
直接初始化方式的三种情况:1.初始值已知且数量较少;2.初始值是另一个vector对象的副本;3.所有元素的初始值是一样; push_back负责把一个值当成vector对象的尾元素“压倒(push)”vector对象的“尾端(back)”。 循环体内部包含有向vector对象添加元素的语句,则不能使用外围for循环。
v.empty() | v中不含有任何元素返回真 |
v.size() | 返回v中元素的个数 |
v.push_back(t) | 向v中尾端添加一个值为t的元素 |
v[n] | 返回v中第n个位置上元素的引用 |
v1=v2 | 用v2中元素的拷贝替换v1中的元素 |
v1={a,b,c...} | 用列表中元素的拷贝替换v1中的元素 |
v1==v2 | v1和v2相等当且仅当元素数量相同且对应位置的元素值相同 |
v1!=v2 | |
<,<=,>,>= |
计算vector内对象的索引:vector对象的下标从0开始,元素值可比较时vector对象才可比较;两个整数相除,结果为整数,余数部分忽略;不能用下标形式添加元素即vector对象的下标运算符可用于访问已存在的元素而不能添加元素(ivec[ix]=ix;严重错误,ivec不包含任何元素)
四、迭代器
string、vector支持迭代器,string支持很多与容器类型类似的操作,vector支持下标运算符;
1.使用:有迭代器的类型同时拥有返回迭代器的成员,使用迭代器可访问某个元素;若两个迭代器指向的元素相同或都是同一个容器的尾后迭代器则它们相等,否则不等;所有标准容器的迭代器都定义了==和!=;大多数未定义<运算符
*iter | 返回迭代器iter所指元素的引用 |
iter->men等价于(*iter).men | 解引用iter并获取该元素名为men的成员(试图解引一个非法迭代器或尾后迭代器都是未被定义的行为) |
++iter | 令iter指向容器的上一个元素(end返回的迭代器并不实际指向某个元素故不能递增或解引用) |
--iter | 令iter指向容器的下一个元素 |
iter1==iter2 | 判断两个迭代器是否相等 |
iter1!=iter2 |
eg: auto b=v.begin(),e=v.end();//b和e类型相同,b表示v的第一个元素,e表示v尾元素的下一个位置,这些类型都拥有begin和end的成员;(end成员返回的迭代器称为尾后迭代器简称尾迭代器)
2.迭代器类型:拥有迭代器的标准库类型使用iterator和const_iterator来表示迭代器类型;const_iterator能读取但不能修改其所指的元素值;若vector对象或string对象是个常量只能使用const_iterator;否则可使用iterator或const_iterator;
3.begin和end运算符:begin和end返回的具体类型由对象是否常量决定,常量返回const_iterator;不是常量返回iterator;cbegin和cend:不论vector对象是否为常量返回值都是const_iterator;标准库函数begin和end:定义在iterator头文件中与begin和end成员功能类似,将数组作为它们的参数eg:int ia[]={0,1,2...9};int *beg=begin(ia);int *last=end(ia);
4.某些对vector对象的操作会使迭代器失效:<1>不能在范围for循环中向vector对象添加元素<2>任何一种可能改变vector对象容量的操作都会使vector对象的迭代器失效(凡使用迭代器的循环体都不要向迭代器所属容器添加元素)
5.迭代器运算
iter+n | 仍得一个迭代器,迭代器指示的新位置与原来相比向前移动了若干个元素 |
iter-n | 仍得一个迭代器,迭代器指示的新位置与原来相比向后移动了若干个元素 |
iter1+=n | 将iter1加n的结果赋给iter1 |
iter1-=n | 将iter1减n的结果赋给iter1 |
iter1-iter2 | 两个迭代器相减的结果是它们之间的距离,类型名为difference_type的带符号整数型;参与运算的两个迭代器必须合法且必须指向同一个容器中的元素或尾元素的下一个位置 |
>、>=、<、<= | 若某个迭代器指向的容器位置在另一个迭代器之前。则说前者小于后者 |
eg:vector={a,b,c,d},iter1=a,iter2=b;iter1-iter2=-3,iter1<iter2(二分搜索即数据结构中的二分法)
五、数组
1.定义与初始化内置数组
定义:数组是存放类型相同的对象的容器,大小确定不变,不能随意向数组中增加元素;默认情况 下数组的元素被默认初始化,维度必须是常量表达式。不允许用auto关键字由初始值的列表推断类型,数组的元素应为对象,故不存在引用的数组;<1>显式初始化数组元素:维度比提供的初始值数量大,剩下元素被初始化为默认值<2>字符数组的特殊性:可用字符串字面值对字符数组初始化,字符串字面值的结尾处有空字符,空字符也会被拷贝到字符数组中<3>不允许拷贝和赋值:可用拷贝、赋值数组中某个元素<4>在很多用到数组名字的地方,编译器会自动将其替换为一个指向数组首元素的指针eg:string *p2=nums;//等价于P2=&nums[0];
2.访问数组元素:可使用范围for语句或下标运算符访问;索引从0开始;size_t:与机器相关的无符号类型,表示内存中任意对象的大小;数组用法与vector基本类似
3.指针与数组
使用数组时编译器一般会把它转换成指针;
<1>&:可用于任何对象,,对数组元素使用取地址符可得到指向该元素的指针;数字不能使用auto但数组作为指针可以(int ia[]={0,1,2,3,4,5,6,7,8,9};auto ia2(ia);//ia2是一个整型指针,指向ia的第一个元素即实际编译器执行的初始化为auto ia2(&ia[0]);
<2>使用decltype关键字市上述转换不发生即decltype(ia)返回的是由10个整数构成的数组
<3>指针也是迭代器:vector和string支持的运算数组的指针也全都支持
<4>指针运算:两个指针相减的结果是它们之间的距离,结果的类型是标注库类型ptrdiff_t,该类型也是定义在cstddef头文件中的带符号类型,两个空指针也允许相减,结果为0;内置的下标运算符所用的索引值不是无符号类型,可处理负值但结果地址必须指向原来指针所指同一数组中元素或同一数组尾元素的下一个位置eg:int *p=&ia[2];int k=p[-2];//p[-2]指向ia[0]表示的那个元素
4.C风格字符串
C风格字符串的函数(不负责验证其字符串参数) |
strlen(p) | 返回p的长度,空字符不计算在内 |
strcmp(p1,p2) | 比较p1和p2的相等性;若p1==p2返回0;p1>p2返回一个正值 |
strcat(p1,p2) | 将p2附加到p1之后返回p1 |
strcpy(p1,p2) | 将p2拷贝给p1,返回p1 |
传入此类函数的指针必须指向以空字符作为结束的数组;
5.混用string对象和C风格字符串
任何出现字符串字面值的地方都可用以空字符结束的字符数组替代:<1>允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值<2>在string对象的加法运算中允许使用以空字符结束的字符数组作为其中一个运算对象;在string对象的复合赋值运算中允许使用以空字符结束的字符数组作为右侧的运算对象(反过来不成立若某处需一个C风格字符串无法直接用string对象来替代)
string专门提供一个成员函数c_str:eg:char *str=s;//错误,不能用string对象初始化char*;const char *str=s.c_str();//正确;返回值是一个C风格的字符串即函数的返回结果是一个指针该指针指向一个以空字符结束的字符数组,结果指针的类型是const char*;若后续操作改变,s的值可能让之前返回的数组失去效用
允许使用数组来初始化vector对象,只需指明要拷贝区域的首元素地址和尾后地址vector<int>ivec(begin(int_arr),end(int_arr));//拷贝;vector<int>subVec(int_arr+1,int_arr+4);//三个元素创建了对象subVec,s三个元素值分别为int_arr[1]、int_arr[2]、int_arr[3]
六.多维数组
多维数组即数组的数组,当一个数组的元素仍是数组时,一个维度表示数组本身大小,另外一个维度表示其元素大小,一维称为行第二维称为列
1.多维数组的初始化:<1>int ia[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};<2>int ia[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};<3>int ia[3][4]={{0},{1},{2},{3}};//仅初始化每一行的第一个元素
2.多维数组的下标引用:可使用下标运算符来访问多维数组的元素,此时数组的每个维度对应一个下标运算符。若表达式含有的下标运算符数量比数组的维度小,则表达式的结果将是给定索引处的一个内层数组
3.使用范围for语句处理多维数组:size_t cnt=0; for(auto &row:ia) for(auto &col:row){col=cnt;++cnt;} //把控制变量row和col声明成引用类型,第一个for循环遍历ia的所有元素,这些元素是大小为4的数组故row的类型为含有4个整数的数组的引用;每次迭代把cnt的值赋值给ia的当前元素(因为要改变数组元素的值故引用类型,将外层循环的控制变量row设置为引用类型可避免数组被自动转成指针即row的类型是int*,内层循环就不合法了)
4.多维数组名转换得来的指针实际上是指向第一个内层数组的指针;使用auto或decltype能尽可能地避免在数组前面加上一个指针类型
目录