十、数组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;}}