C++primer——3 字符串、向量和数组

3 字符串、向量和数组

3.1 命名空间using的声明

每个using声明引入命名空间中的一个成员。一行可以只放一条using声明也可以放多个using声明。注意,每句话都要以分号结束

using std::cin;
using std::cout; using std::endl;

另外,头文件中不应包括using声明

3.2 标准库类型string

标准库类型string表示可变长的字符序列

3.2.1 定义和初始化string对象

初始化string的方式

string s1默认初始化,s1是一个空串
string s2(s1)s2是s1的一个副本
string s2 = s1等价于上一条
string s3(“value”)s3是字面值"value"的副本,除了字面值最后的空字符
string s4(n, ‘c’)s4初始化为连续n个字符c组成的串
3.2.2 string对象上的操作

string::size_type类型

有几种定义的配套类型体现了标准库类型与机器无关的特性,类型size_type就是其中的一种

它是一个无符号类型的值,而且能够存放下任何string对象的大小

c++11新标准允许通过auto或者decltype来推断变量类型

suto = len = line.size(); len的类型是string::size_type

string对象相加

string s1 = "hello", s2 = "world\n";
string s3 = s1+s2; //s3 = "helloworld\n"
s1 += s2;
string s4 = s1 + "," + s2; 

**注意:当string和字面值混合相加时,必须确保每个+的两侧的运算对象至少有一个是string

string s4 = "hello" + "," + s2; //err

警告:C++语言中的字符串字面值并不是标准库类型string的对象,切记,字符串字面值与string是不同的类型

范围for语句

想要基于for语句改变string对象中字符的值,必须把循环变量定义成引用类型。如果只是单纯的遍历则不需要

for (auto &n : nums)

注意:无论何时使用到字符串的下标,都应该注意检查其合法性

3.3 标准库类型vector

标准库类型vector表示对象的集合。vector是一个类模板,模板本身不是类或函数,相反可以将模板看成编译器生成类或函数编写的一份说明。编译器根据模板创建类或函数的过程称为实例化

警告:对于某些编译器可能仍需要老实声明来处理vector的vector对象,如vector<vector<int> >

3.3.1 vector的定义和初始化

c++11新标准提供列表初始化的方式,即

vector<string> articles = {"a", "af", "dsfa"};

初始化的真正含义依赖于传递初始值时用的时花括号还是圆括号。在用一个整数初始化时可能会产生歧义,需要仔细甄别

vector<int> v1(10);     //v1有10个元素 0
vector<int> v2{10};     //1个元素 10

vector<int> v3(10, 1); //10个元素 1
vector<int> v4{10, 1}; //两个元素 10, 1

如果初始化用了花括号形式,但提供的值又不能列表初始化,那么就可以考虑用来构造初始化

vector<string> s1{"hi"}; //v5有一个元素
vector<string> s2("hi"); //err
vector<string> s3{10};   //转为构造初始化 有10个元素
vector<string> s4{10,"hi"}; //转为构造初始化 10个hi
3.3.2 向vector对象中添加元素

关键概念:vector对象能高效增长。通常情况下,在定义vector对象的时候,不需要设定大小。如果实现设定了大小,效率反而会更差,只有一种例外情况是所有元素的值都一样。

所以,高效做法是开始创建空vector对象,然后再动态添加元素

3.4 迭代器介绍

在使用下标访问string对象的字符和vector的对象元素这一方法之外,还可以使用迭代器这一更通用的机制。

有效的迭代器:指向某个元素,或者指向容器中尾元素的下一位置。

其余情况都是无效迭代器

3.4.1 使用迭代器
//be类型由编译器决定
//b表示v的第一个元素, e表示v尾元素的下一位置
auto b = v.begin(), e = end(); //b e 类型相同

特殊情况下如果容器为空,则begin和end返回同一个迭代器

标准容器迭代器的运算符

*iter返回迭代器iter所指元素的引用
iter->mem解引用iter并获取该元素的名为mem的成员,等价于*(iter).mem
++iter令iter指示容器中下一个元素
–iter令iter指示容器中上一个元素
iter1 == iter2两个迭代器相等,返回1
iter != iter2不相等返回1

注意:end返回的迭代器并不实际指示某一个元素,所以不能对其进行递增或解引用的操作

迭代器的类型分为:iterator, const_iterator。其中const_iterator只能读不能写

begin和end返回的具体类型由对象是否是常量决定

const vector<int> cv;
auto it1 = cv.begin(); //it1的类型是const_iterator
vector<int> v;
auto it2 = v.cbegin();//it2的类型是const_iterator 不论v是不是常量

对于成员访问操作,在实际使用中遇到以下问题,在这里标记记录一下

vector<string> str{"helloworld"};
auto itStr = str.begin();
if (itStr->empty()) cout << "空" << endl;
//对于vector<int>的迭代器,不可以使用empty
vector<int> nums{1,2,3,4};
auto itNums = nums.begin();
if (itNums->empty()) cout << "空" << endl; //err

警告:但凡是使用了迭代器的循环体,都不可以向迭代器所属的容器添加元素因为一旦改变了vector对象容量,都会使vector对象的迭代器失效。

3.4.2 迭代器的运算

只要两个迭代器指向的是同一个容器中的元素或者尾元素的下一位置,就能将其相减。所得的结果是两个迭代器之间的距离。

距离的类型名是difference_type的带符号整数型

3.5 数组

不同于vector:数组大小确定不变,不能随意向数组中增加元素。对于不确定元素的确切个数,建议使用vector

3.5.1 定义和初始化内置数组

编译的时候,数组的维度应该是已知的,所以,维度必须是一个常量表达式

字符数组的特殊性

//在使用字符串字面值初始化时,要注意字符串字面值结尾还有一个空字符
const char a4[6] = "abcdef"; //err没有空间添加空字符,检索过程只用碰到空字符才会停止,如此的话会持续检索下去导致出现不可预料的安全问题
char ca[] = {'c', '+', '+'};
cout << strlen(ca) << endl; //严重错误,没有空字符,strlen可能会沿着ca的内存中的位置不断寻找直到遇到空字符

不允许拷贝和赋值如果在某些编译器上允许,那是得益于所谓的编译器扩展,但是在移植到其它编译器上可能会出现问题。所以,不要使用非标准特性

复杂的数组声明

int *ptrs[10];  //ptrs是含有10个整形指针的数组
int &refs[10] = /* ? */;  //err不存在引用的数组
int (*Parray)[10] = &arr;  //Parray指向一个含有10个整数的数组
int (*arrRef)[10] = arr;   //arrRef引用一个含有10个整数的数组
						   //arry指向一个含有10个整数的数组的引用
int *(&arry)[10] = ptrs;   //arry是数组的引用,该数组含有10个指针
3.5.3 指针和数组

C++11特性引入两个函数begin和end。

int ia[] = {1,2,3,4,5};
int *b = begin(ia); //这是是将数组作为两个函数的参数使用
int *e = end(ia);	//
3.5.4 C风格字符串
strlen§返回p的长度
strcmp(p1, p2)比较。p1==p2,返回0;p1>p2,返回正值;p1<p2,返回负值;
strcat(p1, p2)p2附加到p1后,返回p1
strcpy(p1, p2)将p2拷贝给p1,返回p1
3.5.6 多维数组

要使用范围for语句处理多为数组,除了最内层的循环外,其他所有循环的控制变量都应该是和引用类型。

for (auto &row : ia)
    for (auto col : row)
        cout << col <<endl;

如果row不使用引用类型,编译器初始化row是,会自动将这些数组形式的元素转换成指向该数组内首元素的指针。如此,row就是int *,显然内层的循环就不合法了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值