C++Primer 5th Chap3 Strings,Vectors, and Arrays
使用名字空间成员的简单方法:
using namespace ::name;例如:using std::cin;
头文件不应包含using声明
标准库类型string:(需要带有头文件#include<string>)
string对象的初始化方式:
string s1;(默认空字符串)
string s2=s1;
string s3="asfg";(拷贝初始化)(也可:string s3("asfg");直接初始化)
string s4(10,'x');(s4=="xxxxxxxxxx")
string的操作:
os<<s 将s写入输出流os中并返回os
is>>s 将is中字符串赋给s并返回is
getline(is,s)从is中读取一行赋给s并返回is
s.empty() 返回s是否为空
s.size() 返回s中字符个数
s[n] 返回s中下标为n的字符的引用,原理同数组
>,<,==,<=,>= 比较两字符串的“大小”,按字典顺序
使用cin,cout可以直接读写s对象,从第一个字符读起到第一个空白(即只能读取一个“单词”),如果希望完整读取:
string str;
while(cin>>str){
/*********/}
或者使用getline读取一整行(换行符未存进字符串对象):
string str;
while(getline(cin,str)){
/*********/}
注意:str.size()返回值类型为string::size_type类型,通过auto可以获取字符串长度:
auto len=str.size();
第一个相异字符决定两字符串"大小",若两字符串仅长度不一,则长的“大于”短的
注意:字符串字面值之间不可直接相加,‘+’两端至少有一项是string对象
cctype头文件中的字符处理函数:
char s;
isalnum(s); s是字母或数字为真
isalpha(s); s是字母时为真
iscntrl(s); s是控制字符是为真
isdigit(s); s是数字时为真
isgraph(s); s不是空格但是可以打印时为真
islower(s); s是小写字母时为真
isprint(s); s是可打印字符时为真
ispunct(s); s是标点符号时为真
isspace(s); s是空白时为真
isupper(s); s是大写字母时为真
isxdigit(s); s是十六进制数字时为真
tolower(s); 输出小写字母
toupper(s); 输出大写字母
范围for语句:(c++11)
类似Java的foreach语句,格式为: for(declarion:expression),其中expression是一组序列
std::string str("Hello World");
for(auto &c:str){(使用引用类型改变了string的值)
c=toupper(c);
std::cout<<c;}(c对应的就是序列中的元素)
标准库类型vector:
格式:vector<int>ivec;
vector<vector<int>>ivec_2d;(二维,c++11)
vector<vector<int> >ivec_2d;(二维,旧c++标准)
初始化格式:vector<T> v1;(空)
vector<T> v2(v1);(v2含v1的所有元素的副本,等价于vector<T>v2=v1;)
vector<T> v3(n,val);(与string类似,包含n个相同的元素)
vector<T> v4(n);(包含n个元素,但仅默认初始化)
vector<T> v5{a,b,c,.....};(直接初始化,等价于vector<T> v5={a,b,c,.....};)
对于列表初始化,按向量类型进行区分:
vector<string> vecstr1{10};(vecstr1有十个默认初始化的元素)
vector<string> vecstr2{10,"strings"}(vecstr2有十个元素"strings")
vector<string> vecstr3{"Mother","Fucker"};(vecstr3有两个元素”Mother“,”Fucker“)
添加元素:vector<int> v5;v5.push_back(i);(将元素i压入向量尾部)
注意:范围for语句的循环体内部不能包含向vector对象添加元素的语句(范围for语句的遍历序列大小应是固定的)
vector操作:v.empty();(判断是否为空)
v.size();(元素个数,返回类型vector<T>::size_type)
v.push_back(i);
v[n];
<,>,<=,>=,==,!=(按字典顺序比较)
vector的下标只能访问元素而不能添加元素
迭代器iterator
auto b=v.begin();b表示v的第一个元素 auto e=v.end();e表示v的尾元素的下一位置
其中若v为空,v.begin()和v.end()均表示v的尾后元素
迭代器操作:*iter 返回所指元素的引用
iter->mem (等价于(*iter).mem)获取成员mem
++iter 指向容器后一个元素
--iter 指向容器前一个元素
==,!= 判断相等与否
迭代器类型:iterator(能读写)和const_iterator(只读不写)
(c++11)v.cbegin();和v.cend();返回类型均为const_iterator,无关对象本身是否为常量
任何改变容器对象容量的操作(比如push_back)均使迭代器失效
迭代器运算:iter+n 向后n个元素
iter-n 向前n个元素
iter+=n 向后并赋值
iter-=n 向前并赋值
iter1-iter2 两个迭代器之间的距离(类型是difference_type带符号整数,两个迭代器必须指向同一容器中的元素)
>,<,<=,>= 位置在前则小,在后则大
数组:
数组的大小是固定的,也即其个数必须是常量const
例如:constexpr int sz=42;
string strArray[sz];
char a1[ ]={'H','e','l','l','o','\0'}等效于char a1[ ]="Hello";
禁止用数组来赋值另一数组
几组易混淆的概念:
例如:int *prts[10];(含有10个整型指针的数组)
int (*Parray)[10]=&arr;(Parray指向一个含有10个整数的数组)
int (&arrPref)[10]=arr;(arrPref是一个含有10个整数的数组的引用)
int *(&arry)[10]=arr;(arry是一个含有10个整型指针的数组的引用)
数组下标的类型是size_t,两指针相减的类型是ptrdiff_t类型 auto n=end(arr)-begin(arr)得到arr元素数量
编译器自动将数组名替换为指向数组首元素的指针,使用decltype仍视其为数组
数组的begin和end函数:(c++11)(#include<iterator>)
int *beg=begin(arr);(获取指向arr首元素的指针)
int *last=end(arr);(获取指向arr尾后元素的指针,避免因使用auto *e=&arr[10];不当而出错)
C风格字符串:(除非题目有一些奇怪的要求,尽量还是避免使用)
string函数:(应用类型为char[ ]即字符数组,要求str以空字符'\0'结尾)
strlen(str);返回str的长度并且不计空字符
strcmp(str1,str2);比较两字符串“大小”,=:0, >:正值,<:负值
strcat(p1,p2);p1后面附加p2并且返回p1
strcpy(p1,p2);将p2拷贝给p1并且返回p1
允许字符数组和string进行混用,存在部分限制:
禁止用string初始化char[ ],反之允许(借助c_str()函数:const char *str=s.c_str();)
允许数组初始化vector:
例如:int int_arr[ ]={1,2,3,4,5};
vector<int>ivec(begin(int_arr),end(int_arr));(提供数组的首元素地址和尾后元素地址即可)
vector<int>ivec(int_arr+1,int_arr+3);(也可以仅用数组的一部分进行初始化)
多维数组:
初始化方式:
例如:int ia[3][4]={{1},{2},{3}};(初始化每行的首元素)int ia[3][4]={1,2,3,4};(仅初始化第一行)
引用:
例如:int(&row)[4]=ia[1];(row引用ia的第二行4元素数组)
范围for遍历:
例如:for(const auto &row:ia){//外层必须用引用类型遍历
for(auto col:row){//只有最内层可以不用引用类型
/*..........*/}