
🌊用有趣的言语来阐述苦涩难懂的代码世界,让每一个技术都充满风趣!
🔭个人主页: 散峰而望
🚀学习方向: C/C++等方向
📌专栏系列:
💬人生格言: 冀以尘雾之微,补益山海,荧烛末光,增辉岁月。
🎬博主简介



文章目录
- 前言
- [1. 一维数组](#1. 一维数组)
-
- [1.1 数组创建](#1.1 数组创建)
- [1.2 数组的初始化](#1.2 数组的初始化)
- [1.3 数组元素访问](#1.3 数组元素访问)
- [1.4 数组元素的打印](#1.4 数组元素的打印)
-
- [1.4.1 数组和 sizeof](#1.4.1 数组和 sizeof)
- [1.4.2 数组的输入输出](#1.4.2 数组的输入输出)
- [1.5 范围 for](#1.5 范围 for)
-
- [1.5.1 范围 for 语法](#1.5.1 范围 for 语法)
- [1.5.1 auto 关键字](#1.5.1 auto 关键字)
- [1.6 memset 设置数组内容](#1.6 memset 设置数组内容)
-
- [1.6.1 memset](#1.6.1 memset)
- [1.6.1 设置数组内容](#1.6.1 设置数组内容)
- [1.6.3 错误使用](#1.6.3 错误使用)
- [1.7 memcpy 拷贝数组内容](#1.7 memcpy 拷贝数组内容)
- [1.8 练习](#1.8 练习)
- 结语
前言
前面我们已经将C++的最基础最重要的一部分给讲完了,接下来我们将继续深入另一个在写代码比较常用的知识点数组 ,从而能够面对多种数据不再感到手忙脚乱,能够依靠编号 和阵列来组织,从而更好的输入或打印多种数据。
数组是一组相同类型元素的集合。从这个概念中我们就可以发现 2 个有价值的信息:
- 数组中存放的是 1 个或者多个数据,但是数组元素个数不能为 0。
- 数组中存放的多个数据,类型是相同的。
数组分为一维数组和多维数组,多维数组一般比较多见的是二维数组。
1. 一维数组
一维数组是最常见的,通常用来存放一组数据,一维数组是一块连续的空间。

1.1 数组创建
一维数组创建的基本语法如下:
c
type arr_name[常量值];
存放在数组的值被称为数组的元素,数组在创建的时候需要指定数组的大小和数组的元素类型。
- type 指定的是数组中存放数据的类型,可以是:char、short、int、float 等,也可以自定义的类型
- arr_name 是数组的名字,这个名字可以自定义,根据实际情况,起的有意义就行。
-
\]中的常量值是用来指定数组的大小的,数组的大小是根据实际的需求指定就行。在算法竞赛中为了为了保证不越界访问,往往会多开辟一些空间,后期题目中会讲到。
- 例如:int arr[N] ;
比如:我们现在想存储某个公司的20人的业绩,那我们就可以创建一个数组,如下:
cpp
//第一种表现形式
int arr[20];
//第二种表现形式
const int N = 20;
int arr[N];
//第三种表现形式
#define N 4;
int arr[N];
当然我们也可以根据创建其他类型和大小的数组:
cpp
char ch[8];
double score[10];
1.2 数组的初始化
有时候,数组在创建的时候,我们需要给定一些初始值,这种就称为初始化的。那数组如何初始化呢?数组的初始化一般使用大括号,将数据放在大括号中。
cpp
//完全初始化,数据会依次放入数组
int arr[6] = {1,2,3,4,5,6};
//不完全初始化
int arr[6] = {1};
//第一个元素初始化为1,剩余元素默认初始化为0
//错误的初始化 - 初始化项太多
int arr[3] = {1,2,3,4};
1.3 数组元素访问
数组是有下标的,下标是从 0 开始的,假设数组有 n 个元素,最后一个元素的下标是 n-1,下标就相当于数组元素的编号,如下:
cpp
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

数组的访问提供了一个操作符[] ,这个操作符叫:下标引用操作符。
有了下标访问操作符,我们就可以轻松的访问到数组的元素了,比如我们访问下标为 7 的元素,我们就可以使用 arr[7] ,想要访问下标是 3 的元素,就可以使用 arr[3] ,如下代码:
cpp
#include<iostream>
using namespace std;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
cout << arr[7] << endl;
cout << arr[3] << endl;
return 0;
}
演示结果:

1.4 数组元素的打印
接下来,如果想要访问整个数组的内容,那怎么办呢?
只要我们产生数组所有元素的下标就可以了,那我们使用 for 循环产生所有的下标,接下来使用下标访问就行了。
注意:如果产生的下标超出了有效下标的范围,比如,使用负数作为下标,或者超出了下标的最大值,再使用这个下标访问元素就会造成:越界访问。越界访问访问的时候,代码编译时语法没报错,但是运行时一定会出问题的。
1.4.1 数组和 sizeof
- sizeof(数组名),计算的是数组的总大小,单位是字节
- sizeof(数组名) / sizeof(第一个元素),计算的是数组的元素个数
cpp
#include<iostream>
using namespace std;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
cout << sizeof(arr) << endl;
cout << sizeof(arr) / sizeof(arr[0]) << endl;
return 0;
}
演示结果:

1.4.2 数组的输入输出
我们已经知道如何打印单个的数组元素,那我们该如何遍历数组中所有的元素哩?运用循环,遍历所有的数组下标就能将数组的所有的元素都打印了。
cpp
#include <iostream>
using namespace std;
int main()
{
int arr[5] = {0};
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
//输入
for(i = 0; i < sz; i++)
{
cin >> arr[i];
}
//输出
for(i = 0; i < sz; i++)
{
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
演示结果:

1.5 范围 for
打印数组元素除了可以使用之前讲过的三种循环外,还有一个更方便的方式,使用范围 for。范围 for 是在 C++11 这个标准中引入的,如果你使用的编译器默认不支持C++11,可能需要配置才能使用。如果没有配置可能会报出这样的错误:
Error\]range-based 'for' 100ps are not allowed in C++98 mode
以DevC++为例教程:Dev-C++一些问题的处理
1.5.1 范围 for 语法
cpp
for ( 类型 变量名 : 数组名 )
语句 //多条语句需要加大括号
示例:打印数组
cpp
#include<iostream>
using namespace std;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(int x : arr)
{
cout << x << " ";
}
return 0;
}
上面代码中的 for 就是范围 for,代码的意思是将 arr 数组中的元素,依次放在 x 变量中,然后打印 x,直到遍历完整个数组的元素,仍发挥着循环的作用。这里的 x 是一个单独的变量,不是数组的元素,所以对 x 的修改,不会影响数组。
但是对于范围 for 要慎重使用!范围 for 是对数组中所有元素进行遍历的,但是我们实际在做题的过程中,可能只需要遍历数组中指定个数 的元素,这样范围 for 就不合适了。
1.5.1 auto 关键字
auto 的主要用途是让编译器自动推导出变量的类型的,比如:
cpp
#include <iostream>
using namespace std;
int main()
{
auto a = 3.14;
auto b = 100;
auto c = 'x';
return 0;
}

可以看到使用 vs 2022 调试监视时,a、b、c都推导出变量的类型。
使用 auto 类型,上面的范围 for 也可以这样写:
cpp
#include <iostream>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (auto e : arr) //auto能够自动推导数组中每个元素的数据类型,在数组范围内遍历打印元素
{
cout << e << " ";
}
return 0;
}
演示结果:

范围 for 中 e 前面的类型可以可以是 auto 关键字,当你不知道数组中放什么类型的时候,可以使用 auto 作为类型,auto 在范围 for 中很常用。如果明确的知道数组元素的数据类型,也可以将 auto 换成对应的数据类型。
1.6 memset 设置数组内容
1.6.1 memset
函数原型如下:
cpp
void * memset ( void * ptr, int value, size_t num );
参数解释:
ptr -- 指针:指向了要设置的内存块的起始位置
value -- 要设置的值
num -- 设置的字节个数
memset 是用来设置内存的,将内存中的值以字节为单位设置成想要的内容,需要头文件< cstring >。
1.6.1 设置数组内容
代码演示:
cpp
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char str[] = "hello world";
memset(str, 'x', 6);
cout << str << endl;
int arr[] = {1,2,3,4,5};
memset(arr, 0, sizeof(arr));//这里数组的大小也可以自己计算
for(auto i : arr)
{
cout << i << " ";
}
cout << endl;
return 0;
}
演示结果:

传输过程演示:

1.6.3 错误使用
代码展示:
cpp
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int arr[] = { 1,2,3,4,5 };
memset(arr, 1, 4 * sizeof(int));
for (auto e : arr)
{
cout << e << " ";
}
cout << endl;
return 0;
}
演示结果:

Dev-C++ 应该对其有优化,输入的还是正常值,所以用 vs 2022 演示

从上面打印结果可以看出,当 value 设置为 1 或者其他非 0 的数字时,打印结果不符合预期。
主要原因是 memset 函数是给每个字节设置 value 值,而一个整型元素占用 4 个字节,一个整型的每个字节都被设置为 1,二进制就是:00000001000000010000000100000001,转换成十进制就是:16843009,因此结果是不符合预期的。
1.7 memcpy 拷贝数组内容
在使用数组的时候,有时候我们需要将数组 a 的内容给数组 b,比如:
cpp
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = {0};

怎么做呢?直接赋值可以吗?不行!
cpp
#include<iostream>
using namespace std;
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = {0};
b = a;
cout << b << endl;
return 0;
}
演示结果:

其实 C++ 中有一个库函数 memcpy 可以做数组内容的拷贝,当然 memcpy 其实是用来做内存块的拷贝的,当然用来做数组内容的拷贝也是没问题的。memcpy 需要的头文件是< cstring >。
函数原型如下:
cpp
void * memcpy ( void * destination, const void * source, size_t num );
//destination -- 目标空间的起始地址
//source -- 源数据空间的起始地址
//num -- 拷⻉的数据的字节个数
代码举例:
cpp
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = {0};
memcpy(b, a, 10 * sizeof(int));
for(int e: b)
{
cout << e << " ";
}
return 0;
}
演示结果:

当然如果拷贝 double 类型的数组时,计算时应该使用 sizeof(double),要灵活变化。
1.8 练习
思路:
- 输入
- 输入数组的元素值,得有数组
- 输入xx,要查找的值
- 查找-遍历数组,去找xx
- 输入下标,或者-1
cpp
#include<iostream>
using namespace std;
const int N = 10010;//多开辟空间,防止数组越界
//又因为n<=10000,所以设10010
int arr[N];
int main()
{
int n = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
int k = 0;
cin >> k;
int i = 0;
for (i = 0; i < n; i++)
{
if (k == arr[i])
{
cout << i << endl;
break;
}
}
if (i == n)
cout << -1 << endl;
return 0;
}
提示:
一般在涉及到需要数组存放数据的时候,我们要注意:
- 有的题目要求数据从下标0的位置开始存放,也有些题目要求数据是从下标1的位置开始存放,要仔细阅读题目。让从下标 1 开始存放的时候,数组的开辟必须要有多余的空间使用,如果开辟的刚刚好就会越界。
- 数组空间的开辟要足够,以免数据越界,所以经常题目需要存放n个数据,我们就开辟 n+10 个空间,这样空间就非常充足,比较保险。其实在空间足够的情况下,浪费一点空间是不影响的。在后期学习动态规划相关算法的时候,你就会有非常明显的感觉,一般都会预留好空间。
- 一般数组较大的时候,建议将数组创建成全局数组,因为局部的数组太大的时候,可能会导致程序无法运行,刷题多了就⻅怪不怪了。全局变量(数组)是在内存的静态区开辟空间,但是局部的变量(数组)是在内存的栈区开辟空间的,每个程序的栈区空间是有限的,不会很大。
以上这些题可以自己练练手,后面会进行讲解。
结语
希望这篇文章能够让各位对一维数组 有着深入的了解,同时也要多练练题巩固巩固。下一篇将要讲解二维数组。
同时愿诸君能一起共渡重重浪,终见缛彩遥分地,繁光远缀天。

