十、数组

  • 2023-12-08 02:15:05
  • 阅读:41次

十、数组

1、数组的概念

1)引出数组

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

#include <iostream>

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 <iostream>

int main()
{
    int studentId[10]{};
    for (int i = 0; i < 10; i++)
    {
        std::cout << "请输入第" << i << "个学生的学号:";
        std::cin >> 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 <iostream>

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

}

2、数组的应用

1)项目设计

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

#include <iostream>

int main()
{
	int studentId[100]{ 0 };
	int indexId{};  //已等级的学生信息
	while (indexId < 100)
	{
		std::cout << "输入学号(输入0查看已等级的学生信息):";
		std::cin >> 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 <iostream>

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 <iostream>
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 <iostream>
int main()
{
	int studentId[]{ 9991,9992,9993,9994,9995,9996 };
	for (auto i : studentId)   //系统通过auto自动推断出变量类型
	{
		std::cout << i << std::endl;
	}
}

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

#include <iostream>

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

4、多维数组

1)引出多维数组:

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

//一维数组实现
#include <iostream>

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 <iostream>

//学院冬季发放大白菜,,一共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 <iostream>

//学院冬季发放大白菜,,一共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 <array>   //需要先引入头文件
std::array<变量类型,元素数量>变量名{初始化值};       //array的声明

//案例
std::array<int,5>studentId;     //5个学员的学号

2)array使用

#include <iostream>
#include <array>  //引入头文件

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

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

//std::array的几个常见用法
std::array<int,5>studentId;    //声明5个学员的学号
studentId.size();     //返回studentId拥有几个元素
studentId.fill(250);  //将studentId数组的每个元素都设置为250
studentId.at(1);      //返回studentId[1]的内容
#include <iostream>
#include <array>

int main()
{
	std::array<int, 5>studentId;    //声明5个学员的学号
	std::cout << "数组studentId拥有" << studentId.size() << "个元素" << std::endl;;     //返回studentId拥有几个元素
	studentId.fill(250);  //将studentId数组的每个元素都设置为250
	for (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 <iostream>
#include <array>

int main()
{
	int classA[3]{ 123,456 };
	int classB[3]{ 123,456 };
	std::array<int, 5>studentIdA{123,456,789};    
	std::array<int, 5>studentIdB{123,456,789};    
	std::array<int, 5>studentIdC{121,456,789 };

	std::cout << (classA == classB) << std::endl;   //返回0,说明原生数组不可以进行比较
	std::cout << (studentIdA == studentIdB) << std::endl; //返回1
	std::cout << (studentIdA == studentIdC) << std::endl;  //返回0
}

6、std::vector容器

1)std::vector语法

//vector数组的语法
#include <vector>   //需要先引入头文件
std::vector<数据类型>变量名{初始化值};       //vector的声明

//案例
std::vector<int>studentId;     //声明一个int类型的数组studentId,但是没有元素
std::vector<int>studentId{1,2,3};     //声明一个int类型的数组studentId,初始化3个元素
std::vector<int>studentId(5);     //注意是(),不是{},设置这个vector拥有5个元素
std::vector<int>studentId(5,100);     //注意是(),不是{},设置这个vector拥有5个元素,且初始值都为100

2)std::vector简单使用

#include <iostream>
#include <vector>

int main()
{
	std::vector<int> 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 <iostream>
#include <vector>

int main()
{	
	int userId;
	std::vector<int>studentId;  //定义vector数组

	do
	{
		std::cout << "请输入学号:";
		std::cin >> userId;
		if (!userId) break;  //如果学号为0,直接退出
		studentId.push_back(userId);  //向数组中动态的添加值
	} while (true);  //因为已经有跳出循环机制,不需要再利用while的判断

	for (int x : studentId)
	{
		std::cout << x << std::endl;
	}
}

热门内容