C++ primer(第5版)第三章 字符串、向量和数组 学习笔记

(本文主要内容总结或摘抄自C++ primer中文版(第5版)( Stanley B. Lippman、Josée Lajoie、Barbara E. Moo著,王刚、杨巨峰译,电子工业出版社),如有侵权请联系删除。)

引言:string和vector是两种最重要的标准库类型,内置数组是一种更基础的类型。string表示可变长的字符序列,vector存放的是某种给定类型对象的可变长序列。

3.1命名空间的using声明

std是一个命名空间,std::cin表示从标准输入中读取内容,;;作用域操作符含义是:编译器应从左侧作用域中去寻找右侧的名字,我们可以使用更简单的方法using声明来简化这一操作,例:

using namespace::name;一般来说,我们直接使用using namespace::std;便可以直接使用cin、cout、endl等语句。

注意:头文件不应使用using声明,可能会与其他文件产生冲突

3.2标准库类型的string

string初始化的几种方法

string s1;

string s2=s1;

string s3="hiya";

string s4=("hiya");

string s5(10,'c');   //s4的内容是cccccccccc

string s6('c');

注意:用cin输入string遇到空格则停止

读取未知数量的string对象

int main()
{
	string word;
	while (cin >> word)   // 反复读取直至到达文件末尾
		cout << word << endl;   //逐个输出单词,每个单词后跟一个换行
	return 0;
}

使用getline读取一整行

int main(){
    string line;
    while(getline(cin,line))   //getline遇到换行则停止读取,每次读取cin的一行赋给line
        cout<<line<<endl;
    return 0;
}

string的empty和size操作

//每次读入一整行,遇到空行直接跳过
while(getline(cin,line))
    if(!line.empty())
        cout<<line<<endl;
//每次读入一整行,输出其中超过80个字符的行
while(getline(cin,line))
    if(line.size()>80)
        cout<<line<<endl;

string::size_type类型

用作用域操作符表明size_type类型是在类string中定义的,它是一个无符号整数型。

注意:不要把该类型与int类型混用

auto len=line.size();   //len的类型是size_type

比较string类型

string str="Hello";
string phrase="Hello World";
string slang="Hiya";

str小于phrase,slang大于str和phrase。

为string对象赋值

string st1(10,'c'),st2;
st1=st2;

两个string对象相加

string s1="Hello,",s2="World\n";
string s3=s1+s2;
s1+=s2;

字面值和string对象相加

string s1="hello",s2="world";
string s3=s1+", "+s2+'\n';
string s6=(s1+", ")+"world";

规则:(1)不能把字面值直接相加

          (2)至少有一个string对象

处理每个字符使用如下语句

for(declaration:expression)
    statement
//范例1
string str("some string");
for(auto c:str)   //对于str中的每个字符
    cout<<c<<endl;   //输出当前字符,后面紧跟一个换行符
//范例2
string s("Hello World!!!");
//转换成大写形式
for(auto &c:s)
c=toupper(c);
cout<<s<<endl;

使用下标进行随机访问

//将16进制数转换为10进制数并输出
const string hexdigits="0123456789ABCDEF";
string result;
string::size_type n;
while(cin>>n)
    if(n<hexdigits.size())
        result+=hexdigits[n];
cout<<result<<endl;

3.3标准库类型vector

使用时要包含头文件,#include<vector>,定义方法:

vector<int> a;
vector<Sales_item> b;
vector<vector<string>> c;

 

列表初始化vector对象

vector<string> articles={"a","an","the"};
vector<string> v1{"a","an","the"};
vector<int> ivec(10,-1);
vector<int> svec(10,"hi!");

值初始化

通常情况下,可以只提供vector对象容纳的数量而略去初始值,此时库会创建一个值初始化的元素初值,赋给容器中的所有元素。(如果容器中元素的类型不支持默认初始化,我们就必须提供初始的元素值)

vector<int> ivec(10);   //10个元素,每个都初始化为0
vector<string> svec(10);   //10个元素,每个都是空string对象

区分花括号和圆括号

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有2个元素,分别是10和1

vector内对象的索引

与string一样,vector对象下标也是size_type类型。

3.4迭代器介绍

用一种更通用的机制来实现访问string对象的字符或vector对象的元素,这就是迭代器(iterator)。

3.4.1使用迭代器

auto b=v.begin(),e=v.end();//b和e的类型相同
//b表示v的第一个元素,e表示v尾元素的后一个元素

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

string s("some string");
if(s.begin()!=s.end()){   //确保s非空
    auto it=s.begin();   //it表示s的第一个字符
    *it=toupper(*it);   //将当前字符改写为大写形式
}

将迭代器从一个元素移动到另外一个元素

迭代器使用递增运算符(++)来从一个元素移动到下一个元素,但是注意:end返回的迭代器并不实际指示某个元素,所以不能对其进行递增或解引用。

//依次处理s的字符直至处理完全部字符或者遇到空白
for(auto it=s.begin();it!=s.end() && !isspace(*it);++it)
    *it=toupper(*it);   //将当前字符改写为大写形式

迭代器类型

就像不知道size_type到底是什么类型一样,一般来说我们也无须知道迭代器的精确类型,但实际上我们可以用iterator和const_iterator来表示迭代器的精确类型。

vector<int>::iterator it;   //it能读写vector<int>类型的对象的元素
string::iterator it2;   //it2能读写string类型的对象的元素
vector<int>::const_iterator it3;   //只能读不能写
string::const_iterator it4;   //只能读不能写

cbegin和cend

如果对象只需读而无须写,则最好使用const_iterator类型的cbegin和cend代替begin和end。

某些对vector对象的操作会使迭代器失效

注意:凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。

迭代器的算术运算

只要两个迭代器指向的是同一个容器中的元素或者尾元素的下一位置,就能将其相减,所得结果是两个迭代器的距离,距离是指左侧迭代器向前移动多少距离追上右侧迭代器,其类型名是difference_type(带符号整型数)。

使用迭代器运算

//使用迭代器进行二分搜索,text必须是有序的
auto beg=text.begin(),end=text.end();
auto mid=text.begin()+(end-beg)/2;
while(mid!=end && *mid!=sought){
    if(sought<*mid)
        end=mid;
    else
        beg=mid+1;
    mid=beg+(end-beg)/2;
}

3.5数组

数组大小固定,不能随意向数组中增加元素,运行某些应用性能良好,但是相应损失一些灵活性。

注意:如果不清楚元素的确切个数,请使用vector。

编译的时候,维度应该是已知的,维度必须是一个常量表达式,默认情况下,数组的元素被默认初始化。

初始化时注意:(1)元素可以少但不能多,int类型数组未初始赋值的元素赋值为0,string类型数组未初始赋值的元素赋值为空

                         (2)字符数组最后一个元素为'\0',也就是说,大小为4的字符数组只能存放3个元素

//正确
int a2[]={0,1,2};
int a3[5]={0,1,2};
string a4[3]={"hi","bye"};
char a1[]={'c','+','+'};

不允许拷贝和赋值

理解复杂的数组声明

int *p[10];
int &refs[10]=/*?*/;   //错误,不存在引用的数组
int (*p2)[10]=&arr;   //p2指向一个含有10个整型的数组
int (&arrRef)[10]=arr;   //arrRef引用一个含有10个整型的数组

3.5.2访问数组元素

数组下标是size_t类型,无符号类型,建议用unsigned或者auto来定义下标。

3.5.3指针和数组

指针也是迭代器

标准库函数begin和end

这两个函数定义在头文件iterator中,begin是指向首元素的指针,end是指向尾元素下一位置的指针。

int ia[]={0,1,2,3,4,5,6,7,8,9};
int *beg=begin(ia);
int *last=end(ia);

指针运算

指针相减的结果是ptrdiff_t类型,有符号类型,与size_t相似。

3.6多维数组

多维数组的初始化

多维数组的下标引用

使用范围for语句处理多维数组

//将元素位置索引作为它的值
size_t cnt=0;
for(auto &row:ia)
    for(auto &col:row){
        col=cnt;
        ++cnt;
}

指针和多维数组

int ia[3][4];
int (*p)[4]=ia;   //p指向含有4个整数的数组
p=&ia[2];   //p指向ia的尾元素

类型别名简化多维数组的指针

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值