C++编程:复合数据类型—数组 c++ 复合类型
bigegpt 2024-10-16 07:54 1 浏览
C++中不仅有基本数据类型,还提供了更加灵活和丰富的复合数据类型。
在程序中为了处理方便,常常需要把具有相同类型的数据对象按有序的形式排列起来,形成“一组”数据,这就是“数组”(array)。
数组中的数据,在内存中是连续存放的,每个元素占据相同大小的空间,就像排好队一样。
1. 数组的定义
数组的定义形式如下:
数据类型 数组名[元素个数];
- 首先需要声明类型,数组中所有元素必须具有相同的数据类型;
- 数组名是一个标识符;后面跟着中括号,里面定义了数组中元素的个数,也就是数组的“长度”;
- 元素个数也是类型的一部分,所以必须是确定的;
int a1[10]; // 定义一个数组a1,元素类型为int,个数为10
const int n = 4;
double a2[n]; // 元素个数可以是常量表达式
int i = 5;
//int a3[i]; // 错误,元素个数不能为变量
需要注意,并没有通用的“数组”类型,所以上面的a1、a2的类型分别是“int数组”和“double数组”。这也是为什么我们把数组叫做“复合数据类型”。
2. 数组的初始化
之前在讲到for循环时,提到过使用范围for循环可以遍历一个“序列”,用花括号括起来的一组数就是一个序列。所以在给数组赋值时,也可以使用这样的序列。
int a3[4] = {1,2,3,4};
float a4[] = {2.5, 3.8, 10.1}; // 正确,初始值说明了元素个数是3
short a5[10] = {3,6,9}; // 正确,指定了前三个元素,其余都为0
//long a6[2] = {3,6,9}; // 错误,初始值太多
//int a6[4] = a3; // 错误,不能用另一个数组对数组赋值
需要注意的是:
- 对数组做初始化,要使用花括号{}括起来的数值序列;
- 如果做了初始化,数组定义时的元素个数可以省略,编译器可以根据初始化列表自动推断出来;
- 初始值的个数,不能超过指定的元素个数;
- 初始值的个数,如果小于元素个数,那么会用列表中的值初始化靠前的元素;剩余元素用默认值填充,整型的默认值就是0;
- 如果没有做初始化,数组中元素的值都是未定义的;这一点和普通的局部变量一致;
3. 数组的访问
(1)访问数组元素
数组元素在内存中是连续存放的,它们排好了队之后就会有一个队伍中的编号,称为“索引”,也叫“下标”;通过下标就可以快速访问每个元素了,具体形式为:
数组名[元素下标]
这里也是用了中括号来表示元素下标位置,被称为“下标运算符”。比如a[2]就表示数组a中下标为2的元素,可以取它的值输出,也可以对它赋值。
int a[] = {1,2,3,4,5,6,7,8};
cout << "a[2] = " << a[2] << endl; // a[2] = 3
a[2] = 36;
cout << "a[2] = " << a[2] << endl; // a[2] = 36
需要注意的是:
- 数组的下标从0开始;
- 因此a[2]访问的并不是数组a的第2个元素,而是第三个元素;一个长度为10的数组,下标范围是0~9,而不是1~10;
- 合理的下标,不能小于0,也不能大于 (数组长度 - 1);否则就会出现数组下标越界;
(2)数组的大小
所有的变量,都会在内存中占据一定大小的空间;而数据类型就决定了它具体的大小。而对于数组这样的“复合类型”,由于每个元素类型相同,因此占据空间大小的计算遵循下面的简单公式:
数组所占空间 = 数据类型所占空间大小 * 元素个数
这样一来,即使定义的时候没有指定数组元素个数,现在也可以计算得出了:
// a是已定义的数组
cout << "a所占空间大小:" << sizeof(a) << endl;
cout << "每个元素所占空间大小:" << sizeof(a[0]) << endl;
// 获取数组长度
int aSize = sizeof(a) / sizeof(a[0]);
cout << "数组a的元素个数:" << aSize << endl;
这里为了获取数组的长度,我们使用了sizeof运算符,它可以返回一个数据对象在内存中占用的大小(以字节为单位);数组总大小,除以每个数据元素的大小,就是元素个数。
(3)遍历数组
如果想要依次访问数组中所有的元素,就叫做“遍历数组”。我们当然可以用下标去挨个读取:
cout << "a[0] = " << a[0] << endl;
cout << "a[1] = " << a[1] << endl;
…
但这样显然太麻烦了。更好的方式是使用for循环:
// 获取数组长度
int aSize = sizeof(a) / sizeof(a[0]);
for (int i = 0; i < aSize; i++ )
{
cout << "a[" << i << "] = " << a[i] << endl;
}
循环条件如果写一个具体的数,很容易出现下标越界的情况;而如果知道了数组长度,直接让循环变量i小于它就可以了。
当然,这种写法还是稍显麻烦。C++ 11标准给我们提供了更简单的写法,就是之前介绍过的范围for循环:
for (int num: a )
{
cout << num << endl;
}
当然,这种情况下就无法获取元素对应的下标了。
4. 多维数组
之前介绍的数组只是数据最简单的排列方式。如果数据对象排列成的不是“一队”,而是一个“方阵”,那显然就不能只用一个下标来表示了。我们可以对数组进行扩展,让它从“一维”变成“二维”甚至“多维”。
int arr[3][4]; // 二维数组,有三个元素,每个元素是一个长度为4的int数组
int arr2[2][5][10]; // 三维数组
C++中本质上没有“多维数组”这种东西,所谓的“多维数组”,其实就是“数组的数组”。
l 二维数组int arr[3][4]表示:arr是一个有三个元素的数组,其中的每个元素都是一个int数组,包含4个元素;
l 三维数组int arr2[2][5][10]表示:arr2是一个长度为2的数组,其中每个元素都是一个二维数组;这个二维数组有5个元素,每个元素都是一个长度为10的int数组;
一般最常见的就是二维数组。它有两个“维度”,第一个维度表示数组本身的长度,第二个表示每个元素的长度;一般分别把它们叫做“行”和“列”。
(1)多维数组的初始化
和普通的“一维”数组一样,多维数组初始化时,也可以用花括号括起来的一组数。使用嵌套的花括号可以让不同的维度更清晰:
数据类型 数组名[行数][列数] = {数据1, 数据2, 数据3, …};
数据类型 数组名[行数][列数] = {
{数据11, 数据12, 数据13, …},
{数据21, 数据22, 数据23, …},
…
};
需要注意:
- 内嵌的花括号不是必需的,因为数组中的元素在内存中连续存放,可以用一个花括号将所有数据括在一起;
- 初始值的个数,可以小于数组定义的长度,其它元素初始化为0值;这一点对整个二维数组和每一行的一维数组都适用;
- 如果省略嵌套的花括号,当初始值个数小于总元素个数时,会按照顺序依次填充(填满第一行,才填第二行);其它元素初始化为0值;
- 多维数组的维度,可以省略第一个,由编译器自动推断;即二维数组可以省略行数,但不能省略列数。
// 嵌套的花括号的初始化
int ia[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
// 只有一层花括号的初始化
int ia2[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
// 部分初始化,其余补0
int ia3[3][4] = {
{1,2,3},
{5,6}
};
int ia4[3][4] = {1,2,3,4,5,6};
// 省略行数,自动推断
int ia5[][4] = {1,2,3,4,5};
(2)访问数据
也可以用下标运算符来访问多维数组中的数据,数组的每一个维度,都应该有一个对应的下标。对于二维数组来说,就是需要指明“行号”“列号”,这相当于数据元素在二维矩阵中的坐标。
// 访问ia的第二行、第三个数据
cout << "ia[1][2] = " << ia[1][2] << endl;
// 修改ia的第一行、第二个数据
ia[0][1] = 19;
同样需要注意,行号和列号都是从0开始、到 (元素个数 - 1) 结束。
(3)遍历数组
要想遍历数组,当然需要使用for循环,而且要扫描每一个维度。对于二维数组,我们需要对行和列分别进行扫描,这是一个双重for循环:
cout << "二维数组总大小:" << sizeof(ia) << endl;
cout << "二维数组每行大小:" << sizeof(ia[0]) << endl;
cout << "二维数组每个元素大小:" << sizeof(ia[0][0]) << endl;
// 二维数组行数
int rowCnt = sizeof(ia) / sizeof(ia[0]);
// 二维数组列数
int colCnt = sizeof(ia[0]) / sizeof(ia[0][0]);
for (int i = 0; i < rowCnt; i++)
{
for (int j = 0; j < colCnt; j++)
{
cout << ia[i][j] << "\t";
}
cout << endl;
}
同样,这里利用了sizeof运算符:
- 行数 = 二维数组总大小 / 每行大小
- 列数 = 每行大小 / 每个元素大小
当然,也可以使用范围for循环:
for (auto & row : ia)
{
for (auto num : row)
{
cout << num << "\t";
}
cout << endl;
}
这里的外层循环使用了auto关键字,这也是C++ 11新引入的特性,它可以自动推断变量的类型;后面的&是定义了一个“引用”。关于这部分内容,会在后面继续介绍。
5. 数组的简单排序算法
数组排序指的是给定一个数组,要求把其中的元素按照从小到大(或从大到小)顺序排列。
这是一个非常经典的需求,有各种不同的算法可以实现。我们这里介绍两种最基本、最简单的排序算法。
(1)选择排序
选择排序是一种简单直观的排序算法。
它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后追加到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序可以使用双重for循环很容易地实现:
#include<iostream>
using namespace std;
int main()
{
int arr[] = {5, 9, 2, 7, 4, 3, 12, 6, 1, 5, 7};
int size = sizeof(arr) / sizeof(arr[0]);
// 选择排序
for (int i = 0; i < size; i++)
{
for (int j = i + 1; j < size; j++)
{
if (arr[j] < arr[i])
{
// 如果arr[j]更小,就和arr[i]交换位置
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
// 输出
for (int num : arr)
cout << num << "\t";
cin.get();
}
(2)冒泡排序
冒泡排序也是一种简单的排序算法。
它的基本原理是:重复地扫描要排序的数列,一次比较两个元素,如果它们的大小顺序错误,就把它们交换过来。这样,一次扫描结束,我们可以确保最大(小)的值被移动到序列末尾。这个算法的名字由来,就是因为越小的元素会经由交换,慢慢“浮”到数列的顶端。
冒泡排序的代码实现也非常简单,同样是使用双重for循环:
// 冒泡排序
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size - i - 1; j++)
{
if (arr[j] > arr[j+1])
{
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
相关推荐
- 无畏契约手游测试资格获取方法,安卓IOS下载教程
-
《无畏契约:源能行动》是拳头游戏与腾讯光子工作室联合开发的《无畏契约》正版手游,延续了端游的5v5战术射击核心玩法,并针对移动端进行了操作优化。游戏以快节奏的爆破模式为核心,融合角色技能系统、经济策略...
- 微软正在测试重新设计的Office图标 但您现在可以提前下载重制版本
-
今年4月,有消息称微软正在征求用户对一组Office图标7年来首次重制版的看法(上一次重制是在2018年末)。现在,有人决定自己动手,制作了一套微软的高分辨率图标包与用户共享以获得反馈。Reddi...
- AB Download Manager:一款可以替代IDM的开源桌面下载管理器
-
软件介绍IDM下载器大家应该多少都知道一点,如果不知道的话只能自行百度了,但是IDM本身是需要付费的,而今天推荐的这款软件,在下载方面是和IDM差不多的,大概有90%的相似度,感兴趣的朋友可以体验一下...
- 《夺宝奇兵》PS5光盘仅20G:其余需联网下载
-
来源:游民星空【《夺宝奇兵》PS5光盘仅20G:其余需联网下载】据游戏测试账号“DoesItPlay1”在推特发布动态表示,《夺宝奇兵:古老之圈》PS5实体光盘只存储了20GB的游戏数据,其余内容需要...
- 薇姐聊诗词7:诗词创作韵部查询及检测工具
-
薇姐聊诗词7:诗词创作韵部查询及检测工具。·1、诗词创作中所用韵脚哪里找?平水韵:106部,分平声30部、上声29部、去声30部、入声17部,反映中古汉语语音体系。新韵:(中华新韵)14部,以普通话为...
- 阿里云国际站:怎样模拟高并发测试场景?
-
本文由【云老大】TG@yunlaoda360撰写一、使用JMeter安装JMeter:从JMeter官网下载并安装JMeter。创建测试计划:打开JMeter,创建一个新的测试计划。添加线程组...
- Android Studio 新增 AI 驱动的测试和更智能的崩溃诊断功能
-
随着GoogleI/O2025大会的落幕,值得注意的是,谷歌在AndroidStudio中引入了几项新功能,旨在改善Android应用程序的开发流程。最新版本集成了更先进的AI工...
- 如何在本地测试PHP源码的网站
-
通常,我们测试自建网站或从网上获取的PHP源码时,若直接上传到服务器,出错后再修改会很麻烦,因此一般会选择先在本地电脑上进行测试。1、先下载喜欢的源码,很多网站提供下载,如源码论坛等。这些源码是现成...
- 显卡性能测试工具3DMark06的应用教程
-
显卡作为计算机的重要组成部分,也是主要的输出设备。在计算机系统中,图形处理性能的瓶颈往往在于显卡。若要评估显卡性能,用户可以借助专业的检测工具3DMark,判断显卡是否能满足当前需求,或者是否需要...
- Downie4 安装教程(轻松获取视频素材)
-
效果一、准备工作下载软件链接:http://www.macfxb.cn二、开始安装1、双击运行软件,将其从左侧拖入右侧文件夹中,等待安装完毕2、应用程序显示软件图标,表示安装成功三、运行测试1、打开软...
- 如何使用瑞星杀毒软件的网速测试功能
-
下面为大家介绍瑞星杀毒软件的网速测试功能。1、打开安全工具,找到网速测试,点击下载后开启。2、打开网速测试页面,点击开始测试按钮。3、测试结束后,你就能知晓自己的网速了。(9744667)...
- 阿里云国际站:如何测试服务器真实带宽?
-
本文由【云老大】TG@yunlaoda360撰写基于命令行工具测试iperf/iperf3:服务器端:在服务器上安装iperf后,运行iperf-s或iperf3-s启动服务端,...
- CentOS Docker 安装
-
Docker支持以下的64位CentOS版本:CentOS9(stream)更高版本...必须启用centos-extras仓库,该仓库默认启用,如果您禁用了它,需要重新启用。使用官...
- Fast YOLO:用于实时嵌入式目标检测(附论文下载)
-
关注并星标从此不迷路计算机视觉研究院公众号ID|ComputerVisionGzq计算机视觉研究院专栏作者:Edison_G目标检测被认为是计算机视觉领域中最具挑战性的问题之一,因为它涉及场景中对象分...
- aigc检测报告与查重监测报告
-
哈喽学妹学弟们!最近是不是都在忙着写论文呢?记得当初我写论文的时候,也被AIGC检测报告和查重监测报告搞得晕头转向。不过经过我的一番摸索,终于搞清楚了它们之间的区别和联系。来来来,学姐今天就来给你们传...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- httperror403.14-forbidden (63)
- logstashinput (65)
- hadoop端口 (65)
- dockernetworkconnect (63)
- esxi7 (63)
- vue阻止冒泡 (67)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)