督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正。

标准库vector类型初探,同一种类型的对象的集合(类似数组),是一个类模版而不是数据类型,学名容器,负责管理 和 存储的元素 相关的内存,因为vetcor是类模版,对应多个不同类型,比如int,string,或者自己定义的数据类型等。

程序开头应如下声明

#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::endl;

简单的vector<xx>类型的变量声明

vector<int> ivec;//声明一个vector<int>数据类型的变量ivec

问题1、标准库类型vector初始化的值的类型必须一致!

    vector<int> ivec1;//默认调无参构造
vector<int> ivec2(ivec1);//直接初始化ivec2为ivec1的一个副本
vector<string> strvec(ivec2);//error C2514: “std::vector”: 类没有构造函数。说明类型不一致,无法完成初始化!自然报错!

vector对象的初始化,vector类模版定义了四个构造函数,无参构造函数,直接初始化的带参构造函数,初始化为n个值为i的构造函数,还有一种值初始化构造函数。

下面的也没有问题!

    vector<vector<int>> ivec;//ok,完全没问题!存储的是vector<int>类型的元素

问题2、勿忘它的两种直接初始化的方式

    vector<int> ivec(, );//初始化ivec为含有20个元素,每个元素=10
vector<string> svec(, "hello");//初始化为含义10个元素,每个元是一个字符串hello //值初始化方式
vector<int> ivec1();//内置类型,比如int类型的元素存在容器vector,那么默认初始化为100个0
vector<string> svec1();//同理若是类类型,如果有默认构造函数,那么按照它的默认构造函数初始化,比如这里是20个空串

如果既不是带默认构造函数的类类型,也不是c/c++的内置基本类型,那么编程时,需要手动写上初始化值具体是多少。还有一种极端,类类型里没有定义任何的构造函数,那么c++标准库还是会产生一个初始值去依次初始化容器里的元素。

问题3、需要理解c++标准库容器对象,比如vector容器的一个重要属性!

标准库容器在运行的同时,可以高效的被添加元素,且不用预先分配内存空间!要知道,vector动态增长的效率高,专家推荐使用,且要知道,这不同于内置基本类型,后续深入,这里要先记住,不需要提前为容器对象分配内存。

问题4、对vector容器对象的求长度和判空操作

发现十分类似标准库string对象的操作,还有数组等,很像的。但是肯丢有不同。这里要注意,对于容器vector来说,vector类型总是要说明它包含的元素的类型!不能丢!

    vector<string> svec(, "null");
//vector::size_type len = svec.size();//error C2955: “std::vector”: 使用类 模板 需要 模板 参数列
cout << len << endl;

改为

    vector<string>::size_type len = svec.size();
cout << len << endl;//打印10

判空操作(和标准库类型string的判空类似,空就返回true)

    vector<int> ivec;
if (ivec.empty())
{
cout << ivec.size() << endl;//成功执行,打印0
}

问题5、对vector容器添加元素的操作push_back()

    vector<string> svec;
string str;
//每次循环把输入的str字符串插入到vector容器对象的后面
while (cin >> str)
{
svec.push_back(str);
}
//直到循环结束为止

问题6、vector容器对象的下标操作(类似string对象的下标)

可以作为右值,也可以作为左值,同时建议使用标准库容器的size_type类型来定义下标

    vector<string> svec(, "sss");
//重置容器内部元素的值为ooxx
for (vector<string>::size_type i = ; i != svec.size(); i++)
{
svec[i] = "ooxx";
}

需要知道的事实:类似size()这样的小型库函数,在c++里都被定义为了内联函数!

注意:vector容器的下标操作(标准库string类型同样类似),仅仅是只能获取已经存在的元素,不能添加元素!如下是错误的

    vector<int> ivec;
for (vector<int>::size_type i = ; i != ; i++)
{
//ivec[i] = i;//这样做是错误的!程序中断!因为ivec是空的vector对象!下标操作只能针对已经存在的元素
ivec.push_back(i);//这样就对了,从尾部插入
}

且要知道,vector容器的下标也是类似string对象或者数组,从0开始

    vector<int> ivec(, );
//int i = ivec[10];//产生运行时错误,程序中断,不存在元素下标为10的

这样的错误,就是常见的缓冲区溢出错误,很常见,需要注意,对数组也适用,还有标准库string类型

问题7、输入一组整数到vector对象,相邻的元素相加输出,并提示奇数的情况。

错误1:goto语句造成死循环

    int in;
vector<int> ivec; begin:
cout << "请输入一组整数:注意ctrl+z结束输入!" << endl; while (cin >> in)
{
ivec.push_back(in);
}
//判断空输入否
if ( == ivec.size())
{
cout << "输入为空,重新输入!" << endl;
goto begin;
}

错误2:下标溢出错误

for (vector<int>::size_type i = ; i < ivec.size(); i = i + )
{
cout << ivec[i] + ivec[i + ] << "\t";
//每行输出的个数控制为5个。必须i+1,因为i初始值=0
if ( == (i + ) % )
{
cout << endl;
}
}

i<ivec.size()这里出错,下标溢出,只有元素个数是偶数的时候不错,奇数就溢出了。修改后:

 #include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::endl; int main(void)
{
int in;
vector<int> ivec;
cout << "请输入一组整数:注意ctrl+z结束输入!" << endl; while (cin >> in)
{
ivec.push_back(in);
}
//判断空输入否
if ( == ivec.size())
{
cout << "输入为空,重新输入!" << endl;
system("pause");
return -;
}
//求相邻的元素的和,关键算法!
//因为是相邻元素,故判断完毕,i+2之后再赋给i,跨度为2
//且不知道输入的元素是奇数,肯丢留最后一个元素不计算,是偶数则正好计算完毕!
//这里必须是i < size -1,否则下标溢出错误,偶数没问题,主要是奇数的话,如果到倒数第二个元素还+2,必然是溢出错误!
for (vector<int>::size_type i = ; i < ivec.size() - ; i = i + )
{
cout << ivec[i] + ivec[i + ] << "\t";
//每行输出的个数控制为5个。必须i+1,因为i初始值=0
if ( == (i + ) % )
{
cout << endl;
}
}
//判断奇偶
if ( != ivec.size() % )
{
cout << "元素个数为奇数,最后一个元素" << ivec[ivec.size() - ] << "被忽略!" << endl;
} cout << endl; system("pause");
return ;
}

问题8、读入一组整数到vector对象,使得头尾元素两两配对,计算和,并输出奇数元素个数的提示。

     vector<int> ivec;
int in;
cout << "输入一组正数,ctrl+z结束输入:" << endl; while (cin >> in)
{
ivec.push_back(in);
} if ( == ivec.size())
{
cout << "空容器,必须输入元素!" << endl;
system("pause");
return -;
}
//首末元素相加的处理,具有模版性质,也就是设计程序的通用性
//如果是奇数元素,那么中间的会留下,如果是偶数元素,没这个问题
vector<int>::size_type first = ;
vector<int>::size_type last = ;
vector<int>::size_type count = ;//计数,控制打印输出 for (first = , last = ivec.size() - ; first < last; first++, last--)
{
cout << ivec[first] + ivec[last] << "\t";
count++;
//控制打印输出每行3个数
if ( == count % )
{
cout << endl;
}
}
//判断奇数还是偶数,给出提示
//灵活!使用简单的方式,如果是奇数的话,必然最后last和first重合
if (first == last)
{
cout << "中间的元素" << ivec[first] <<"留下了,因为元素个数是奇数!" << endl;
} cout << endl;

问题9、读入一段文本到vector对象,把对象中每个元素里面的单词都转换为大写之后在输出,5个一行。

 #include <iostream>
#include <vector>
#include <string>
#include <cctype>
using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::endl; int main(void)
{
vector<string> svec;
string str; while (cin >> str)
{
svec.push_back(str);
} if ( == svec.size())
{
return -;
} for (vector<string>::size_type i = ; i != svec.size(); i++)
{
for (string::size_type j = ; j != svec[i].size(); j++)
{
//如果是小写字母
if (islower(svec[i][j]))
{
//转换为大写输出
svec[i][j] = toupper(svec[i][j]);
}
} cout << svec[i] << "\t"; if ( == (i + ) % )
{
cout << endl;
}
} system("pause");
return ;
}

问题10、迭代器入门

//c++为每一种标准容器都定义了一种迭代器类型,迭代器是一种——可以检测容器内的元素并且可以遍历元素的数据类型。除了使用下标来访问vector对象之外,还可以使用迭代器访问,比下标操作更方便,更通用,因为所有的标准库的容器都支持迭代器,但是只有部分容器支持下标操作,故成熟的c++程序员应该使用迭代器,而不是下标操作访问容器内的元素。

//vector容器的迭代器类型
vector<int>::iterator iter;//定义一个iter变量,它的数据类型是vector<int>定义的迭代器类型

//记住,每个标准库容器都定义了自己的迭代器类型,用来遍历自己容器内的元素。

    //每个容器都定义了begin和end函数,目的是返回迭代器,如果容器不空,则begin返回的迭代器指向容器内的第一个元素
vector<int> ivec;
vector<int>::iterator iter;
iter = ivec.begin();//iter变量被初始化,使用容器的begin函数返回的迭代器,此时iter指该元素为ivec[0]

//恰恰相反,end函数返回的迭代器,指向容器内末端元素的下一个元素!记住是下一个!不是最后一个!故end操作返回的也叫超出末端迭代器。说明end函数返回的迭代器指向一个不存在的元素,不指向容器内任何实际存在的元素!作用是哨兵!表示我们已经处理完毕容器所有元素!

如果容器为空,则begin函数返回的迭代器和end函数返回的迭代器相同。

问题11、vector迭代器的自增、解引用、和比较相等否的操作

如果想要获取迭代器指向的元素的值,可以使用类似指针的操作,解引用操作!*iter就代表迭代器iter指向的元素的值!比如iter迭代器指向的元素是容器内第一个ivec[0],那么*iter和ivec[0]是等价语句!

如果想让迭代器类似下标那样,移动自己的指向,则可以使用迭代器的自增操作。比如iter++就是迭代器向前移动一个元素的位置!除了这些,迭代器也可以进行比较操作,==、!=操作来比较容器的迭代器,如果两个迭代器指向同一个元素,则==为真,否则为假。

注意,end函数不指向容器内的元素,故不能对它使用自增或者解引用操作!

    //新的赋值方式
vector<int> ivec(, );
//把容器ivec的元素重置为0 //for (vector<int>::size_type i = 0; i != ivec.size(); i++)
//{
// ivec[i] = 0;//这是old方法
//} //比较经典常用的方法如下:
for (vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); iter++)
{
*iter = ;
}

如果容器为空,则begin函数和end函数返回的迭代器相等,for循环测试失败,没问题!

问题12、两类只读迭代器类型

//类似普通的const常量,但是有区别。比如,如果仅仅想遍历容器的元素,对迭代器有const_iterator类型的迭代器,对它解引用,得到的是指向const对象的引用

     string str;
vector<string> svec; while (cin >> str)
{
svec.push_back(str);
} for (vector<string>::const_iterator iter = svec.begin(); iter != svec.end(); iter++)
{
//*iter = "dada";//error,const_iterator类型的迭代器,本身可以被改变,比如自增,但是迭代器指向的容器内的元素不能被修改!
//和普通的const常量有一些区别!有些类似指向常量的指针,指针本身可以变,但是指向的内容不能修改。
}

来对比const类型的迭代器,类似常指针,本身定义的时候必须初始化,本身不能被修改,但是指向的内容可以修改,如

     vector<int> ivec();
//const类型的iter必须初始化
const vector<int>::iterator iter = ivec.begin();
//初始化之后不能被修改
//iter++;//error
//但是iter指向的内容可以被修改,对比,const_iterator类型的迭代器,类似指向常量的指针,迭代器本身能修改,指向的元素不能修改,,和他/她相反
*iter = ;

注意区分两者,不要混淆。总结:

const 迭代器是迭代器常量

该迭代器本身的值不能修改,即该迭代器在定义时需要初始化,而且初始化之后,不能再指向其他元素。若需要指向固定元素的迭代器,则可以使用const 迭代器。但是它指向的元素的值可以被修改!

const_iterator 是一种迭代器类型

对这种类型的迭代器解引用会得到一个指向const 对象的引用,即通过这种迭代器访问到的对象是常量。该被指向的对象不能修改,因此,const_iterator 类型只能用于读取容器内的元素,不能修改元素的值。若只需遍历容器中的元素而无需修改它们,则可以使用const_iterator。但是迭代器本身能被修改。两者相反!

问题13、迭代器的算术操作

其他容器的迭代器类似。除了自增、自减之外,还有其他算术运算适用。

     vector<int> ivec();
//const类型的iter必须初始化
vector<int>::iterator iter = ivec.begin();
//iter++;//ok
//iter--;//ok //iter + 5;//ok,对一个迭代器对象加一个整型值,使得iter指向新的元素第6个元素,注意不要越界
//但是,加上或者减去的整型,最好是size_type类型的! //iter - 100;//error,越界,程序中断! //iter + 10;//ok,加的时候,可以加到最后一个元素的下一位。 //还能求两个迭代器的距离
vector<int>::iterator iter1 = ivec.end(); cout << iter1 - iter << endl;//打印10 //注意,这里相减得到的值,可能是负数,也可以是正数
cout << iter - iter1 << endl;//打印-10
//这就说明,这个值的类型不再是容器的size_type类型,而是新的容器的类型,叫:
//differenec_type
vector<int>::difference_type i = iter - iter1;//ok,是带符号类型

注意,迭代器是没有相加操作的!比如:

    iter1 + iter1;//报错!

也就是说,要求得容器的中间元素,不能这样写:

vector<int>::iterator mid = (vi.begin() + vi.end())/;

但是可以这样:

vector<int>::iterator mid = vi.begin() + vi.end()/;

直接定位容器的中间元素,简单高效,不再需要一次次的去自增或者自减的遍历了。

欢迎关注

dashuai的博客是终身学习践行者,大厂程序员,且专注于工作经验、学习笔记的分享和日常吐槽,包括但不限于互联网行业,附带分享一些PDF电子书,资料,帮忙内推,欢迎拍砖!

把《c++ primer》读薄(3-2 标准库vector容器+迭代器初探)的更多相关文章

  1. C++ Primer 有感(标准库vector及迭代器)

    vector是同一种对象的集合,每个对象都有一个对应的整数索引值.和string对象一样,标准库将负责管理与存储元素相关的类存.引入头文件 #include<vector> 1.vecto ...

  2. C++标准库vector以及迭代器

    今天看C++的书,出现了一个新的概念,容器vector以及容器迭代器. vector是同一种对象的集合,每个对象都有一个对应的整数索引值.和string对象一样,标准库将负责管理与存储元素相关的类存. ...

  3. C++标准库vector及迭代器

    vector是同一种对象的集合,每个对象都有一个对应的整数索引值.和string对象一样,标准库将负责管理与存储元素相关的类存.引入头文件 #include<vector> 1.vecto ...

  4. 把《c++ primer》读薄(3-3 标准库bitset类型)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. //开头 #include <bitset> using std::bitset; 问题1.标准库bitset类型( ...

  5. C++ Primer 第三章 标准库类型vector+迭代器iterator 运算

    1.vector: 标准库类型vector表示对象的集合,其中所有对象的类型都相同,集合中的每个对象都有一个与之对应的索引,索引用于访问对象.因为vector“容纳着”其他对象,所以它也常被称作容器( ...

  6. C++primer第三章标准库类型

    除第二章介绍的基本数据类型外,C++ 还定义了一个内容丰富的抽象数据类型标准库. 本章将介绍标准库中的 vector.string 和 bitset 类型. string 类型支持长度可变的字符串 v ...

  7. c++ primer 第三章 标准库类型

    1. string 标准库 1.1初始化 string s1; 默认构造函数s1为空 string s2(s1); 将s2初始化为s1的一个副本 string s3("value" ...

  8. c/c++ 标准库 vector

    c/c++ 标准库 vector 标准库 vector的小例子 test1~test7 #include <iostream> #include <vector> using ...

  9. 把《c++ primer》读薄(3-1 标准库string类型初探)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 问题1:养成一个好习惯,在头文件中只定义确实需要的东西 using namespace std; //建议需要什么再using声 ...

随机推荐

  1. 关于click和submit的笔记

    click主要用于元素的点击时的响应事件,而submit是指表单元素form的提交事件. 但是,当click加入到表单的提交按钮时,事情似乎就有点复杂,总是忘记了.这两天搜了下,又实践了一下. 主要用 ...

  2. java-通过JDBC操作数据库

    一.加载驱动 这里我们用Class.forname();来加载驱动,用此语句会提示排除异常. Class.forName("com.mysql.jdbc.Driver"); 括号中 ...

  3. Python之路Day21-自定义分页和cookie

    本节知识点概要 1.URL 2.views - 请求其他信息 - 装饰器 3.Templates - 母版 - 自定义 4.Models操作 5.分页(自定义分页) 6.cookie 7.sessio ...

  4. SQl SGA 整理

    --查看诊断位置信息 select * from v$diag_info; --查看sga中内存分配信息 select * from sys.x$ksmfs; --查看内存块还剩余多少 select ...

  5. Struts 2的数据校验

    既然说到了Struts 2的数据校验,我们该怎么去实现呢?又是通过什么来实现呢? 就让我带着大家一起来走进Struts 2的数据校验吧. 首先我们会想到在Stuts 2的登录案例中我们定义了一个Act ...

  6. Node.js 框架

    Node.js的是一个JavaScript平台,它允许你建立大型的Web应用程序.  Node.js的框架平台使用JavaScript作为它的脚本语言来构建可伸缩的应用. 当涉及到Web应用程序的开发 ...

  7. 设置Android Studio启动时可选最近打开过的工程

    Android Studio启动时,默认会打开最近关闭的工程. 如果想Android Studio在启动时,打开欢迎界面(Welcome to Android Studio界面),则可以通过设置Set ...

  8. 总结Objective-c常用算法

          今天是星期天,想睡到10点起床,结果认为自己太奢侈了,不能这么做,于是把闹钟设置成了6:30:结果终于9:36醒了,起床,无缘无故迟了,好吧,就算太累了吧,周天就原谅自己一回.终于到了中午 ...

  9. 参数的元数据信息&数据库的元数据信息

    package it.cast.jdbc; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql. ...

  10. xcodebuild编译ipa

    #!/bin/sh # autoBuild.sh # CTest # # Created by Ethan on 14-11-3. # Copyright (c) 2014年 Ethan. All r ...