十、数组1、数组的概念

1)引出数组

需求:学校为了统计学生的信息,需要设计一个程序,要求如下,一共有十个学员,要求依次输入各位学员的学号,并将其打印出来。

#include int main(){    int studentId1, studentId2, studentId3, studentId4, studentId5;    std::cin >> studentId1;    std::cin >> studentId2;    std::cin >> studentId3;    std::cin >> studentId4;    std::cin >> studentId5;    std::cout << "第一个学生的学号为" << studentId1 << std::endl;    std::cout << "第二个学生的学号为" << studentId2 << std::endl;    std::cout << "第三个学生的学号为" << studentId3 << std::endl;    std::cout << "第四个学生的学号为" << studentId4 << std::endl;    std::cout << "第五个学生的学号为" << studentId5 << std::endl;}

问题描述:实际生活中,我们经常会需要处理多个具有相同性质的数据,比如100个员工的工资、10个学院的学号,这种情况下,依次申请多个变量变得不太现实或者太过繁杂,这种情况下,我们使用数组来解决这样的问题。

2)数组的声明

//数组声明语法数据类型 数组变量名称[数组元素个数]{初始化值,初始化值...}//示例:申请10个学员的学号int studentId[10]{1,2,3,4}     //后面的没初始化,默认为0。代表有10个元素//示例:申请100个员工的工资int salary[100]{}      //不初始化,默认为0注:同一个数组,其数据类型是一样的

3)数组的使用及遍历

//输入10个学生的学号,并且输出#include int main(){    int studentId[10]{};    for (int i = 0; i < 10; i++)    {        std::cout << "请输入第" << i <> studentId[i];    }    for (int i = 0; i < 10; i++)    {        std::cout << "第" << i << "个学生的学号为:";        std::cout << studentId[i]<<std::endl;    }    //计算数组中元素个数    std::cout << "studentId数组中有" << sizeof(studentId) / sizeof(int) << "个元素";}

注:数组不初始化可以编译,但是有可能使用内存中的垃圾数值

2)数组的本质

数组本质:数组的本质是按照所申请的数据类型,向操作系统申请了一段连续的内存空间,中间不能插入其他的变量

例:int age[6]在内存中是按照如下显示的,总共占用4*6=26字节



//计算数组的大小#include int main(){    int studentId[10]{};    std::cout<<"数组studentId的大小为"<<sizeof(studentId)<<std::endl;  //即4*10=40字节}

2、数组的应用

1)项目设计

需求:学校今天开学,要求等级每一位报道的学生,因此我们要设计一个程序,要求输入学员的编号,并且打印出来。根据报名表得知,今天来报道的学生有100位,但是不排除有个别学生因为飞机晚点、火山喷发等原因无法即使到达,但是无论如何,我们的报道工作还是要做的

#include int main(){int studentId[100]{ 0 };int indexId{};  //已等级的学生信息while (indexId < 100){std::cout <> studentId[indexId];if (studentId[indexId] == 0){system("cls");for (int i = 0; i < indexId; i++){std::cout << i << "号 学生学号" << studentId[i] << std::endl;}}else indexId++;       //,不是0,就代表学号。表示变成了下一个元素}}

2)数组的另外一种声明方式

//数组的另外一种声明方式:不告诉数组的元素个数,但是对值进行赋值变量类型 数组名[]{初始化,初始化}//示例int a[]{1,2,3};    //编译器会自动将a声明为只有一个有3个元素的数组

3、基于数组的循环

​C++11之后的新用法:

1)案例:打印出一个数组的所有元素

//打印出一个数组的所有元素#include int main(){int studentId[]{ 1001,1002,1003,1004,1005,1006 };for (int i = 0; i < sizeof(studentId) / sizeof(int); i++)   //先计算元素个数{std::cout << "第"<<i<<"个学生的学号为:" << studentId[i] << std::endl;}}

2)基于数组的循环

①基于数组的循环语法

//基于数组的循环语法for(变量类型 变量名称:数组名称){    循环内容;}//例for(int i:studentId)   //给i赋予studentId数组中每个元素的值,{    循环内容;}//第一次i=studentId[0],第二次i=studentId[1],第三次i=studentId[3],依次。。。//变量类型根据实际需求进行定义,例如char、auto都可以for(auto 变量名称:数组){    循环内容;}

②基于数组的循环用法

//基于数组的循环用法#include int main(){int studentId[]{ 9991,9992,9993,9994,9995,9996 };for (int i : studentId){std::cout << i << std::endl;  //取元素时,不再使用studentId[i]取数据中的值,而是直接通过i}}

③通过auto指定变量类型

//通过auto指定变量类型#include int main(){int studentId[]{ 9991,9992,9993,9994,9995,9996 };for (auto i : studentId)   //系统通过auto自动推断出变量类型{std::cout << i << std::endl;}}

④变量类型可以是任意类型

#include int main(){int studentId[]{ 65,66,67,68,69,70 };for (char i:studentId)   //次数会进行强制类型转化{std::cout << i<< std::endl;}}

4、多维数组

1)引出多维数组:

需求:学校冬季要发大白菜,一共有3个班级,每个班级5个学员,要求统计这三个班所有学员的学号,并且打印出来。

//一维数组实现#include int main(){int studentId[15]{ };for (int x = 0; x < 15; x++){std::cout << "第" << (x / 5) + 1 << "班,第" << (x % 5)+1 << "个学生" << std::endl;}}

2)多维数组的定义

//多维数组声明语法类型 变量名称[元素个数][元素个数]...[元素个数]{};//示例int studentId[3][5]{};                        //即可表示3个班,5个学员//多维数组初始化示例int studentId[3][5]{{101,102,103,104,105},     //访问第一个元素studentId[0][0]{201,202,203,204,205},{301,302,303,304,305}     //访问第15个元素studentId[2][4]}

案例:学校冬季要发大白菜,一共有3个班级,每个班级5个学员,要求统计这三个班所有学员的学号,并且打印出来。

#include //学院冬季发放大白菜,,一共3个班,每个班5个学院,要求统计这三个班所以学员的学号,并且打印出来int main(){int studentId[3][5]{{101,102,103,104,105},{201,202,203,204,205},{301,302,303,304,305}};for (int x = 0; x < 3; x++){for (int y = 0; y < 5; y++){std::cout << x+1 << "班第" << y+1 << "个同学的学号是:" << studentId[x][y] << std::endl;}}}

3)多维数组的遍历

除上述方式外,还可使用如下方式遍历多维数组,但是需要单独引入一个变量进行计数

#include //学院冬季发放大白菜,,一共3个班,每个班5个学院,要求统计这三个班所以学员的学号,并且打印出来int main(){int studentId[3][5]{{1,2,3,4,5},{1,2,3,4,5},{1,2,3,4,5}};for (int x=0;x<3;x++){int count{};for (int y :studentId[x])    //y就表示student[x]中的值{count++;  //单独引入一个变量进行计数std::cout << x + 1 << "班第" << count << "个同学的学号是:" <<y << std::endl;}}}

4)多维数组的本质

本质:多维数组的本质也是向操作系统申请一块连续的内存,一般来讲是按照低纬度优先排序的方式来排序(可能因操作系统和编译器不同而不同),而索引只是为了方便访问对应的内存区域

示例:int studentId[3][5]在内存中的样子如下

studentId[0][0]studentId[0][1]studentId[0][2]studentId[0][3]studentId[0][4]
studentId[1][0]studentId[1][1]studentId[1][2]studentId[1][3]studentId[1][4]
studentId[3][0]studentId[3][1]studentId[3][2]studentId[3][3]studentId[3][4]

4)数组的安全问题

​由于数组的本质是向操作系统申请了一块内存,因此越界的数组将会访问到不该访问的地址,这种越界将会造成程序奔溃、BUG、错误,更可怕的是数组越界漏洞,可能会让攻击者拿到操作系统的控制权。

5、安全的数组(std::array容器)

1)std::array概念

​由于原生的数组存在着安全问题,使用不当会造成程序的漏洞,因此C++标准库里提供了容器,后面详细的进行容器学习,本次只简单了解array这种容器如何实现类似数组的功能。

//array数组的语法#include    //需要先引入头文件std::array变量名{初始化值};       //array的声明//案例std::arraystudentId;     //5个学员的学号

2)array使用

#include #include   //引入头文件int main(){std::arraystudentId{ 1001,1002,1003,1004 }; //声明一个int类型的数组,包含4个元素,并进行初始化for (int x : studentId)        //遍历数组,x表示数组中的每个元素{std::cout << x << std::endl;}}

2)std::array的几个常见用法

//std::array的几个常见用法std::arraystudentId;    //声明5个学员的学号studentId.size();     //返回studentId拥有几个元素studentId.fill(250);  //将studentId数组的每个元素都设置为250studentId.at(1);      //返回studentId[1]的内容
#include #include int main(){std::arraystudentId;    //声明5个学员的学号std::cout << "数组studentId拥有" << studentId.size() << "个元素" << std::endl;;     //返回studentId拥有几个元素studentId.fill(250);  //将studentId数组的每个元素都设置为250for (int i : studentId){std::cout << i << std::endl;}std::cout << "数组studentId的第4个值为" << studentId.at(3)<<std::endl;      //返回studentId[3]的内容}

3)std::array的安全性

当使用【数组名.at】时,如果数组越界会直接报错,便于寻找错误,但是原生数组对于越界访问的数组不报错。

4)array数组的比较

通过std::array可以比较两个数组是否相同,但是原生数组无法进行比较

//数组的比较#include #include int main(){int classA[3]{ 123,456 };int classB[3]{ 123,456 };std::arraystudentIdA{123,456,789};    std::arraystudentIdB{123,456,789};    std::arraystudentIdC{121,456,789 };std::cout << (classA == classB) << std::endl;   //返回0,说明原生数组不可以进行比较std::cout << (studentIdA == studentIdB) << std::endl; //返回1std::cout << (studentIdA == studentIdC) << std::endl;  //返回0}

6、std::vector容器

1)std::vector语法

//vector数组的语法#include    //需要先引入头文件std::vector变量名{初始化值};       //vector的声明//案例std::vectorstudentId;     //声明一个int类型的数组studentId,但是没有元素std::vectorstudentId{1,2,3};     //声明一个int类型的数组studentId,初始化3个元素std::vectorstudentId(5);     //注意是(),不是{},设置这个vector拥有5个元素std::vectorstudentId(5,100);     //注意是(),不是{},设置这个vector拥有5个元素,且初始值都为100

2)std::vector简单使用

#include #include int main(){std::vector studentId(5);  //告诉数组有5个元素,默认有初始值std::cout << "数组有:" << studentId.size() <<"个元素" << std::endl;std::cout << studentId.at(2) << std::endl;   //查看studentId[2]的值for (int x : studentId){std::cout << x << std::endl;}}

2)std::vector的新用法

注:array具备的有点,vector都具备

//向数组中动态添加值#include #include int main(){int userId;std::vectorstudentId;  //定义vector数组do{std::cout <> userId;if (!userId) break;  //如果学号为0,直接退出studentId.push_back(userId);  //向数组中动态的添加值} while (true);  //因为已经有跳出循环机制,不需要再利用while的判断for (int x : studentId){std::cout << x << std::endl;}}