C++ Primer第五版之第3章 字符串、向量和数组

命名空间的声明

  • 头文件中不应该包含using声明

标准库类型string

定义和初始化string对象

  • 初始化string对象的方式
string s1; //s1是一个空串
string s2(s1); //s2是s1的副本
string s2 = s1; //等价于s2(s1)
string s3("abc"); //s3是字面值"abc"的副本
string s3 = "abc"; //等价于s3("abc")
string s4(n,'c'); //把s4初始化为有连续n个字符c组成的串
  • 使用“=”初始化一个变量,叫做拷贝初始化,相反,如果不使用等号初始化变量,叫做直接初始化。

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个字符的引用
s1+s2; //字符串连接,每个加法运算符必须有一个操作数为string类型,不能连接两个字面值
  • 读写string操作
    • cin>>s; //在读入时,string对象会自动忽略开头的空白,并且遇到空白时(即空格、换行符、制表符等)停止;
      • getline(cin,line); //从给定的输入流中读入内容,直到遇到换行符为止,注意和cin的区别
      • line.size();//返回一个无符号整型,在line.size()<n这个表达式中,如果n是一个具有负值的int,则n会自动转换成一个比较大的无符号值这样结果肯定为true;所以不要在表达式中混用有符号数和无符号数,尤其是在size中。
      • ==:检验两个对象相等
  • string::size_type类型
    • 对于size函数,其返回值是一个string::size_type类型,是一个无符号类型的值,可以通过auto关键字自动获取返回值类型,eg:auto len = line.size();
    • 通过作用域操作符来表明size_type是在string中定义的。
    • 如果一条表达式中已经有了size()函数,就不要使用int了,以避免int和unsigned混用可能带来的问题
  • 切记,字符串字面值和string是不同的类型

处理string对象中的字符

  • 头文件cctype;
    • c++的标准头文件为cname格式;
  • 处理字符的函数有:判断数字、字母、控制字、字母数字、小写字母、大写字母、大小写字母转化、十六进制数、空白、标点符号、空格等;
  • 基于范围的for语句,eg:for(declaration : expression)
    • 一般的for语句通过下标,下标定义为:string::size_type n;
    • 如果某个索引是带符号整型,则会自动转换成string::size_type类型
    • 使用范围for语句改变字符串中的字符
    • 注意要改变string对象中字符的值,必须将循环变量定义为引用类型

标准库类型vector

定义和初始化vector对象

  • 老版本中,vector< vector<> >内层两边都要有空格,新版本不强调了,但在有的编译器中仍要;
  • vector初始化方法
vector<int> v1;
vector<int> v2(v1);等价于v2  = v1;
vector<int> ivec1(10, 5);//ivec包含了10个5
vector<string> svec3(10);  // 10个元素,每个都是空的string
vector<string> v1 = {"qwe", "qwer", "qwerty"};//列表初始化只能通过大括号初始化
// 注意花括号和圆括号提供初始化操作的区别
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 };//v1有2个元素,一个为10,一个为1
  • vector的操作:
    • v.empty();
    • v.size();
    • v.push_back(t);//向v的尾端添加一个元素
    • v[n];//返回v中第n个位置上元素的引用
    • <,>,<=,=>;//按照字典顺序进行比较
  • 如果循环体内包含向vector对象添加元素的语句,那么不能使用范围for循环,即范围for语句体中不应改变其便利序列的大小。
  • 不能用下标形式添加元素,但可以访问已经存在的元素;
  • 与string类似,定义下标时要:vector<int/string>::size_type n;

迭代器介绍

使用迭代器

  • 迭代器的类型都拥有名为begin和end的成员,begin指向第一个元素或者字符,end指向尾元素的下一位置,如果容器为空,则begin和end返回同一个迭代器,都是尾后迭代器。
auto b = ivec2.begin();
auto e = ivec2.end();
  • 标准容器的迭代器运算符
    • *iter:返回迭代器iter所指的引用,类似于指针
    • iter->mem:解引用iter并获取该元素名为mem的成员,等价于(*iter).mem;
    • ++iter:令iter指示容器的下一个元素
    • 由于end返回的迭代器并不实际指示某个元素,所以不能对其进行递增或者解引用的操作。
    • 所有标准容器的迭代器都定义了==和!=,但是他们中的大多数都没有定义<,因此在迭代器的for循环中多用!=;
  • 迭代器类型
    • 用auto关键字让编译器自动确定,或者用
vector<int>::iterator it;//读写
vectotr<int>::const_iterator it2;//只能读
string::iterator it4;
string::const_iterator it4;//只能读
  • const_iterator和常量指针一样,能读但不能修改它所指的元素值,如果vectorstring是常量,那么只能使用常量迭代器;
  • 如果对象只需读操作而不需写操作的话最好使用常量类型,在c++11中,用cbegin和cend代替begin和end;
auto b = ivec2.cbegin();
  •  结合解引用和成员访问操作
    • 如果迭代器所指的对象是类,那么可通过解引用和圆点操作符来访问类中的元素。例如,对于一个由字符串组成的vector对象来说,要想检查其元素是否为空,令it是该vector对象的选代器,只需检查it所指字符串是否为空就可以了,其代码如下所示:
(*it).empty()  // 注意(*it) . empty () 中的圆括号必不可少。
(*it).mem<==>it->mem:两者等价
(*it).empty()<==>it->empty()
"->"运算符把解引用和成员访问两个操作结合到一起
  • 结合解引用和成员访问操作
  • !!!!但凡是使用了迭代器的循环体,都不要向迭代器所属的容器中添加元素

迭代器运算

  • string和vector迭代器支持的运算
    • iter+n;
    • 迭代器相减可以得到两个迭代器指针的距离,即右边的迭代器移动多少个距离可以追上左侧的迭代器。得到的距离类型为difference_type,是带符号整型,这个距离可正可负。
      • iter1-iter2;
    • <,>,<=,>=:判断迭代器的位置关系
    • 迭代器的算术运算

数组

  • 相对于容器,数组运行性能较好,但灵活性差一点;如果不确定元素的具体个数,请使用vector;
  • 数组的声明维度必须为常量表达式,eg:
const unsigned cnt = 42;
constexpr unsigned sz = 42;
  • 数组的元素应为对象,不存在引用的数组;数组本身也是对象,允许定义数组的指针及数组的引用。
  • 字符数组的特殊性
    • 字符数组可以用字符串字面值进行初始化
    • 不允许用一个数组初始化另一个数组,也不允许把一个数组直接赋值给另一个数组。
char a3[] = "C++"; //自动添加表示字符串结束的空字符
char a4[6] = "Daniel"; //错误因为没有空间可以存放空字符
  • 复杂的数组声明
    • 指针和数组:最好的方法是从数组名字开始由内向外的顺序阅读
    • []运算符的优先级高于*          
int *ptrs[10]; //声明含有10个整型指针的数组;
int(*Parray)[10];//Parray是一个指向大小为10的数组的指针
int &refs[10] = /* ?* /; //错误,不允许使用引用的数组
int(&arrRef)[10] = arr; //arrRef引用一个含有10个整数的数组
  • 在C++中指针和数组有非常密切的关系,使用数组的时候编译器一般会把它转化为指针。
  • 指针也是迭代器
    • c++提供了获取首元素和尾元素指针的函数 :begin()和end()
//标准库函数begin()和end(),定义在iterator头文件中
int ia[] = {0, 1, 2, 3, 4, 5};
int *beg = begin(ia);           //指向ia首元素的指针
int *last = end(ia);            //指向ia尾元素的指针

C风格字符串

  • C风格字符串为将字符串存放在字符数组中并以空字符结束('\0'),eg: char str[] = "c++";
  • C风格字符串一般以指针来操作,操作函数为:
    • strlen(p);strcmp();strcat(p1,p2);strcpy(p1,p2);
    • 传入这些函数的指针必须指向以空字符作为结束的数组;
  • 使用标准库string要比使用C风格字符串更安全更高效。

与旧代码的接口

  • 允许使用以空字符结束的字符数组来初始化string对象或者为其赋值;
  • 反过来,可以用c_str函数实现用string对象初始化指向字符的指针,eg:const char *str = s.c_str();//注意,const必须有
string strr("Hello");
const char *str2 = strr.c_str();//不能改变
//char *str3;
//strcpy(str3, str2);//想要改变需要copy一份
  • 允许使用数组来初始化vector对象
int int_arr[] = { 0, 1, 2, 3, 4, 5 };
vector<int> ivec(begin(int_arr), end(int_arr));
  • 现代C++ 程序应当尽量使用vector和迭代器,避免使用内置数组和指针,应当尽量使用string,避免使用C风格字符串。

多维数组

  • 要使用范围for语句处理多维数组,除了最内层循环外,其他所有循环控制变量都应该为引用类型。
  • 指针和多维数组
    • 多维数组名实际上是指向第一个内层数组的指针  
for (auto pp = begin(ia); pp != end(ia); ++pp)
{
	//qq指向内层数组的首元素
	for (auto qq = begin(*pp); qq != end(*pp); ++qq)
		cout << *qq << endl;
}
//pp为指向ia的第一个内层数组的指针
//然后内层都要用到解引用符获取内层元素
for (auto &row : ia)
{ 
    for (auto col : row) 
    {
    	...
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值