c++primer 第三章 字符串、向量和数组

3.1 命名空间的using声明

头文件不应该包含using声明,因为头文件内容会拷贝到引用他的文件中去。

3.2 标准库类型string

3.2.1 定义和初始化string对象

  • 初始化string方法在这里插入图片描述

  • 直接初始化和拷贝初始化
    使用=的是拷贝初始化,会先创建一个对象,再把这个对象赋值。

3.2.2 string对象上的操作在这里插入图片描述

  • 从读入中给string对象赋值。
    • 使用标准输入给string赋值。会忽略开头空白(空格、回车、制表符等),从第一个字符开始读取,直到下一处空白。
      程序输入“ hello word”,cin>>s,s中内容是hello。
    • 读取未知数量的单词,可以用cin作为读入条件。
int mian(){
	string word;
	while(cin>>word){//反复读取,直到文件尾
		cout<<word<<endl;
	}
	return 0;
}
  • 希望保留输入的空白符,使用getline()函数将进行读取。
int mian(){
	string line;
	while(getline(cin,line)){//反复读取,直到文件尾
		cout<<line<<endl;//line中不包含换行符
	}
	return 0;
}
  • s.size()返回类型
    • 返回string::size_type类型 ,是配套类型。
    • 配套类型体现了标准库类型和机器无关的特性。
    • string::size_type是无符号类型,可以放下任意string的大小。
  • string类型相加:+的两侧至少有一个是string类,不能两个都是字面值或char*。

3.2.3 处理string对象中的字符

在这里插入图片描述

  • 建议使用c++中的c标准库头文件。
  • 使用范围for语句改变字符串中的字符。
string s{"hello word"};
for(auto &c, s ){
	//c是引用,所以才能改变s中的值。
	//不声明成引用,在范围for中只是拷贝。
	c = toupper(c);
}
  • string对象的下标范围在[0,size-1].
  • 若string为空,s[0]的结果未定义。

3.3标准库类型vector

  • vector是容器,也叫类模板。
  • 早期c++标准中,声明vector的vector,右尖括号间要有两个空格。某些编译器可能也只能处理这种老式的声明。
vector<vector<int> >.

3.3.1 定义和初始化vector对象

在这里插入图片描述- 列表初始化vector放在花括号内,使用多个相同元素初始化用圆括号。
圆括号提供的值是构造,花括号的值是列表初始化。

vector<int> v1{1,2,3,4}	;	//vector中是1~4
vector<int> v2(10,1);	   //vector中10个1
vector<int> v3(10);		   //vector中10个0
vector<string> svec{10, "hello"}; //svec中10个"hello".编译器可以接受,但是个人不要使用这种初始化方法!!

3.3.2 向vector中添加元素

  • v.push_back()
  • 范围for中不应该改变遍历序列的大小

3.3.3 其他vector操作

在这里插入图片描述- size()返回类型是size_type类型,要使用的话,也要指明基本类型,如下面的int。当然,使用auto声明更好用。

vector<int>::size_type sz =ivec.size();
  • vector 也可以使用下标。但是不能使用下标添加元素。
  • 确保下标合法的方法是使用范围for。

3.4 迭代器介绍

3.4.1 使用迭代器

在这里插入图片描述

  • 试图解引用一个非法迭代器或者尾后迭代器都是未定义的行为。
  • end实际上不指向某个元素,所以不能自增或者解引用。
  • 比较迭代器一般使用!=而不是<,因为这种风格在标准库提供的所有容器上都有效。
  • 声明一个迭代器的方法:
vector<int>::iterator it;//必须说明数据类型
string::iterator it2;

vector<int>::const_iterator it3;//只读型
string::const_iterator it2;
  • 获取vector的迭代器的方法
auto b =v.begin();
auto e = v.end();

auto cb = v.cbegin();//类型是vector<xx>::const_iterator
auto ce = v.cend();
  • 若迭代器指向一个类,要访问类成员或类函数,()必不可少。所以最好用箭头运算符替代,不出错。
(*iter).empty();
iter->empty();//等价于(*iter).empty();
  • 不允许在范围for循环中改变vector的容量。

3.4.2 迭代器运算

在这里插入图片描述

  • 两个迭代器间相减,得到迭代器之间的距离,类型是difference_type(带符号型整数)
  • 迭代器相加没有意义。
  • 使用auto方法声明迭代器时,不用声明是const或者引用。若声明成const,ivec.begin()返回的是指针,顶层const会使迭代器指针没办法移动,失去了迭代器的作用;若声明成指针,声明出指针的指针,用起来麻烦。
 auto it1 = ivec.begin();
 const auto it2 = ivec.begin();//it2++这类改变指针指向的操作出错
 auto * it3 = ivec.begin();//我的编译器会报错

数组

3.5.1 定义和初始化内置数组

  • 定义数组时,必须指定数组类型,不允许用auto推导
  • 不存在引用的数组(同vector)
  • 字符数组可以用字符串字面值初始化。使用这种方法初始化,数组最后会加上一个空字符。
char c_arr[] ="hi~";//等同于char c_arr[] ={'h','i','~','\0'}
  • 数组不允许拷贝和赋值
int a1[],a2[];
a1=a2;//错误,不允许拷贝、赋值
  • 复杂的数组声明
    类型修饰符从左往右依次绑定
int * ptrs[10];//ptrs含有10个int型指针的数组
int & refs[10]=/*?*/;//错误, refs含有10个int型引用的数组,不存在
int (*parray)[10] =&array;//parray是指针,指向一个10个int的数组
int (&arrRef)[10] = arr;//arrRef是对有10个int的数组的引用。

3.5.2 访问数组元素

  • 别越界就ok

3.5.3 指针和数组

  • 当数组作为一个auto变量的初始值时,推断出的类型是指针。用decltype返回的仍是数组
int ia[] ={1,2,3};
auto ia2(ia)={1,2,3};//ia2是指针,报错
decltype(ia) ia3 ={4,5,6};//正确
  • 迭代器就是指针,迭代器end指向最后一个元素之后。若数组有10个元素,则迭代器end指向a[10]。
  • 两指针相减得到的类型ptrdiff_t,带符号。与机器类型无关,定义在cstddef头文件中。
  • 内置下标运算(如数组)可以是负数,不要求是无符号类型;而标准库类型必须是无符号类型。
int ia[] ={1,2,3};
int *p = &ia[2];
int i = p[-2];//表示ia[0]的元素

3.5.4 c风格字符串

  • 以下函数定义在cstring头文件中。
    在这里插入图片描述
  • c风格字符串必须以空字符\0结束。
char ca{'c','+','+'};
cout<<strlen(ca)<<endl;//无空字符结尾,严重错误
  • 字符串大小的比较必须使用strcmp函数,否则只是比较两个char型指针的大小(比较两个互不相关的指针严重错误)。
  • strcat用于字符串拼接,strcat(carr1,carr2)会将carr2中内容拷贝到carr1中。如果carr1中剩余空间不足,放不下拼接内容,会出现严重错误。
  • string比c风格字符串更安全高效,建议使用string。

3.5.5 与旧代码的接口

  • c++中,任何字符串字面值都可以用空字符结尾的字符数组代替。
  • 将string转为c风格字符串,使用c_str成员函数,返回const char *
string *str = s;
const char *str = s.c_str();
  • 如果后续操作改变了string的值,c_str返回的这个数组会失去作用。安全的使用方法是及时拷贝后使用。
  • 可以使用数组初始化vector
int a[]{1,2,3,4,5,6,7,8,9,10};
vector<int> ivec1(begin(a),end(a));
vector<int> ivec2(begin(a)+1,end(a)-1);

多维数组

  • 多维数组就是数组的数组
int a[3][4];//有三个元素的数组,每个元素是有4个int的数组。
int arr[10][20][30]={0};//所有元素初始化为0
  • 多维数组的初始化
int a1[2][3] ={
	{1,2,3},
	{4,5,6}
	};
int a2[2][3]={1,2,3,4,5,6};//a2与a1等价
int a3[2][3]={{1},{4}};//初始化每行首元素
int a4[2][3]={1,2,3};//初始化第一行,剩下元素进行值初始化(0)
  • 多维数组的下标引用
//a1[1]代表a1数组的第二个元素,是一个有4个int的数组,自动转为int指针
//ruo是一个引用,再从左往右看,row是一个对有4个int的数组的引用
int (&row)[4] = a1[1];
  • 使用范围for处理多维数组,除了最内层外,其余层都要声明成引用。
    若不声明成引用,则数组会自动转成指针,对编译器而言,就是在int**和int*内循环,不合法,不能通过编译。
    int a[10][20][30]={0};
    int i = 0;
    for ( auto &a1 : a)//外层只能是引用
        for( auto &a2:a1)
            for( auto &a3:a2){//范围for中要修改数据也要声明成引用
                a3=i++;
            }
    for (const auto &a1:a)
        for(const auto &a2:a1)
            for(const auto a3:a2){//若是只读不写可以不写成引用
                cout << a3 << " ";
            }
    cout << endl;
  • 声明指向多维数组的指针
int ia[3][4];
int (*p)[4]=ia;//最基本的方式,注意,小括号必须加上。

for(auto p =ia;p!= ia + 3;p++)//使用auto,ia+3可以用标准库end(ia)代替
	for(auto q = *p;q!=*p + 4;q++)
		cout<*q<<endl;
		
using int_array = int[4];
for(int_array *p =ia;p!= ia + 3;p++)//使用类型别名简化声明
	for(int *q = *p;q!=*p + 4;q++)
		cout<*q<<endl;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值