在之前的学习中,我们用变量来存储数据。但如果需要存储全班30个同学的成绩,定义30个变量就太麻烦了。数组就是用来解决这个问题的——它可以用一个名字存储多个同类型的数据,并且在定义时需要确定数组的大小。
你可以把数组想象成一排编了号的储物柜:每个柜子存放一个数据,通过编号(下标)就能快速找到对应的数据。
| 下标 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 元素 | arr[0] | arr[1] | arr[2] | arr[3] | arr[4] |
| 值 | 10 | 20 | 30 | 40 | 50 |
| 地址 | 0x1000 | 0x1004 | 0x1008 | 0x100C | 0x1010 |
数组在内存中是连续存储的。因为每个 int 占 4 字节,所以相邻元素的地址相差 4。知道数组首地址和下标,就能直接算出任意元素的地址(首地址 + 下标 × 4),这就是数组能通过下标快速访问元素的原因。
数组按照维度可以分为一维数组和多维数组:
arr[3] 就能找到第4个柜子。本节课先学习一维数组,多维数组会在后面的课程中学到。
定义一维数组时,需要说明数据类型、数组名称和数组大小。其中数组的命名规则和变量的命名规则相同,数组的大小用[]加数字的形式表述。
int arri[10];
double arrd[1];
bool arrb[12];由于竞赛时有内存限制,所以建议在主函数外定义数组。
关于一维数组的大小,有几点需要额外注意:
int n;
cin >> n;
int arr[n]; //不要通过这种形式定义一个数组int N = 100000;
int arr1[N];
double arr2[N];int arr['0']; //创建一个大小为48的数组使用{}的方式对一维数组进行初始化,必须在定义数组时对其进行初始化。若{}内填写数值,则按照顺序对数组内元素进行赋值,未填写部分补0。
int arr[10] = {}; // 初始化为全0
int arr[5] = {1, 2}; // 将第一个数初始化为1,第二个数初始化为2,其余所有数初始化为0
int arr[5] = {0}; // 将第一个数初始化为0,其余所有数初始化为0
int arr[5] = {2, 3, 8, 1, 3}; // 整个数组初始化为2,3,8,1,3需要添加头文件,可以在任意位置对数组进行赋值,将数组元素全部设置为某一个值。使用fill_n需要填写三部分内容:数组名称、数据个数和初始化的数值,初始化的数值可以为任意值。
1#include <iostream>
2#include <algorithm>
3using namespace std;
4
5int arr[105];
6
7int main () {
8 fill_n(arr, 105, 1);
9 return 0;
10}memset是C语言风格的初始化方式,可以在任意位置对数组进行赋值,将数组元素全部设置为某一个值。
使用memset需要填写三部分内容:数组名称、初始化数值和数组大小。
其中初始化的数值一般使用16进制表示,常用数值为:0、1、-1、0x3f、0x7f,其中0x3f和0x7f都表示一个比较大的整数。
另外数组大小不是数组里面存储的数值的个数,而是占用内存的大小。
1#include <iostream>
2#include <algorithm>
3using namespace std;
4
5int arr[105];
6
7int main () {
8 memset(arr, 0, sizeof(arr));
9 memset(arr, 1, sizeof(arr));
10 memset(arr, -1, sizeof(arr));
11 memset(arr, 0x3f, sizeof(arr));
12 memset(arr, 0x7f, sizeof(arr));
13 return 0;
14}将数组初始化为全0有以下5种方式:
arr[3] = {};arr[3] = {0};arr[3] = {0, 0, 0};fill_n(arr, 3, 0);memset(arr, 0, sizeof(arr));一维数组只需要一个下标就能定位元素。我们使用数组名称[下标]的形式访问数组,可以通过该方式获取到下标位置的元素的值或者对该位置进行赋值。
1#include <iostream>
2#include <algorithm>
3using namespace std;
4
5int arr[105];
6
7int main () {
8 fill_n(arr, 105, 1);
9 arr[10] = 2; //对某个位置进行赋值
10 arr[20] = 4; //对某个位置进行赋值
11 for (int i = 0; i < 105; i++) { // 使用循环遍历数组的所有下标
12 cout << arr[i] << " "; // 获取某个位置的数值
13 }
14 return 0;
15}访问数组元素需要注意以下几点:
arr[i-1]这样的操作时,一定要注意检查i-1是否大于等于0。arr[i+1]这样的操作时,一定要注意检查i+1是否小于n。int arr[5] = {1, 2, 3, 4, 5};
// 错误:访问了 arr[5],下标最大只能到4
for (int i = 0; i <= 5; i++) {
cout << arr[i];
}int arr[1000000];)会导致栈溢出。解决方法是将大数组定义在主函数外部(全局变量区)。int n; cin >> n; int arr[n]; 这种写法在某些编译器上能通过,但它不是标准C++的做法,在竞赛中应该避免。正确做法是预先定义一个足够大的数组。memset(arr, 1, sizeof(arr)) 并不会将每个int元素设为1,而是将每个字节设为1,得到的int值是16843009。memset只适合初始化为0、-1或特殊值(0x3f、0x7f)。