C++学习总结-string对象,vector对象

时间:2021-12-20 16:36:44

string对象

使用string对象之前,要在代码头部加上#include <string> 和using namespace std::string;

(使用命名空间中的名字之前应该用using 声明引入该名字,但是注意using 声明不要放在头文件中,以避免使用了该头文件的文件中会产生名字冲突

string对象的初始化

空string对象 string s1;

用字符串字面值初始化 string s2="hello";或者string s2("hello");

指定数量和初始值 string s3(10,'c');

拷贝构造函数 string s4(s3);

用拷贝赋值运算符string s5=s4;

读string对象

string对象可以用iostring对象来读写。注意用标准输入读的时候,string对象会自动忽略开头的空白,从第一个真正的字符开始读起,遇到空白终止。

string s;cin>>s;

输入  hello world,则s得到hello

用getline可以保留输入时的空白符。getline从输入流读入内容,直到遇到换行符为止。注意得到的string对象不包含换行符。

string对象size()函数的返回值

是string::size_type类型(这个类型是在类string中定义的),这是一个无符号的值。因此在含此类型的表达式中不要使用int.(此时int会转换为unsigned int,可能会带来非预期想要的运算结果)

string对象的比较

简单说来,是两个对象第一对相异字符的比较结果。采用ascii码大小比较,大小写敏感。因此对于string s1("hello"),s2("hF");有s1>s2

string对象相加

string对象重载了+运算符,因为标准库允许把字符字面值和字符串字面值转换成string对象,所以string s1="hello”;string s2=s1+","+'u';得到string对象s2是hello,u.注意加法运算符的两侧的运算对象至少有一个是string对象.因此string s2="hello"+','是不正确的。字符串字面值没有加用的加法运算符。

C++头文件与C头文件

C中的头文件name.h,在C++中被命名为cname.也就是说二者内容是一样的。区别是cname的头文件中定义的名字属于命名空间std,而name.h中的名字则不是。

访问string对象中的字符

用C++11新规则遍历读取:用如下方法

string str("some string");

for(auto c:str){cout<<c<<endl;}这有点像javascript,php等语言中的写法,很简洁方便


用C++11新规则遍历写,要将写循环变量定义成引用类型。用如下方法

string str("some string");

for(auto &c:str){

c=toupper(c);

}

用下标运算符[]

for(decltype(s.size()) index=0;index<s.size();++index){...}

[]的参数是string::size_type类型的值,其返回值是该位置上字符的引用。因此,既可用来读,也可作为左值,修改该位置的字符。(当然此时string对象不能是const对象。)

用下标运算符[]可实现很方便的随机访问

注意,用下标运算符[],应保证其合法性。首先下标要定义成string::size_type类型(这样可以确保其大于或等于0),其次要检查下标是否小于string对象的长度。

vector对象

使用vector对象前,需要添加头文件和using声明

#include <vector>

using std::vector;这与使用string对象类似

vector是一个类模板,使用它时,要提供vector存放对象的类型信息,以实例化为类。

vector对象的初始化

默认初始化 vector<T> v1;

指定大小和元素初始值 vector<T> v2(n,val);

只指定大小 vector<T> v3(n);

列表初始化 vector<T> v4{a,b,c,d};或者vector<T> v4={a,b,c,d};C++11新增方法,vs2010测试不通过

拷贝构造函数 vector<T> v5(v4);

拷贝赋值运算符 vector<T> v6=v5;

C++的几种初始化方法

直接初始化int i(0);

拷贝初始化int i=0;

列表初始化int i={0};或者int i{0};

大多数情况下,这些初始化方式可以相互等价地使用,但是会有例外,如下

1.提供多个初始值时,不能用拷贝初始化string s1(10,'c');无法用拷贝初始化方式写出等价的定义

2.如果提供类内初始值,则不能用直接初始化

struct Sales_data{

std::string bookNo;

unsigned units_sold=0;

double revenue=0.0;

};这是类内初始化,初始值也可放在{}内,但是不能用()

3.如果提供的是初始元素值,只能用列表初始化

vector<string> v1{"a","an","the"};

4.不能用拷贝初始化实现只指定元素个数

不能将vector<int> ivec(10);写成vector<int> ivec=10;

对于vector<int>,也不能用列表初始化实现只指定元素个数。

对于列表初始化中,初始化过程会尽量将其当成 是元素的初始值列表。若不能执行列表初始化,则会考虑用其中的值来构造vector对象。

vector<string> v1{"hello","hi"};被当作列表初始化

vector<string> v2{10,"hi"};被等价于vector<string> v2(10,"hi");

构造vector对象,不能使用拷贝初始化。只能用直接初始化或列表初始化。而列表初始化常被用来为vector内的元素提供初始值。当花括号内的元素不能用来实施列表初始化时,它会转为直接初始化。例,上面的vector<string> v2{10,"hi"};被等价于vector<string> v2(10,"hi");

vector对象初始化方式的选择

初始个数已知,用vector<T> v1(n);

初始个数已知,且元素初始值都一样,用vector<T> v2(n,value);

初始值是另一个vector对象的副本,用vector<T> v3(v2);

最常用且最高效的是,使用默认初始化函数,定义一个空vector对象,运行时再向其中添加具体值

范围for循环体内不应该改变其所遍历序列的大小。

或者说,如果循环体内包含向容器添加元素的操作,那么,不能使用范围for循环。(for(auto i:v){..})因为范围for循环预存了迭代器end()的值。一旦在序列中添加或删除了元素,end函数的值可能变得无效了。


vector对象的遍历和随机访问

与string对象类似,用for循环和下标运算符。不同的是,vector对象的下标类型是vector<T>::size_type

向vector对象添加元素

用push_back,千万不能用下标形式添加。下标只能用于操作已存在的元素。记住,vector对象和string对象的下标运算符只能用于访问已存在的元素

迭代器

string和标准库容器都 支持迭代器。所以迭代器是一种通用的访问string或者容器对象的元素的方法。

容器都有成员begin()和end().分别用来返回指向第一个元素的迭代器,和指向尾元素的下一个位置的迭代器。

通过解引用来获取它指向的元素时,一定要保证迭代器合法且确实指向着某个元素,因此要先保证容器(或string对象)不为空,用v.begin()!=v.end()判断。

用迭代器实现遍历容器或string对象

for(auto it=v.begin();it!=v.end();++it){cout<<*it<<endl;...}用;it!=v.end()判断是否已经遍历,而不用<运算符是因为所有标准窗口的迭代器都实现了==和!=,大多数都没有定义<运算符。这也是泛型编程的体现。

迭代器类型

有iterator和和const_iterator两种,分别表示一般迭代器和指向常量的迭代器。后者指向的元素值不能被修改。

const string对象或者容器对象只能用const_iterator

迭代器失效

任何一种改变容器容量的操作,会使得迭代器失效。因此,但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素

迭代器的算术运算

string和vector对象的迭代器支持多种运算,如加减、比较运算。支持it+n,it-n,it1-it2,it1<it2等,其中n是整数。it1-it2的类型是difference_type类型的带符号整型数