首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C++数组(一)(算法竞赛)

C++数组(一)(算法竞赛)

作者头像
散峰而望
发布2025-12-23 11:48:15
发布2025-12-23 11:48:15
1490
举报

前言

前面我们已经将C++的最基础最重要的一部分给讲完了,接下来我们将继续深入另一个在写代码比较常用的知识点数组,从而能够面对多种数据不再感到手忙脚乱,能够依靠编号阵列来组织,从而更好的输入或打印多种数据。

数组是一组相同类型元素的集合。从这个概念中我们就可以发现 2 个有价值的信息:

  • 数组中存放的是 1 个或者多个数据,但是数组元素个数不能为 0。
  • 数组中存放的多个数据,类型是相同的。

数组分为一维数组和多维数组,多维数组一般比较多见的是二维数组。

1. 一维数组

一维数组是最常见的,通常用来存放一组数据,一维数组是一块连续的空间。

1.1 数组创建

一维数组创建的基本语法如下:

代码语言:javascript
复制
type arr_name[常量值];

存放在数组的值被称为数组的元素,数组在创建的时候需要指定数组的大小和数组的元素类型。

  • type 指定的是数组中存放数据的类型,可以是:char、short、int、float 等,也可以自定义的类型
  • arr_name 是数组的名字,这个名字可以自定义,根据实际情况,起的有意义就行。
  • []中的常量值是用来指定数组的大小的,数组的大小是根据实际的需求指定就行。在算法竞赛中为了为了保证不越界访问,往往会多开辟一些空间,后期题目中会讲到。
  • 可以使用 const int N = 100 的方式定义常量,来指定数组的大小。
  • 例如:int arr[N] ;

比如:我们现在想存储某个公司的20人的业绩,那我们就可以创建一个数组,如下:

代码语言:javascript
复制
//第一种表现形式
int arr[20];

//第二种表现形式
const int N = 20;
int arr[N];

//第三种表现形式
#define N 4;
int arr[N];

当然我们也可以根据创建其他类型和大小的数组:

代码语言:javascript
复制
char ch[8];
double score[10];

1.2 数组的初始化

有时候,数组在创建的时候,我们需要给定一些初始值,这种就称为初始化的。那数组如何初始化呢?数组的初始化一般使用大括号,将数据放在大括号中。

代码语言:javascript
复制
//完全初始化,数据会依次放入数组
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,下标就相当于数组元素的编号,如下:

代码语言:javascript
复制
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
在这里插入图片描述
在这里插入图片描述

数组的访问提供了一个操作符[],这个操作符叫:下标引用操作符

有了下标访问操作符,我们就可以轻松的访问到数组的元素了,比如我们访问下标为 7 的元素,我们就可以使用 arr[7] ,想要访问下标是 3 的元素,就可以使用 arr[3] ,如下代码:

代码语言:javascript
复制
#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(第一个元素),计算的是数组的元素个数
代码语言:javascript
复制
#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 数组的输入输出

我们已经知道如何打印单个的数组元素,那我们该如何遍历数组中所有的元素哩?运用循环,遍历所有的数组下标就能将数组的所有的元素都打印了。

代码语言:javascript
复制
#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 语法
代码语言:javascript
复制
for ( 类型  变量名 : 数组名 )
   语句 //多条语句需要加大括号

示例:打印数组

代码语言:javascript
复制
#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 的主要用途是让编译器自动推导出变量的类型的,比如:

代码语言:javascript
复制
#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 也可以这样写:

代码语言:javascript
复制
#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

函数原型如下:

代码语言:javascript
复制
void * memset ( void * ptr, int value, size_t num );
参数解释:
ptr -- 指针:指向了要设置的内存块的起始位置
value -- 要设置的值
num -- 设置的字节个数

memset 是用来设置内存的,将内存中的值以字节为单位设置成想要的内容,需要头文件< cstring >。

1.6.1 设置数组内容

代码演示:

代码语言:javascript
复制
#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 错误使用

代码展示:

代码语言:javascript
复制
#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,比如:

代码语言:javascript
复制
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = {0};
在这里插入图片描述
在这里插入图片描述

怎么做呢?直接赋值可以吗?不行!

代码语言:javascript
复制
#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 >。

函数原型如下:

代码语言:javascript
复制
void * memcpy ( void * destination, const void * source, size_t num );
//destination -- 目标空间的起始地址 
//source      -- 源数据空间的起始地址 
//num         -- 拷⻉的数据的字节个数 

代码举例:

代码语言:javascript
复制
#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 练习

  1. 查找特定的值

思路:

  1. 输入
  2. 输入数组的元素值,得有数组
  3. 输入xx,要查找的值
  4. 查找-遍历数组,去找xx
  5. 输入下标,或者-1
代码语言:javascript
复制
#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;
 } 

提示: 一般在涉及到需要数组存放数据的时候,我们要注意:

  1. 有的题目要求数据从下标0的位置开始存放,也有些题目要求数据是从下标1的位置开始存放,要仔细阅读题目。让从下标 1 开始存放的时候,数组的开辟必须要有多余的空间使用,如果开辟的刚刚好就会越界。
  2. 数组空间的开辟要足够,以免数据越界,所以经常题目需要存放n个数据,我们就开辟 n+10 个空间,这样空间就非常充足,比较保险。其实在空间足够的情况下,浪费一点空间是不影响的。在后期学习动态规划相关算法的时候,你就会有非常明显的感觉,一般都会预留好空间。
  3. 一般数组较大的时候,建议将数组创建成全局数组,因为局部的数组太大的时候,可能会导致程序无法运行,刷题多了就⻅怪不怪了。全局变量(数组)是在内存的静态区开辟空间,但是局部的变量(数组)是在内存的栈区开辟空间的,每个程序的栈区空间是有限的,不会很大。
  4. 数组逆序重存放
  5. 向量点积计算
  6. 开关灯
  7. 小鱼比可爱

以上这些题可以自己练练手,后面会进行讲解。

结语

希望这篇文章能够让各位对一维数组有着深入的了解,同时也要多练练题巩固巩固。下一篇将要讲解二维数组

同时愿诸君能一起共渡重重浪,终见缛彩遥分地,繁光远缀天

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1. 一维数组
    • 1.1 数组创建
    • 1.2 数组的初始化
    • 1.3 数组元素访问
    • 1.4 数组元素的打印
      • 1.4.1 数组和 sizeof
      • 1.4.2 数组的输入输出
    • 1.5 范围 for
      • 1.5.1 范围 for 语法
      • 1.5.1 auto 关键字
    • 1.6 memset 设置数组内容
      • 1.6.1 memset
      • 1.6.1 设置数组内容
      • 1.6.3 错误使用
    • 1.7 memcpy 拷贝数组内容
    • 1.8 练习
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档