string表示可变长的字符序列,vector存放的是某种给定类型对象的可变长序列。
头文件不应包含using声明,否则头文件的内容会拷贝到所有引用它的文件中去。
使用等号=初始化的是拷贝初始化,不使用等号的称为直接初始化。
size()函数的返回值是类型size_type,无符号整数型。如果n是负值的int,则s.size()
string s(10,'c'); // s的内容是cccccccccc
cin>>word; // 遇到空格停止
getline(cin,line); // 读入一整行,直到换行符
auto len = line.size(); // len的类型是string::size_type
string s1 = s + "," + "world"; // 加法需保证+两次的运算对象至少有一个是string
string s2 = "hello" + "," + s1; // 错误:两个运算对象都不是string
一般来说,C++程序应该使用名为cname的头文件而不使用name.h的形式。
// 统计string对象中标点符号的个数
string s("Hello World!!!");
decltype(s.size()) punct_cnt=0; // 用于统计个数,无符号整型确保下标不小于0
for(auto c:s)
if(ispunct(c)) punct_cnt++;
// 使用范围for语句改变字符串中的字符
string s("Hello World!!!");
for(auto &c:s)
c = toupper(c); // 将string对象转换成大写
cout << s << endl;
标准库类型vector表示对象的集合,其中所有对象的类型都相同,通常也称容器。
vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,如vector
由于引用不是对象,所以不存在包含引用的vector。
vector<int> v1(10); // v1有10个元素,每个的值都是0
vector<int> v2{10}; // v2有1个元素,该元素的值是10
vector<int> v3(10,1); // v3有10个元素,每个的值都是1
vector<int> v4{10,1}; // v4有2个元素,值分别是10和1
vector<string> v5{"hi"}; // v5有一个元素"hi"
vector<string> v6("hi"); // 错误,不能用字符串字面值构建vector对象
vector<string> v7{10}; // v7有10个默认初始化的元素
vector<string> v8{10,"hi"}; // v8有10个值为"hi"的元素
添加元素的方法是先创建一个空vector,然后在运行时利用vector的成员函数push_back向其中添加元素。PS:预先指定vector对象的容量没有什么必要,反而可能导致性能变差,不建议。
如果循环体内部含有向vector对象添加元素的语句,则不能使用范围for循环!范围for语句体内不应改变其所遍历序列的大小。
vector<int> v; // 空vector对象
for(int i = 0; i != 100; i++)
v.push_back(i); // 往vector中添加0到99,不能用下标方式添加元素!
/*《C++Primer 5th》P94.练习3.16*/
#include
#include
#include
using namespace std;
void main()
{
vector<int> v1, v2(10), v3(10, 42), v4{ 10 }, v5{ 10,42 };
vector<string> v6{ 10 }, v7{ 10,"hi" };
cout << "v1:" << endl; for (auto c : v1) cout << c << "\t";
cout << "\n\nv2:" << endl; for (auto c : v2) cout << c << "\t";
cout << "\n\nv3:" << endl; for (auto c : v3) cout << c << "\t";
cout << "\n\nv4:" << endl; for (auto c : v4) cout << c << "\t";
cout << "\n\nv5:" << endl; for (auto c : v5) cout << c << "\t";
cout << "\n\nv6:" << endl; for (auto c : v6) cout << c << "\t";
cout << "\n\nv7:" << endl; for (auto c : v7) cout << c << "\t";
getchar();
return ;
}
所有标准库容器如vector都可以使用迭代器,但是只有少数几种才同时支持下标运算符。严格来说,string对象不属于容器类型,但它支持迭代器。
begin成员负责返回指向第一个元素的迭代器,end成员负责返回尾元素的下一位置(该位置并无元素)的迭代器。end返回的迭代器通常称为尾后迭代器或尾迭代器。
如果容器为空,则begin和end返回的是同一个迭代器即尾后迭代器。
所有标准库容器的迭代器都定义了==和!=,但其中大多数并没有定义<运算符!!!
for(auto it = s.begin(); it != s.end(); ++it)
*it = toupper(*it);
vector<int>::iterator it; // it能读写vector的元素
string::iterator it2; // it2能读写string对象中的字符
vector<int>::const_iterator it3; // it3只能读元素,不能写元素
string::const_iterator it4; // it4只能读字符,不能写字符
begin和end返回的具体类型由对象是否是常量来决定,如果对象是常量,begin和end返回const_iterator;如果对象不是常量,返回iterator。
C++11新标准引入了cbegin和cend,用法与begin、end相同,不同的是不论vector对象是否常量,返回值都是const_iterator。
it->mem和(*it).mem表达的意思相同。
(*it).empty() // 解引用it,然后调用empty成员
*it.empty() // 错误,试图访问it的empty成员(并不存在)
for(auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
cout<< *it <
迭代器的距离是指一个迭代器移动多少位置能追上另一个迭代器,类型位difference_type的带符号整型数,可正可负。
迭代器的经典算法时二分搜索。
定义数组时必须指定数组类型,不允许使用auto关键字由初始值的列表推断类型。和vector一样,数组元素应为对象,因此不存在引用的数组。
// 错误示范
const char a[6] = "Daniel"; // 错误,没有空间存放空字符
int a[] = {0,1,2};
int a2 = a; // 错误,不允许使用一个数组初始化另一个数组
a2 = a; // 错误,不能把一个数组直接赋值给另一个数组
int *ptrs[10]; // ptrs是含有10个整型指针的数组
int &refs[10] = /*?/; // 错误,不存在引用的数组
int (*parray)[10] = &arr; // parray指向一个含有10个整数的数组
int (&arrRef)[10] = arr; // arrRef引用一个含有10个整数的数组
int *(&array)[10] = ptrs; // arry是数组的引用,该数组含有10个指针
int arr = {0,1,2,3,4,5,6,7,8,9};
int *e = &arr[10]; // 指向arr尾元素的下一位置的指针
for(int *b = arr; b != e; ++b) // arr表示首元素的地址
cout << *b << endl;
说明:arr有10个元素,尾元素所在位置的索引是9,下一位置的不存在的元素用于提供地址初始化e。与尾后迭代器雷系,尾后指针不指向具体的元素,不能进行解引用或是递增操作。
C++11标准引入了begin和end两个函数,与容器中的成员函数功能相似。但数组不是类类型,所以begin和end不是数组的成员函数,正确的使用形式是将数组作为它们的参数。
int ia[] = {0,1,2,3,4,5,6,7,8,9};
int *beg = begin(ia); // 指向ia首元素的指针
int *last = end(ia); // 指向arr尾元素的下一位置的指针
constexpr = size_t sz =5;
int arr[sz] = {1,2,3,4,5};
int *ip = arr;
int *ip1 = ip + 4; // ip1指向arr的尾元素arr[4]
auto n = end(arr)-begin(arr); // n为5,类型为ptrdiff_t带符号类型
如果两个指针分别指向不相关的对象,则不能比较它们。
如果p是空指针,允许给p加上或减去一个值为0的整型常量表达式。两个空指针也允许彼此相减,结果为0。
定义在cstring头文件中,cstring是C语言头文件string.h的C++版本。
对大多数应用来说,使用标准库string要比使用C风格字符串更安全、更高效。
string s("hello world"); // string初始化
char *str = s; // 错误,不能用string对象初始化char*
const char *str = s.c_str();
// 正确,返回C风格的字符串,不改变字符数组内容,改变s的值会使返回的数组失效
int int_arr[] = {0,1,2,3,4,5};
vector<int> ivec(begin(int_arr),end(int_arr));
要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。
size_t cnt =0;
for(auto &row : ia) // for(auto row : ia )错误,自动转换成ia首元素的指针
for(auto &col : row) // for(auto col : row)也正确
{
col = cnt;
++cnt;
}
for(auto p = begin(ia); p != end(ia); ++p)
for(auto q = begin(*p); q != end(*p); ++q)
cout << *q << ' ';