::
:作用域操作符string s1;
string s2 = s1;
string s3 = "hiya";
string s4(10,'c');
=
进行初始化实际上是在执行的是拷贝初始化,反之是直接初始化string s8 = string(10,'c');
// 拷贝初始化,创建一个临时对象然后进行拷贝初始化
string s;
cin>>s;
string word;
while (cin >> word) {
cout << word << " ---- " << endl;
}
getline
来代替原来的>>
运算符.#include"Sales_data.h"
#include
#include
int main()
{
string word;
while (getline(cin,word)) {
cout << word << " ---- " << endl;
}
return 0;
}
string::size_type
类型的值,这是string定义的几种配套类型之一,这些配套类型体现了标准库类型与机器无关的特性.他可能是一个unsigned类型,因此切记使用负数和size_type做比较.如果一条表达式中已经有了size()函数就不要再使用int了,这样就可以避免混用int和unsigned可能带来的问题
加法运算符的两侧
的运算对象至少有一个是string string s1 = "1";
string s2 = s1 + ',';
string s3 = "hello" + ","; //error 两个运算对象都不是string
string s4 = "hello" + ", " + s2; //erro:不能把字面值直接相加
string s5 = s1 + "112" + ","; //正确,每个加法运算符都有一个运算对象是string
为了与C兼容,字符串字面值并不是标准库类型的string对象.即字符串字面值与string是不同的类型
string str("some string");
for(auto c:str)
cout<<c<<endl;
练习1:统计字符串中标点符号的个数
string str("some string!!!!");
decltype(str.size()) punct_cnt = 0;
for(auto c:str){
if(ispunct(c)){
punct_cnt++;
}
}
cout<<"字符串中标点符号的个数: "<<punct_cnt<<endl;
[]
:接受的输入参数是string::size_type
类型的值,这个参数表示要访问的字符的位置,返回值是该位置上字符的引用#incldue
vector<string> articles = {"za","b"};
vector<string> v1{"1","2"};
vector<string> v2("1","2"); //error 列表初始化只能使用花括号
vector<int> ivec(10); // 每个元素初始化为0
vector<string> svec(10); //每个元素初始化为空的试听对象
vector vi = 10; //error 必须使用直接初始化的形式指定向量大小
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有两个元素,只分别为10,1
vector<string> v5{"hi"}; //列表初始化
vector<string> v6("hi"); //erro,不能使用字符串字面值构建vector对象
vector<string> v7{10}; //v7有10个默认初始化的元素
vector<string> v8{10,"i"};//v8有10个值为"hi"的元素
如果循环内部包含有向vector对象添加元素的语句,则不能使用范围for循环,即范围for语句体内不应包含改变其所遍历序列的大小
要使用size_type,需要首先指定他是由哪种类型定义的.vector对象的类型总是包含着元素的类型.vector
vector<string> v5;
for(decltype(v5.size()) ix=0; ix!=10;ix++)
v5[ix] = ix; //验证错误
通过下标访问不存在的元素会导致缓存区溢出,确保下标合法化的一种有效手段就是尽可能的使用范围for语句
string s("some string!");
if(s.begin() != s.end()){
auto it = s.begin();
*it = toupper(*it);
}
cout<<s<<endl;
所有的标准库容器的迭代器都定义了==和!=,但是他们中的大多数都没有定义<运算符.因此,只要我们养成了使用迭代器和!=的习惯,就不用太在意用的是哪种容器类型
iterator
和const_iterator
来表示迭代器的类型 vector<int>::iterator it; //可读写vector中的元素
string::iterator it2; // 可读写string对象中的字符
vector<int>::const_iterator it3; //只能读
string::const_iterator it4;
cbegin
和cend
auto it3 = v.cbegin() //it3的类型是vector::const_iterator
(*it).empty() // 解引用it,然后调用结果对象的empty成员
*it.empty() //error,试图访问it的名为empty的成员
//为了简化上述操作操作,引入->
it->empty()
虽然vector可以动态增长,但是存在一下两个限制
注意:凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
if(it < mid)
//处理vi前半部分的元素
difference_type
的带符号整型数.如果不知道元素的确切个数,使用vector
unsigned cnt = 42; //不是常量表达式
constexpr unsigned sz = 42; //常量表达式
int *parr[sz];
string bad[cnt]; //error,cnt不是常量表达式
string strsp[get_size()]; //当get_size()是constexpr是正确,否则错误
默认情况下,数组的元素被默认初始化,和内置类型的变量一样,如果在函数内部定义了某种内置类型的数组,那么默认初始化会令数组含有未定义的值
const char a[6] = "Daniel"; //error,没有空间可以存放空字符
int a[] = {1,2,3};
int a2 = a; //error,不允许1使用一个数组初始化另外一个数组
a2 = a;//不能吧一个数组直接赋值个另外一个数组
int arr[10];
int *ptrs[10]; // ptrs是含有10个整型指针的数组
int &refs[10]; //error,不存在引用的数组
int (*Parray)[10] = &arr; //Parray指向一个含有10个整数的数组,用法在下面
int (&arrRef)[10] = arr; //arrRef引用一个含有10个整数的数组,用法在下面
int a[10] = {1,2,3};
int (&ptr)[10] = a; //相当于a的别名是ptr
cout<<ptr[0]<<endl;
int a[10] = {1,2,3};
int (*ptr)[10] = &a;
cout<<(*ptr)[0]; // === a[0]
int a[2][10] = {1,2,3};
int (*ptr)[10] = a;
int arr[10];
int *ptrs[10]; // ptrs是含有10个整型指针的数组
int &refs[10]; //error,不存在引用的数组
int (*Parray)[10] = &arr; //Parray指向一个含有10个整数的数组
int (&arrRef)[10] = arr; //arrRef引用一个含有10个整数的数组
sizeof(arr)/sizeof(arr[0])
计算,vector可以通过size()可以直接获得size_t
int ia[] = {1,2,3,4};
auto ia2(ia); //ia2是一个整型指针,指向ia的第一个元素
//本质上等价于: auto ia2(&ia[0]);
decltype(ia) ia3 = {0,1,2,3,4,5,6,7,8,9}; //ia3是一个含有10个整数的数组即:int[10]
ia3 = p; //error,不能用整型指针给数组赋值
int iap = {0,1,2,3,4,5,6};
int *beg = begin(ia);
int *last = end(ia);//指向arr尾元素的下一位置的指针
尾后指针不能执行解引用和递增操作
auto n = end(arr) - begin(arr); //arr中的元素的数量
ptrdiff_t
的标准库类型因为差值可能为负值,所以ptrdiff_t是一种带符号类型int *p = &ia[2];
int j = p[1];
int k = p[-2]; //p[-2] 是ia[0]表示的元素
int a[] = {1,2,3};
int * p1 = &a[1];
int *p2 = &a[2];
cout<<"before p1 : "<<*p1<<endl; // 2
cout<<"before p2 : "<<*p2<<endl; // 3
p1+=p2-p1;
cout<<"after p1 : "<<*p1<<endl;//3
cout<<"after p2 : "<<*p2<<endl;//3
如果p1和p2指向同一个数组,p1+=p2-p1会导致p1最终指向p2
最好不要使用C风格的字符串
char ca[] = {'c','2'};
cout<<strlen(ca); // error,ca没有以空字符结束
const char c1[] = "1233344";
const char c2[] = "{";
if(c1<c2) // 未定义的:试图比较两个无关地址
c_str
完成char *str = s; // error;
const char *str = s.c_str();
c_str()
函数的返回值是一个C风格的字符串,也就是说函数的返回结果是一个指针,该指针指向一个以空字符结束的字符数组.结果指针的类型是cosnt char *
如果执行完c_str()函数后后续程序想一直使用返回的数组,最好将该数组重新拷贝一份.
vector<int> ivec(begin(arr),end(arr));
int ia[3][4];
//大小为3的数组,每个元素是含有4个整数的数组
int arr[10][20][30] = {0};
//大小为10的数组,它的每个元素都是大小为20的数组,这些数组的元素是含有30个整数的数组
//方式一
int ia[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}
};
//方式二:
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
//显示的初始化每行的首元素,其他未列的元素执行默认初始化
int ia[3][4] = {{0},{4},{8}}
//显示的初始化第1行,其他元素执行默认初始化
int ix[3][4] = {0,1,2,3}
int (&row)[4] = ia[1];
//把row绑定到ia的第二个4元素数组上.
size_t cnt = 0;
for(auto &row:ia){
for(auto &col: row){
col = cnt;
++cnt;
}
}
错误
for(auto row:col){
for(auto col:row){
}
}
要使用范围for语句处理多维数组,处理内层的循环外,其他所有循环的控制变量都应该是引用类型
for(auto &row:col){
for(auto col:row){
}
}
当程序使用多维数组的名字时,也会将其转换成指向数组首元素的指针.定义指向多维数组的指针时,别忘了这个多维数组实际上是数组的数组
int ia[3][4];
int (*p)[4] = ia; //p指向了含有4个整数的数组
p = &ia[2]; //p指向了ia的尾元素
for(auto p = ia;p!=ia+3;++p){
//o指向含有4个整数的数组
for(auto q =*p;q!=*p+4;q++){
cout<<*q;
}
cout<<endl;
}
for(auto p =begin(ia);p!=end(ia);++p){
//p指向ia的第一个数组
for(auto q=begin(*p);q!=end(*p);++q)
}
using int_array = int[4];
typedef int int_array[4];
for(int_array *p = ia;p!=ia+3;++p){
for(int *q=*p;q!=*p+4;++q)
cout<<*q;
}