c++ primer 读书笔记十一

3.4迭代器
和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时返回拥有返回迭代器的成员,比如这些类型都拥有名为begin和end的成员,其中begin成员负责指向第一个元素的迭代器

auto b=v.begin(),e=v.end();//b和e的类型相同

end成员则负责返回指向容器(或string对象)“尾元素的下一个位置”的迭代器,也就是说,该迭代器指示的是容器的一个本不存在的“尾后”元素,这样的迭代器没什么意义,仅仅是个标记而已。end成员返回的迭代器常被称作尾后迭代器

迭代器运算符
使用==和!=来比较两个合法的迭代器是否相等,如果两个迭代器指向的元素相同或者都是同一个容器的尾后迭代器,则它们相等;否则就说这两个迭代器不相等。
见表p96页

*iter//返回迭代器iter所指元素的引用
iter->men//等价于(*iter).mem
++iter//
--iter//令iter指向容器的上一个元素
iter1==iter2判断两个迭代器是否相等(不相等)如果两个迭代器指向的是同一个元素或者它们是同一个容器的尾后迭代器,则相等反之不相等
string s(“some string”);
if(s.begin()!=s.end())
    {
    auto it=s.begin();//it表示s的第一个字符
    *it=toupper(*it)//将当前字符改成大写形式
    }

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

迭代器类型
一般来说我们也不知道迭代器的精确类型。而实际上,那些拥有迭代器的标准库类型使用iterator和const——iterator来表示迭代器的类型:
vector::iterator it//it能读写vector的元素
string::iterator it2;//it2能读写string对象中的字符

vector::const_iterator it3;//it3只能读元素不能写元素
string::const_iterator it4;//it4只能读字符,不能写字符
const_iterator和常量指针差不多,能读取但不能修改它所指的元素值,相反,iterato的对象可读可写。如果vector 对象或string对象是一个常量,只能使用const——iterator;如果vector对象或string对象不是常量,那么既可以使用iterator也能使用const——iterator

begin 和end 运算符
begin和end返回的具体类型由对象的是否是常量决定,如果对象是常量,begin和end返回const_iterator;
如果对象不是常量,返回iterator:

vector v;
const vectorcv;
auto it1=v.begin();//it1类型是vector::iterator
auto it2=cv.begin();//it2的类型是vector::const_iterator

如果对象只需读操作而非写操作最好使用常量类型。为了便于得到const_iterator类型的返回值,c++11引入了两个新函数,分别是cbegin和cend:

auto it3=v.cbegin();//it3的类型是vector<int>::const_iterator

类似于begin和end
不论vector对象本身是否是常量返回值都是const_iterator。

结合解引用和成员访问操作
解引用迭代器可获得迭代器所指的对象,例如,对于一个字符串组成的vector对象来说,要想检查其元素是否为空,令it是该vector对象的迭代器,只需检查it所指字符串是否为空,令it是该vector对象的迭代器,只需检查it所指字符串是否为空
(*it).empty()

(*it).empty()中的园括号必不可少,该表达式的含义是先对it解引用,然后解引用的结果再执行点运算符,如果不加圆括号,点运算符由it执行,而非it解引用的结果:
(*it).empty()//解引用it,然后调用结果对象的empty()
*it.empty()//错误试图it的名为empty的成员,但it是个迭代器没有empty成员

为了简化上述表达式c++语言定义了箭头运算符(->)箭头运算符把解引用和成员访问两个操作结合在一起

p99-p101见课本

3.5数组是一种复合类型数组声明形如a[d],a是数组名字,d是数组维度,维度必须大于0,数组的维度必须是一个常量表达式

unsigned cnt=42//不是常量表达式
constexper unsigned sz=42//常量表达式关于constexper
int arr[10];//含有10个数组
int *parr[sz];//含有42个整型指针的数组
string bad[cnt]//错误,cnt不是常量表达式
string strs[get_size()]//get_size()是constexpr时正确;否则错误

定义数组的时候必须制定数组的类型,不允许使用auto关键字来初始值的列表推断类型。另外和vector一样,数组的元素应为对象,因此不存在引用的数组

显示初始化数组
可以对数组的元素进行初始化列表,此时允许忽略数组维数,指明了维数,初始化的总数量就不应该超出指定大小,如果超出就会默认值
const unsigned sz=3;
int ia1[sz]={0,1,2};
int a2[]={0,1,2};
int a3[5]={0,1,2};
string a4[3]={“hi”,”bye”};//等价于a4[]={“hi”,“bye”,”“}
int a5[2]={0,1,2};//错误初始值过多

理解复杂的的数组声明
和vector一样,数组能存放大多数类型的对象,可以定义一个存放指针的数组。又因为数组本身是对象,所以允许定义数组的指针和数组的引用

int *ptrs[10];
int &refs[10]=/*?*/
int (*Parray)[10]=&arr;
int(&arrRef)[10]=arr;


默认情况下,类型修饰符从右往左依次绑定。对于ptrs来说从右往左理解其含义比较简单:首先我们定义一个大小为10的数组,它的名字是ptrs,然后知道数组中存放的是指向int的指针但是对于Parray来说,从右往左理解就是不合理了因为数组的维度紧跟着被声明的名字,所以就数组而言从内往外阅读比较好来理解Parray:首先是圆括号的部分*Parray意味着Parray是个指针,接下来观察右边,可知道Parray是个指向大小为10的数组的指针,最后观察左边知道数组中的元素是int。这样最终含义就明白无误了,Parray是一个指针,它指向一个int数组,数组包含10个元素。同理(&arrRef)表示arrRef是一个引用,它引用的对象的大小为10的数组,,数组元素的类型是int当然,对修饰符的数量并没有特殊限制:
int *(&arry)[10]=ptrs;     
按照由内往外阅读上述语句,首先知道array是一个引用,然后观察右边知道arry引用的对象是一个大小为10的数组,最后观察左边知道,数组的元素类型是指向int的指针。这样arry就是一个含有10int型指针的数组的引用。
从内往外的顺序读

访问数组元素
数组除了大小固定这一特点外,其他用法与vector类型相似,例如可以用数组记录个分数段的成绩个数,从而实现与程序一样的功能
unsigned scored[11]={};
unsigned grade;
while(cin>>grade)
{
if(grade<=100)
++score[grade/10];

}
最好使用下面的语句
for(auto i:scores)
cout<

for(int *b=arr;b!=e;++b)
cout<<*b<<endl;
标准库函数beginend
c++11引入两个名为beginend功能与之前的相似,不过数组不是类类型,因此这两个函数不是成员函数,正确的形式是将数组作为它们的参数

int ia[]={0,1,2,3,4,5,6,7,8,9}
int *beg=begin(ia);//指向ia首元素的指针

int *last=end(ia);//指向arr尾元素的下一个位置的指针

使用beginend可以很容易地写出一个循环并处理数组中的元素。例如,假设arr是一个整型数组,下面的程序负责找到arr中的第一个负数:
int *pbeg=begin(arr),*pend=end(arr);
while(pbeg!=pend&&*pbeg>=0)
    ++pbeg;

尾后指针不能执行解引用和递增操作

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值