数组
在C++中,数组是一种将相同类型元素存储在一起的数据结构。当然,在其他语言,也基本都是如此。
数组有一些特点(不是优点):
- 固定大小:一旦创建,数组的大小就固定了,不能动态改变。
- 元素类型一致性:数组中的所有元素必须具有相同的类型。
- 通过索引访问:可以通过整数索引来访问数组中的特定元素,索引通常从 0 开始([通常]只是这么一说,就是从0开始的)。
- 连续存储:元素在内存中是连续存储的,这使得可以快速地顺序访问元素 (可以理解为学生排了一个队伍)。
- 声明和初始化:可以在声明时进行初始化,例如 int arr[5] = {1, 2, 3, 4, 5}。(也可以声明的时候不初始化)
- 多维数组:C++也支持多维数组,如二维数组等。
数组在 C++中是一种基础且常用的数据结构,广泛应用于各种程序中,用于批量处理数据(这个只是最常用的场景)等场景。
在C++中,数组到底可以用来干什么呢?
我们可以在数组中存储如一组学生的成绩、一组学生的姓名等信息;
还可以基于数组去模拟后面要学习的堆和栈的一些基本操作;
另外,在前面的排序算法中我们操作的都是数组,很多算法的学习都是基于数组来的。
数组还可以用来模拟大数,可以干很多事情的。记住数组的特点,到用的时候你就知道要用它。
数组在内容中的存储方式就像下图这样,是紧挨着的(顺序存储、如果不挨着就丢了)。
如:在代码中使用代码定义了
int a[10] = {0,0,0,0,0,0,0,0,0,0};
计算机会给数组a[10]分配了一块连续的内存空间,方便起见,地址区间记为:1000~1039。其中,内存块的首地址为base_address = 1000。
图中,第一行是访问数组时候用的下标,从0开始,明确标记每一位的位置,第二行是数组每位所占用的内存地址区间(为什么是区间,下面有讲)。
计算机会为每个内存单元分配一个地址,计算机通过地址来访问内存中的数据。当计算即需要随机访问数组中的某个元素的时候,它会首先通过下面的寻址公式,计算该元素存存储的内存地址:
a[i]_address = base_address + i * data_type_size
其中data_type_size表示数组中每个元素的大小。例如,数组中存储的int类型的数据,所以,data_type_size就是4字节。
正式数组在内存中如此存储。所以,随机访问数组的某一个值很方便(因为可以直接计算出它的内存地址)。但是如果要在数组中插入数据就很麻烦,所以,一般我们很少在数组中进行插入、移出这种操作。
下面这段代码可以展示了如何在数组中插入一个数据:
#include <iostream>
using namespace std;
// 在数组指定位置插入数据的函数
void insertIntoArray(int arr[], int size, int value, int position) {
// 这个循环将要插入数据之后的值依次后移了一位
for (int i = size; i > position; i--) {
arr[i] = arr[i - 1];
}
arr[position] = value;
}
int main() {
int arr[10] = {10, 20, 30, 40, 50};
int newSize = 6; // 插入数据后数组中的有效数据个数
int valueToInsert = 25; // 要插入的数据
int positionToInsert = 2; // 要插入的位置下标
insertIntoArray(arr, newSize - 1, valueToInsert, positionToInsert);
for (int i = 0; i < newSize; i++) {
cout << arr[i] << " ";
}
return 0;
}
数组的所有操作都不能改变它的大小。
本文不涉及多维数组。刚开始,先理解并用好一维数组,多维数组在用到的时候再聊。
因为在使用数组的时候我们会用到指针,所以我们也提前对指针做了简单的介绍:指针和引用
今天这篇主要是介绍数组的基础用法。
声明数组
type arrayName [ arraySize ];
type是类型,arrayName是数组名字,arraySize是数组大小。
在这三个部分中,数组名字没啥好说的。重点在于类型和数组大小。
回顾一下之前讲过的数组特点:
固定大小:一旦创建,数组的大小就固定了,不能动态改变。
元素类型一致性:数组中的所有元素必须具有相同的类型。
javascript:void(function(){ window.parent.parent.window.__templateCardIframeWrite(document, ‘1716306290931’, ‘insert_blockquote_source_iframe_ready_0’, true);}())
一个数组虽然存了一些列的元素,但是这些元素的类型是固定且相同的。所以这里的类型虽然修饰的是数组,但是它代表的是数组的每个元素的类型。
看下下面这段代码:
#include <iostream>
using namespace std;
int main() {
int age[10]; // 声明存储10个int数据的数组
double salary[10]; // 声明存储10个double数据的数组
int* p[10]; // 声明存储10个int指针数据的数组
for(int i=0;i<10;i++){
cout<< age[i] << "\t";
}
cout<<endl;
for(int i=0;i<10;i++){
cout<< salary[i] << "\t";
}
cout<<endl;
for(int i=0;i<10;i++){
cout<< p[i] << "\t";
}
cout<<endl;
return 0;
}
编译运行没有报错,但是结果有点奇怪:
为什么打印的值会看起来乱七八糟?是因为我们没有初始化!每个变量都应该尽量及时初始化,避免出现不可预计的错误。
上面的红字是一个忠告。继续回头来看数组。
初始化数组
那如何初始化数组呢?再看下面这段代码:
#include <iostream>
using namespace std;
int main() {
int age[10] = {10,20}; // 声明存储10个int数据的数组,指定age[0]=10,age[1]=20
double salary[10] = {10.1}; // 声明存储10个double数据的数组,指定salary[0]=10.1
int* p[10] = {0}; // 声明存储10个int指针数据的数组,声明所有元素的值为0
for(int i=0;i<10;i++){
cout<< age[i] << "\t";
}
cout<<endl;
for(int i=0;i<10;i++){
cout<< salary[i] << "\t";
}
cout<<endl;
for(int i=0;i<10;i++){
cout<< p[i] << "\t";
}
cout<<endl;
return 0;
}
运行结果:
结合代码的注释和运行结果可以对初始化有初步的认识。
访问数组元素
前面代码中的age[i], salary[i], p[i]就是在读取元素值了。
获取数组大小
下面这段代码在之前讲排序的时候有多次用到。
int arr[] = {64, 34, 25, 12, 22, 11, 90}; // 要排序的一维数组
int n = sizeof(arr) / sizeof(arr[0]); // 获取数组的长度,sizeof用来获取当前对象在内存中占用的大小
今天的使用数组就聊到这里了。截止到这里,排序算法里面对数组的基本使用都已经讲到了。
后面到函数部分的时候,会再次对数组做进一步的说明。
公众号中的文章是按阶段分开的,博客里面是不断完善的。