C++从0到1的入门级教学(五)——字符串、向量和数组

文章目录

  • 5 字符串、向量和数组
    • 5.1 命名空间
    • 5.2 标准库string
      • 5.2.1 定义和初始化string对象
      • 5.2.2 string对象上的操作
        • 5.2.2.1 读取string对象
        • 5.2.2.2 风格
        • 5.2.2.3 使用getline读取一整行
        • 5.2.2.4 empty和size操作
        • 5.2.2.5 size_type类型
        • 5.2.2.6 比较string对象
        • 5.2.2.7 string对象的相加
        • 5.2.2.8 字面值和string对象相加
      • 5.2.3 处理每个字符
        • 5.2.3.1 范围for语句
        • 5.2.3.2 下标
    • 5.3 一维数组
      • 5.3.1 一维数组的定义方式
      • 5.3.2 数组的初始化规则
      • 5.3.3 一维数组数组名
      • 5.3.4 练习案例1:五只小猪称体重
      • 5.3.5 练习案例2:元素逆置
      • 5.3.6 冒泡排序
    • 5.4 二维数组
      • 5.4.1 二维数组的定义方式
      • 5.4.2 二维数组的数组名
      • 5.4.3 二维数组应用案例
    • 5.5 标准库vector
      • 5.5.1 实例化
      • 5.5.2 定义和初始化vector对象
      • 5.5.3 向vector对象中添加元素
      • 5.5.4 案例
      • 5.5.5 其他的操作
        • 5.5.5.1 访问所有元素
        • 5.5.5.2 检查空和大小
        • 5.5.5.3 索引

5 字符串、向量和数组

除了第二章我们介绍的基本数据类型,实际上C++里还定义了一个内容丰富的抽象数据类型库。其中stringvector库是两种最重要的标准库类型,前者支持可变长的字符串,相当于char数组的加强版。后者支持可变长的集合,相当于数组的加强版。除此之外,还有一种标准库类型是迭代器,它通常和string和vector配套使用,用于访问它们里面的元素。

5.1 命名空间

在第一章中我们曾经谈到过这个问题,实际上,在目前的代码中我们大多数都会在代码中加入以下的代码,用于声明我们要用的所有东西都从std库中取。

using namespace std;

以上的声明方法可以使得全局在访问std库中的内容。

需要注意的问题

我们后面会谈到C++的代码可以分文件书写,以体现优美性。而我们通常在头文件中是不会书写using声明的,因为一旦某个文件中导入使用了using声明的头文件,则会导致这个文件也会带有using声明。在实际开发中,我们常常使用各种库的工具,有些工具重名会导致情况很复杂。

5.2 标准库string

标准库string表示可变长的字符序列。如果你想要在代码中使用string这个抽象类型,那么你需要导入它的头文件。

#include <string>

如果你想要使用string的方法,你可以通过一下的方式去调用它。

std::string::

5.2.1 定义和初始化string对象

对于字符串string类型,我们可以有以下几种初始化方式。

string s1;//默认初始化,s1是一个空字符串
string s2 = s1;//s2是s1的副本
string s3 = "字面值";//s3是该字符串字面值的副本
string s4(10,'c');//s4的内容是cccccccccc

我们需要认识一个点。string库实际上是一个类。如果你学过java等面向对象编程语言,你就可以理解上面的s4为何可以采用那种方式初始化。本质上那种方法是把参数传入有参构造器中,我们称为直接初始化;我们把不采用有参构造器初始化而采用=来初始化的方法称为拷贝初始化

5.2.2 string对象上的操作

一个类除了规定初始化的方式外,还要定义对象上所能执行的操作。我们在Java时常叫做方法,而在C++中通常称为函数。

我们试着来体会几种常用的函数操作。

5.2.2.1 读取string对象

在第二讲中我们曾经谈过,cin可以用于从键盘中读取字符,当然,读取完的字符我们可以读入s。

试着敲一下下面的代码,体会我说的话。

#include <iostream>
#include <string>
using namespace std;int main()
{string s;cout << "请输入字符串:" << endl;cin >> s;cout << "输入的字符串为:" << s << endl;system("pause");return 0;
}

out:

image-20220424103306204

我们需要知道一个事,string对象是不会读取空格符、换行符、制表符这种特殊符号的,所以string对象是要从第一个实字符开始读取,直到遇到空格符等符号时停止。

还是上面的代码,我们试着输入hello world,在输入hello时,当遇见hello后面的空格,后半部分的world实际上未被输入到world对象中。

out:

image-20220424103531405

需要注意的是,虽然用cin时string对象不会读取空格符等符号,但是如果是字面值的话含有的空格string对象是可以识别的。

#include <iostream>
#include <string>
using namespace std;int main()
{string s = "hello";string s2 = " world";cout << "输出:" << s << s2 << endl;system("pause");return 0;
}

out:

image-20220424103908962

5.2.2.2 风格

我想我们说的不够清楚。在这一小节中,我们着重讲解C风格字符串和C++字符串的区别。

字符串型用于表示一串字符,其包含下面两种风格:

  • C风格字符串:char 变量名[] = “字符串值”;
  • C++风格字符串:string 变量名 = “字符串值”

如果使用C风格字符串来表示一串字符串的话:

char dog[8] = { 'b', 'e', 'a', 'u', 'x', ' ', 'I', 'I'};  // not a string!
char cat[8] = {'f', 'a', 't', 'e', 's', 's', 'a', '\0'};  // a string!

因为在C++规定中,C风格字符串都是以空字符结尾,空字符被写作\0,其用来标记字符串的结尾。上面两个都是char数组,但实际上,只有第二个数组是字符串,原因如同我们前面所说。cout显示上面的cat前面的七个字符,发现空字符后停止;如果不添加空字符,比如dog,那么cout会把内存中随后的各个字节全部打印出来,直至遇到空字符才会停止;所以,空字符是很重要的。

但是,如果用C风格字符串的数组形式来表示字符串的话,那么要写如此多的单引号,还要加空字符,他不烦我都烦,所以为了大家都省心,后面C++又出现了一种只需用引号括起来即可的字符串,这种字符串被称为字符串常量字符串字面值

char bird[11] = "Mr. Cheeps";    // the \0 is understood
char fish[] = "Bubbles";         // let the compiler count

用引号括起的字符串隐式地包括结尾的空字符,因此不用你再去写出来了。

用图形来表示一下我前面所说的意思就是:

image-20220112085528171

当然了,不管显示隐式,你需要知道的是,用sizeof查看这种方式写出来的字符串大小的时候,他是会把空字符给算进去的,如下图:

image-20220112085820773

注意,我们说过字符常量用的是单引号,不能用双引号;同样地,字符串常量只能用双引号,不能用单引号。

如果要解释的话,你要知道的是字符常量一般来说用单引号括起的某一个字符都是对于ASCII的某一个数字,而我们写字符串常量用双引号括起来一般都是对应字符串所在的内存地址。所以,如果你写出如下的代码:

char shirt_size = 'S';

那只不过是把ASCII中的83赋给了shirt_size,由于是字符型常量所以变成了字符;而如果你是写出如下代码:

char shirt_size = "S"; 

那么这个实际上是:把"S"的内存地址赋给了shirt_size。两者的意思完全不同。

所以,当走到C++来的时候,char字符串类型是可以和string字符串类型画上等号的,string字符串中也是隐式地含有一个\0。

5.2.2.3 使用getline读取一整行

有时我们希望我们通过键盘输入的字符串中保留输入时的空白符,这时候用getline函数代替原来的cin就可以解决这个问题。

getline函数只会读取一行的内容,也就是说,它的结束判别方式不是空格符等符号决定的,而是换行符决定的。为此,如果你在输入中加入空格,并不会使得它输出。

#include <iostream>
#include <string>
using namespace std;int main()
{string line;getline(cin, line);cout << line << endl;system("pause");return 0;
}

out:

image-20220424110439595

5.2.2.4 empty和size操作

从名字上看,我们大概可以猜出empty和size的功能。empty可以判断string是否为空,size可以判断string的大小。

用法很简单,调用对象的函数即可。

#include <iostream>
#include <string>
using namespace std;int main()
{string line = "hello";cout << line.empty() << endl;system("pause");return 0;
}

out:

image-20220424111253504

对于empty来说,其返回的是一个布尔值。

让我们再来看看size的用法。

#include <iostream>
#include <string>
using namespace std;int main()
{string line = "hello";cout << line.size() << endl;system("pause");return 0;
}

out:

image-20220424111432487

5.2.2.5 size_type类型

5.2.2.6 比较string对象

string类中定义了几个运算符用于比较string对象。

最开始要介绍的运算符即为==!=。它们可以检验两个string对象相等或不相等。

5.2.2.7 string对象的相加

string对象相加只需要简单的用+就行了。如下所示:

#include <iostream>
#include <string>
using namespace std;int main()
{string str1 = "hello";string str2 = "world";string str3 = str1 + str2;cout << "两个字符串拼接后的结果:" << str3 << endl;system("pause");return 0;
}

out:

image-20220424112059807

5.2.2.8 字面值和string对象相加

字面值也可以直接和string对象用+相加,但是有一点需要保证的是+的两侧必须有一个是string对象,字面值和字面值是不能通过+简单的相加的。

敲一下下面的代码,理解上面我所说的话。

#include <iostream>
#include <string>
using namespace std;int main()
{string str1 = "hello";string str2 = "world";string str3 = str1 + "big" + str2;cout << "两个字符串拼接后的结果:" << str3 << endl;system("pause");return 0;
}

out:

image-20220425161818129

5.2.3 处理每个字符

5.2.2中是对整个string对象做操作,而在这一小节中,我们打算对字符串中的每个字符做操作。

5.2.3.1 范围for语句

C++11中为我们提供了范围for语句用于遍历字符串序列中每个元素,这种用法类似于Java中的增强for循环。其语法形式如下:

for(取值对象:遍历对象)执行操作

在以下的代码中,让我们仔细体会一下其用法:

#include <iostream>
#include <string>
using namespace std;int main()
{string str1 = "I love you more than i can say";for (auto c : str1) {cout << c << endl;}system("pause");return 0;
}

out:

image-20220425162345106

我们试着对每个字符做一些操作如何?

在下面的例子中,我们想要把字符串改写为大写字母的形式,为此我们使用了标准库函数toupper,这个函数每次只能接收一个字符,然后输出其对应的大写形式。需要注意的是,由于返回的数值要影响原来的str1对象,故我们要使用引用&。

#include <iostream>
#include <string>
using namespace std;int main()
{string str1 = "I love you more than i can say";for (auto &c : str1) {c = toupper(c);//将每个小写字符转换为大写字符}cout << "大写的str1:" << str1 << endl;system("pause");return 0;
}

out:

image-20220425162958796

5.2.3.2 下标

我们不想对string对象中所有的字符做操作,而是想要对某些字符做操作,那么我们可以使用[]来访问string对象中的字符元素,如果你学过python,你会对此很熟悉,元素索引从0开始。

让我们试着下面的代码,我们准备把love中的l变为大写L:

#include <iostream>
#include <string>
using namespace std;int main()
{string str1 = "I love you more than i can say";str1[2] = toupper(str1[2]);cout << "大写的str1:" << str1 << endl;system("pause");return 0;
}

out:

image-20220425163700409

越界问题

使用下标时总要注意不能越界,即下标一定是从0开始,但是在size的范围内,如果超出size,那问题就很大了宝贝。

在Java中数组如果索引越界会抛出异常,程序报错,而对于C++来说,其标准并不要求检测下标是否合法,一旦你使用了一个超出范围的下标,其结果是不可预知的。

5.3 一维数组

5.3.1 一维数组的定义方式

要创建数组,可使用声明语句。数组声明应指出以下三点:

  • 存储在每个元素中的值的类型
  • 数组名
  • 数组中的元素数

一维数组定义的三种方式:

  • 数据类型 数组名 [数组长度];
  • 数据类型 数组名 [数组长度] = {值1,值2...};
  • 数据类型 数组名[] = {值1,值2...};

让编译器去做

像第三种定义方式那样让编译器计算元素个数是一种很糟糕的做法,因为其计数可能和我们自己想的不太一样。

数组的特点

  1. 放在一块连续的内存空间中
  2. 数组中每个元素都是相同的数据类型

image-20211029143248843

数组的索引

数组的用途都是基于这样一个事实:可以单独访问数组元素。方法是使用下标或索引来对元素进行编号。C++的数组从0开始编号,这没有商量的余地。即arr[0]

有效下标值的重要性

编译器不会检查使用的下标是否有效。例如,如果将一个值赋给不存在的元素,如

int arr[10] = {1,2,3,4,5,6,7,8,9,10}
cout<<arr[11]<<endl;

那么编译器是不会指出错误的。

但是在程序运行后,这种赋值可能引发问题,它可能破坏数据或代码,也可能导致程序异常终止,所以必须确保程序只使用有效的下标值。

示例

#include <iostream>
using namespace std;
int main()
{/*1、数据类型 数组名[数组长度]; 2、数据类型 数组名[数组长度] = { 值1,值2... }; 3、数据类型 数组名[] = { 值1,值2... }; *///1、数据类型 数组名[数组长度]//int arr[5];//给数组中的元素进行赋值//数组元素的下标是从0开始索引的/*arr[0] = 10;arr[1] = 20;arr[2] = 30;arr[3] = 40;arr[4] = 50;*///访问数据元素/*cout << arr[0] << endl;cout << arr[1] << endl;cout << arr[2] << endl;cout << arr[3] << endl;cout << arr[4] << endl;*///2、数据类型 数组名[数组长度] = {值1,值2...}//如果在初始化数据的时候,没有把数据全部初始化,那么没有初始化的值初始值为0int arr2[5] = { 10,20,30,40,50 };/*cout << arr2[0] << endl;cout << arr2[1] << endl;cout << arr2[2] << endl;cout << arr2[3] << endl;cout << arr2[4] << endl;*/for (int i = 0; i < 5; i++) {cout << arr2[i] << endl;}//3、数据类型 数组名[] = { 值1,值2... };int arr3[] = { 100,90,80,70,60,50,40,30,20,10 };for (int i = 0; i < 10; i++) {cout << arr3[i] << endl;}system("pause");return 0;
}

【总结1:数组名的命名规范与变量名命名规范一致,不要和变量重名】

5.3.2 数组的初始化规则

C++有几条初始化数组的规则,它们限制了初始化的时刻,决定了数组的元素数目和初始化器中值得数目不相同时将发送的情况。

一般来说,我们给数组定义的时候都会顺便初始化,即:

int cards[4] = {3,6,8,10}

但是也有例外,不过,如果你在定义的时候不初始化,后面就没法初始化了,如果是在方括号里面指定数组的元素个数那还好说,你不初始化它还会给你默认填0,;但是如果你连数组的元素个数都没指定,那数组就要蒙了:我是谁,我在干嘛,它一无所知。所以为了让你在定义的时候也要做初始化的工作,vistual studio做得非常好,如下:

image-20220112083502295

值得一提的是,C++不像java,你不能说把数组赋给另外一个数组,这是不允许的。

int cards[4] = {3,6,8,10};
int hand[4];
hand = cards;

image-20220112083640153

在编译器里,编译器会提示你表达式必须是可修改的左值。

如果你在初始化数组的时候,你指定了数组元素的个数,但是却没有完全初始化,只初始化一部分的值,那么此时其他未指定初始化值的元素都会默认为0.

5.3.3 一维数组数组名

一维数组名称的用途:

  1. 可以统计整个数组在内存中的长度sizeof(arr)
  2. 可以获取数组在内存中的首地址cout<<arr<<endl

示例

#include <iostream>
using namespace std;
int main()
{//数组名用途//1、可以通过数组名统计整个数组占有的内存大小int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };cout << "整个数组名的占用空间为:" << sizeof(arr) << endl;cout << "每个元素占用内存空间为:" << sizeof(arr[0]) << endl;cout << "数组中元素的个数为:" << sizeof(arr) / sizeof(arr[0]) << endl;//2、可以通过数组名查看数组首地址cout << "数组首地址为:" << (int)arr << endl;cout << "数组中第一个元素地址为:" << (int)&arr[0] << endl;cout << "数组中第二个元素地址为:" << (int)&arr[1] << endl;//数组名是常量不可以进行赋值操作//arr = 10;system("pause");return 0;
}

【注:其实arr一般说的就是&arr[0],即你指一个数组,一般就是指数组的头元素的地址】

5.3.4 练习案例1:五只小猪称体重

案例描述

在一个数组中记录了五只小猪的体重,如int arr[5] = {300,350,200,400,250},找出并打印最重的小猪体重。

核心思想

image-20211029170721613

示例

#include <iostream>
using namespace std;
int main()
{int arr[5] = { 300,350,200,400,250 };int max = 0;int test = 0;for (int i = 0; i < 5; i++) {test = arr[i];if (max < test) {max = test;}}cout << "五只小猪里最重的小猪体重为:" << max << endl;system("pause");return 0;
}

5.3.5 练习案例2:元素逆置

案例描述

请声明一个5元素的数组,并且将元素逆置。(如原数组元素为:1,3,2,5,4;逆置后输出结果为:4,5,2,3,1)

核心思想

image-20211029172301483

示例

#include <iostream>
using namespace std;
int main()
{//1、创建数组前int arr[5] = { 1,3,2,5,4 };int start = 0;int end = sizeof(arr) / sizeof(arr[0]) - 1;cout << "逆置前的数组为:" << endl;for (int i = 0; i < 5; i++) {cout << arr[i] << endl;}//创建中间变量放元素int temp = 0;//实现逆置while (start<end) {temp = arr[start];arr[start] = arr[end];arr[end] = temp;start++;end--;}cout << "逆置后的数组为:" << endl;for (int i = 0; i < 5; i++) {cout <<	arr[i] << endl;}system("pause");return 0;
}

5.3.6 冒泡排序

作用:最常用的排序算法,对数组内元素进行排序

  1. 比较相邻的元素,如果第一个比第二个大,就交换他们两个
  2. 对每一对相邻元素做同样的工作,执行完毕后,找到一个最大值
  3. 重复以上的步骤,每次比较次数-1,直到不需要比较

核心思想

image-20211029211529064

示例:将数组{4,2,8,0,5,7,1,3,9}进行升序排序

#include <iostream>
using namespace std;
int main()
{//利用冒泡排序实现升序排列int arr[9] = { 4,2,8,0,5,7,1,3,9 };cout << "排序前:" << endl;for (int i = 0; i < 9; i++){cout << arr[i] << " ";}cout << endl;//开始冒泡排序//总共排序轮数为 元素个数-1for (int i = 0; i < 9 - 1; i++) {//内层循环对比for (int j = 0; i < 9 - i - 1; j++) {if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[ j + 1 ] = temp;}}}//排序后结果cout << "排序后:" << endl;for (int i = 0; i < 9; i++){cout << arr[i] << " ";}cout << endl;system("pause");return 0;
}

5.4 二维数组

二维数组就是在一维数组上,添加一个维度。

image-20211030094801843

5.4.1 二维数组的定义方式

二维数组定义的四种方式:

  1. 数据类型 数组名[行数][列数];
  2. 数据类型 数组名[行数][列数] = {数据1,数据2},{数据3,数据4};
  3. 数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据4};
  4. 数据类型 数组名[][列数] = {数据1,数据2,数据3,数据4}

【建议:以上4种定义方式,利用第二种更加直观,提高代码的可读性。】

image-20211030095506886

示例

#include <iostream>
using namespace std;int main()
{//1、数据类型 数组名[行数][列数]int arr[2][3];arr[0][0] = 1;arr[0][1] = 2;arr[0][2] = 3;arr[1][0] = 4;arr[1][1] = 5;arr[1][2] = 6;/*cout << arr[0][0] << endl;cout << arr[0][1] << endl;cout << arr[0][2] << endl;cout << arr[1][0] << endl;cout << arr[1][1] << endl;cout << arr[1][2] << endl;*/for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {cout << arr[i][j] << " ";}cout << endl;}//2、数据类型 数组名[行数][列数] = {数据1,数据2},{数据3,数据4}int arr2[2][3] = { {1,2,3} ,{4,5,6} };for (int i = 0; i < 2; i++){for (int j = 0; j < 3; j++){cout << arr2[i][j] << " ";}cout << endl;}//3、数据类型 数组名[行数][列数] = {数据1,数据2,数据3,数据4}int arr3[2][3] = { 1,2,3,4,5,6 };for (int i = 0; i < 2; i++){for (int j = 0; j < 3; j++){cout << arr3[i][j] << " ";}cout << endl;}//4、数据类型 数组名[][列数] = {数据1,数据2,数据3,数据4}int arr4[][3] = { 1,2,3,4,5,6 };for (int i = 0; i < 2; i++){for (int j = 0; j < 3; j++){cout << arr4[i][j] << " ";}cout << endl;}system("pause");return 0;
}

5.4.2 二维数组的数组名

  • 查看二维数组所占内存的空间
  • 获取二维数组的首地址

示例

#include <iostream>
using namespace std;int main()
{//1、查看占用内存空间大小int arr[2][3] = { {1,2,3} ,{4,5,6} };cout << "二维数组占用的内存空间为:" << sizeof(arr) << endl;cout << "二维数组第一行占用空间为:" << sizeof(arr[0]) << endl;cout << "二维数组第一个元素占用内存为:" << sizeof(arr[0][0]) << endl;//通过上面几条代码可以统计二维数组的行数和列数cout << "二维数组的行数为:" << sizeof(arr) / sizeof(arr[0]) << endl;cout << "二维数组的列数为:" << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;//2、获取二维数组的首地址cout << "二维数组的首地址:" << (int)arr << endl;cout << "二维数组第一行首地址为:" << (int)arr[0] << endl;cout << "二维数组第二行首地址为:" << (int)arr[1] << endl;cout << "二维数组第一个元素的首地址为:" << (int)&arr[0][0] << endl;cout << "二维数组第二个元素的首地址为:" << (int)&arr[0][1] << endl;system("pause");return 0;
}

5.4.3 二维数组应用案例

考试成绩统计

案例描述:有三名同学(张三,李四,王五),在一次考试中的成绩分别如下表,请分别输出三名同学的总成绩。

张三100100100
李四9050100
王五607080

示例

#include <iostream>
#include <string>
using namespace std;int main() 
{//二维数组案例-考试成绩案例//1、创建二维数组int scores[3][3] = {{100,100,100},{90,50,100},{60,70,80}};string students[3] = { "张三","李四","王五" };//2、统计每个人的总和分数for (int i = 0; i < 3; i++) {int sum = 0;//统计每个人的分数总和for (int j = 0; j < 3; j++) {sum += scores[i][j];/*cout << scores[i][j] << " ";*/}cout << students[i]<<"的总分为:"<<sum << endl;}system("pause");return 0;
}

5.5 标准库vector

vector类似于java中的Array和List,它比数组的功能强,可供使用的成员函数函数更多。

vector每个对象都有索引,索引可以用于访问每个对象,vector本身也是个对象,故我们通常称vector对象为容器。

要想使用vector,与string同理,也需要导入头文件。

#include <vector> 

5.5.1 实例化

C++语言既有类模板,也有函数模板,模板是什么我们后续会讲,但是需要知道的是,vector就是一个类模板。

模板本身不是类或函数,但是可以看做是类或函数的说明。而编译器根据模板创建类或函数的过程称为实例化。当使用模板时,需要之处编译器应该把类或函数实例化哪种类型。

可能你对我说的是啥不是很清楚。我提一个问题:如果你想在想要一个能装int对象的容器,那你一定要说明对吧?说明要装int对象,那么该容器就是int类型容器。如下所示:

vector<int> ivec;//ivec容器中可以存放int对象
vector<Scales_item> Sales_vec;//Sales_vec容器中可以存放Scales_item对象
vector<vector<string>> file;//file容器中的元素是容器。里面的容器又放的是字符串。

5.5.2 定义和初始化vector对象

vector初始化有很多种方式,最简单的莫过于声明但不赋值,这样编译器就会默认给你一个空容器。

vector <string> svec;//默认初始化,svec不包含任何元素

C++的容器模板提供了许多方法,可以帮助我们简便地为vector对象添加元素。

当然,我们也可以指定初始值,或者通过拷贝都是可以的,不过需要注意的是,指定的初始值和拷贝操作都需要元素和容器类型对应。

如何指定初始值?C++提供了一种给vector对象的元素赋予初始值的方法,我们称之为列表初始化。其语法格式如下:

vector<string> articles = {"a","an","the"};

如果是拷贝的话:

vector<string> articles = {"a","an","the"};
vector<string> articles2 = (articles);//将articles的元素全部拷给articles2,需要注意的是容器类型必须相同!

当然你也可以指定容器中的元素,并且要填充多少个这个元素。

vector<int> v1(10,-1);//创建10个int类型的元素,每个元素都初始化为-1

如果你是按照以上的方式去初始化容器的,当你没有给出初始化的值而指定创建多少个类型的元素,那么系统会按照默认给出这几个元素,如:

vector<int> v1(10);//默认给出10个int元素,每个int元素都是0
vector<string> v2(10);//默认给出10个string元素,每个string元素都是空字符串

5.5.3 向vector对象中添加元素

有时候,我们并不确定容器中存有多少元素。为此,我们可以先创建一个空容器,然后用成员函数push_back向容器内添加元素,这就是为什么vector对象比数组好用的原因。

vector<int> v1;//空容器对象
for(int i = 0;i != 100;++i)v1.push_back(i);

有时也可以实时读入数据然后赋予vecotr对象:

string word;
vector<string> text;
while(cin >> word)
{text.push_back(word);//把word添加到text后面
}

vector对象

相比于静态数组和动态数组来说,vector拥有更好的效能。在数组中我们曾经学过,使用静态数组时要指定数组的大小,这就为后续添加元素造成了不便,而使用new开辟空间来创建动态数组又需要指针的控制,这并不好用。

5.5.4 案例

案例要求:编写一段程序,用cin输入一组整数并把它们存入一个vector对象。

#include <iostream>
#include <string>
#include <vector>
using namespace std;int main()
{//1 定义一个空容器vector<int> v1;//2 用cin循环读入一组整数int a;while (cin >> a) {v1.push_back(a);}
}

5.5.5 其他的操作

除了push_back操作外,vector还有许多操作和string类似,我们来体会一下这些操作并学会使用它们!

5.5.5.1 访问所有元素

通过范围for可以访问容器中所有的元素。

#include <iostream>
#include <string>
#include <vector>
using namespace std;int main()
{//1 定义一个空容器vector<int> v1 = {1,2,3,4,5,6};//2 使用范围for输出所有元素for (auto i : v1) {cout << i;}cout << endl;}

out:

image-20220426132147968

5.5.5.2 检查空和大小

vector容器可以使用empty和size两个成员函数来判断容器中是否为空和容器的大小。具体的使用在string中已经详细说明,如果想要复习的可以试着敲一下下面的代码。

#include <iostream>
#include <string>
#include <vector>
using namespace std;int main()
{//1 定义一个空容器vector<int> v1 = {1,2,3,4,5,6};//2 检查容器的大小cout << v1.size() << endl;//3 检查容器是否为空cout << v1.empty() << endl;}

out:

image-20220426132516580

5.5.5.3 索引

和string一样,只要容器不加上const限定符,他就能够通过索引来改变容器内的值。

但是有些人可能想耍小聪明,想利用下标索引来添加元素,这是不允许的。下标索引只能用于访问容器中已经存在的元素。

缓冲区溢出

通过下标访问不存在的元素会产生严重的后果,这个后果叫做缓冲器溢出,其使得设备和PC上总会出现安全问题。

当然,缓冲区溢出常常和程序员的粗心有关,如果你不能保证自己能够使用正确的下标索引,那么使用范围for是保证不会报错的重要手段。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

媒体格式分析之flv -- 基于FFMPEG

本来是应该先写一个媒体文件格式的简单讲解的&#xff0c;还没来得及写&#xff0c;以后再写。今天就先根据ffmpeg的flv.c的flv_demux这个结构体来讲解一下当前比较流行的媒体格式flv. FLV 是FLASH VIDEO的简称&#xff0c;FLV流媒体格式是随着Flash MX的推出发展而来的视频格式…

C++从0到1的入门级教学(三)——表达式和运算符

文章目录3 运算符3.1 表达式3.1.1 基本概念3.1.2 运算符和运算对象3.1.3 运算对象的转换3.1.4 左值和右值3.2 运算符3.2.1 算术运算符3.2.2 赋值运算符3.2.3 比较运算符3.2.4 逻辑运算符3.2.5 成员访问运算符3.2.6 条件运算符3 运算符 C提供了一套供操作内置数据类型的运算符&…

谈谈用SQLite和FMDB而不用Core Data

谈谈用SQLite和FMDB而不用Core Data 发布于&#xff1a;2014-04-22 11:22阅读数&#xff1a;4235 凭良心讲&#xff0c;我不能告诉你不去使用Core Data。它不错&#xff0c;而且也在变好&#xff0c;并且它被很多其他Cocoa开发者所理解&#xff0c;当有新人加入你的组或者需要别…

Idea工具开发 SpringBoot整合JSP(毕设亲测可用)

因为&#xff0c;临近毕业了&#xff0c;自己虽然也学了很多框架。但是&#xff0c;都是在别人搭建好的基础上进行项目开发。但是springboot的官方文档上明确指出不提倡使用jsp进行前端开发&#xff0c;但是在校期间只学了jsp作为前端页面。所以&#xff0c;废话不多说&#xf…

深度学习番外——Yolov5服务器环境搭建

文章目录1 服务器搭建yolov5环境1.1 创建环境1.2 跟随官方指引2 下载预训练权重3 推理4 测试1 服务器搭建yolov5环境 1.1 创建环境 首先先的在本地环境下搭建一个我们的环境&#xff0c;名字设为yolo5-6 conda create -n yolov5-6 python3.7#创建环境 conda activate yolov5…

机器学习实战(一)——员工离职预测

文章目录员工离职预测——逻辑回归的应用1 读取文件2 独热编码3 划分数据集4 归一化5 逻辑回归预测6 模型预测及评估员工离职预测——逻辑回归的应用 开始这个案例之前&#xff0c;请先点击这里的数据集进行下载&#xff1a;HR_comma_sep.zip - 蓝奏云 (lanzout.com) 1 读取文…

Mac版Anaconda安装Tweepy包

Anaconda官网给出的tweepy包安装方法&#xff1a;https://anaconda.org/conda-forge/tweepy 查阅Anaconda官方文档&#xff0c;可以通过以下控制台命令安装Tweepy包。 conda install -c conda-forge tweepy 在控制台执行后&#xff0c;系统可能会提示未找到conda指令&#xff…

iOS 证书与签名 解惑详解

iOS 证书与签名 解惑详解 分类&#xff1a; iPhone2012-06-06 19:57 9426人阅读 评论(1) 收藏 举报iosxcodecryptographyappleiphone测试目录(?)[] 教程截图&#xff1a; 下面是一篇有澳洲墨尔本的一名全职iOS开发者提供的文章。他在论坛上是一个很摩登的年轻人 – Adam Eberb…

Julia学习笔记(一)——入门

文章目录1 入门1.1 启动与退出1.1.1 启动1.1.2 退出1.2 编译文件1.3 变量1.3.1 基本介绍1.3.2 重定义1.3.3 变量名合法性1 入门 1.1 启动与退出 1.1.1 启动 在没有任何IDE的帮助下&#xff0c;使用cmd启动黑窗口来尝试julia是一种最简单的方法。我们称进入julia后的黑窗口为…

Linux学习宝典

文章目录1 虚拟机1.1 简介1.2 Linux版本1.2.1 内核1.2.2 发行版1.3 文件和目录1.3.1 单用户操作系统和多用户操作系统1.3.2 window文件系统1.3.3 Linux下的文件系统2 概述2.1 为什么要学习命令2.2 一些基本操作和说明3 指令和选项4 基础指令4.1 ls指令4.1.1 讲解4.1.2 选项4.1.…

《华为工作法读后感》

开篇 首先不得不说《华为工作法》是一本很好的书籍。感谢我们领导的照顾和用心&#xff0c;才使得我们又有了一些对社会 对工作 对生活等等的认知 。 之前的我是不怎么读书的&#xff0c;因为个人原因读的慢&#xff0c;每句话都要了解其中寓意之后才继续读下去,还有就是工作…

Redis发布与订阅——PUBLISH SUBSCRIBE

2019独角兽企业重金招聘Python工程师标准>>> &#xfeff;Redis发布与订阅——PUBLISH & SUBSCRIBE 一般来说&#xff0c;发布与订阅&#xff08;又称pub/sub&#xff09;的特点是订阅者&#xff08;listener&#xff09;负责订阅频道&#xff08;channel&…

Android 网络通信架构学习

最近跟着云课堂上的极客学院做安卓APP&#xff0c;学习了课程里面介绍的一种网络通信架构。清晰明了&#xff0c;比我自己东一块西一块拼凑出来的要好很多。在这里记录一下。 云课堂的连接&#xff1a;http://study.163.com/course/courseMain.htm?courseId917001 目录&#x…

网络爬虫(二)——Xpath和Selenium的使用

文章目录2 网络爬虫进阶2.1 Xpath2.1.1 Xpath解析原理2.1.2 信息提取2.1.2.1 获取所有结点2.1.2.2 获取子节点2.1.2.3 获取父节点2.1.2.4 获取文本2.1.3 属性匹配2.1.3.1 单个属性匹配2.1.3.2 多个属性匹配3.1 Selenium3.1.1 概述3.1.2 安装3.1.3 元素定位3.1.4 元素信息3.1.5 …

lintcode:买卖股票的最佳时机 III

买卖股票的最佳时机 III 假设你有一个数组&#xff0c;它的第i个元素是一支给定的股票在第i天的价格。设计一个算法来找到最大的利润。你最多可以完成两笔交易。 样例 给出一个样例数组 [4,4,6,1,1,4,2,5], 返回 6 解题 尝试参考买卖股票的最佳时机 II 提交运行发现错误&#…

团队项目计划BACKLOG

团队名称&#xff1a; 铁大老司机 团队成员&#xff1a; 组长&#xff1a;杨超群 组员&#xff1a;杨涛 杜文星 张家军 计划会议过程&#xff1a; 我们小组在周三下午进行了团队会议&#xff0c;会议召开在图书馆大厅&#xff0c;主要内容是进行项目的总体计划安排&#xff0…

C++从0到1的入门级教学(八)——通讯录管理系统

文章目录8 通讯录管理系统8.1 系统需求8.2 菜单功能8.3 退出功能8.4 添加联系人8.4.1 设计联系人结构体8.4.2 设计通讯录结构体8.4.3 main函数中创建通讯录8.4.4 封装添加联系人函数8.5 显示联系人8.5.1 封装显示联系人函数8.5.2 调用显示联系人函数8.6 删除联系人8.6.1 封装检…

【Data Cluster】真机环境下MySQL数据库集群搭建

真机环境下MySQL-Cluster搭建文档 MySQL Cluster简介 MySQL cluster 和 Oracle RAC 完全不同&#xff0c;它采用 无共享架构Shared nothing&#xff08;shared nothing architecture&#xff09;。整个集群由管理节点(ndb_mgmd)&#xff0c;处理节点(mysqld)和存储节点(ndbd)组…

数据结构杂谈(八)——树(上)

文章目录8 树(上)8.1 引入8.2 树的基础知识8.3 树的存储结构8.3.1 双亲表示法8.3.2 孩子表示法8.4 二叉树8.4.1 基础知识8.4.2 高频考点8.4.3 二叉树的性质8.4.4 二叉链表8.4.5 树和二叉树的转换8.4.6 森林和二叉树的转换8.5 遍历8 树(上) 8.1 引入 我们在前面的章节中一直在…

Maven(一)——快速上手Maven

文章目录Maven概述Maven简介Maven的安装Maven的基本使用IDEA配置Maven依赖管理依赖范围Maven概述 Maven是专门用于管理和构建Java项目的工具&#xff0c;它的主要功能有&#xff1a; &#xff08;一&#xff09;提供了一套标准化的项目结构 不同的IDE项目结构是不一样的&…