「C++系列」数组

news2024/11/17 16:00:53

文章目录

  • 一、数组
    • 1. 声明数组
    • 2. 初始化数组
    • 3. 访问数组元素
    • 4. 遍历数组
    • 注意事项
    • 示例代码
  • 二、多维数组
    • 1. 声明二维数组
    • 2. 初始化二维数组
    • 3. 访问二维数组元素
    • 4. 遍历二维数组
    • 注意事项
    • 示例代码
  • 三、指向数组的指针
    • 1. 声明指向数组的指针
    • 2. 通过指针访问数组元素
    • 3. 指针和数组的关系
    • 4. 使用指向数组的指针进行排序
  • 四、传递数组给函数
    • 方法1:传递数组名和大小
    • 方法2:使用引用传递数组(不推荐用于原始数组)
    • 方法3:使用模板和引用传递(对于固定大小的数组)
    • 注意事项
  • 五、从函数返回数组
    • 方法1:返回指向静态数组的指针
    • 方法2:使用 `std::array` 或 `std::vector`
      • 使用 `std::array`
      • 使用 `std::vector`
    • 方法3:返回指向动态分配数组的指针(需要手动管理内存)
  • 六、相关链接

一、数组

C++ 中的数组是一种基础的数据结构,用于存储相同类型的数据的集合。数组中的每个元素可以通过索引(或下标)来访问,索引通常是从 0 开始的。数组的大小在声明时必须指定,并且之后不能改变(尽管可以通过一些技巧如动态内存分配来模拟可变大小的数组,但这通常涉及到指针和动态内存管理)。
在这里插入图片描述

1. 声明数组

数组的声明需要指定数组的类型和大小。例如,声明一个整型数组 arr,包含 5 个元素:

int arr[5];

2. 初始化数组

在声明数组的同时,可以初始化数组中的元素。例如:

int arr[5] = {1, 2, 3, 4, 5};

如果初始化时提供的元素少于数组的大小,则未明确初始化的元素将被自动初始化为零(对于内置类型如 intfloat 等)。

3. 访问数组元素

使用索引来访问数组中的元素。索引是从 0 开始的。例如,访问上面声明的数组 arr 的第一个元素:

int firstElement = arr[0]; // firstElement 的值为 1

4. 遍历数组

遍历数组通常使用循环结构,如 for 循环。例如,打印数组 arr 的所有元素:

for (int i = 0; i < 5; i++) {
    std::cout << arr[i] << " ";
}
std::cout << std::endl;

注意事项

  • 数组的大小在编译时确定,之后不能改变。
  • 数组越界是未定义行为,可能导致程序崩溃或数据损坏。因此,访问数组元素时要确保索引在有效范围内。
  • C++ 标准库提供了 std::vector 容器,它是一个更灵活、更安全的数组替代品,能够动态地增长和缩小。

示例代码

下面是一个完整的示例,展示了如何声明、初始化、访问和遍历数组:

#include <iostream>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};

    // 访问数组的第一个元素
    std::cout << "第一个元素是: " << arr[0] << std::endl;

    // 遍历数组并打印所有元素
    for (int i = 0; i < 5; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出将是:

第一个元素是: 1
1 2 3 4 5 

二、多维数组

C++ 中的多维数组是数组的数组,用于存储具有两个或更多维度的数据。最常见的是二维数组,但它可以扩展到更高维度。多维数组中的每个元素都可以通过一组索引来访问,这些索引对应于数组的每个维度。

1. 声明二维数组

二维数组可以看作是数组的数组,其中每个内部数组(或行)具有相同数量的元素。以下是声明二维数组的语法:

type arrayName[rows][columns];

其中 type 是数组元素的类型,arrayName 是数组的名称,rows 是数组的行数,columns 是数组的列数。

2. 初始化二维数组

在声明二维数组时,可以立即初始化它。如果初始化时省略了某些元素,则这些元素将被自动初始化为零(对于内置类型)。

int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

如果初始化时只提供了部分行,则剩余的行将被自动初始化为零。

3. 访问二维数组元素

二维数组中的元素通过两个索引来访问:第一个索引指定行,第二个索引指定列。

int secondRowThirdColumn = matrix[1][2]; // 值为 7

4. 遍历二维数组

遍历二维数组通常涉及嵌套循环,外层循环遍历行,内层循环遍历列。

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        std::cout << matrix[i][j] << " ";
    }
    std::cout << std::endl;
}

注意事项

  • 多维数组的大小在编译时确定,之后不能改变。
  • 访问数组元素时要确保索引在有效范围内,以避免数组越界。
  • C++ 标准库中的 std::vector<std::vector<T>> 可以作为二维数组的替代品,提供更大的灵活性和动态内存管理。

示例代码

以下是一个完整的示例,展示了如何声明、初始化、访问和遍历二维数组:

#include <iostream>

int main() {
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    // 访问并打印第二行第三列的元素
    std::cout << "第二行第三列的元素是: " << matrix[1][2] << std::endl;

    // 遍历并打印整个二维数组
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            std::cout << matrix[i][j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

输出将是:

第二行第三列的元素是: 7
1 2 3 4 
5 6 7 8 
9 10 11 12 

三、指向数组的指针

在C++中,指向数组的指针是一个特殊的指针,它指向数组的第一个元素的地址。通过这个指针,我们可以访问和修改数组中的元素。然而,需要注意的是,指针本身并不知道它所指向的数组的大小,这意味着在通过指针遍历数组时,我们需要知道何时停止,以避免越界访问。

1. 声明指向数组的指针

当我们声明一个指向数组的指针时,我们通常会让它指向数组的第一个元素。指针的类型应该与数组元素的类型相匹配。

int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr; // ptr 指向 arr 的第一个元素

在这里,ptr 是一个指向 int 的指针,它被初始化为指向 arr 数组的第一个元素。由于数组名(在这里是 arr)在大多数表达式中会被解释为指向其第一个元素的指针,所以上面的 ptr = arr; 是合法的。

2. 通过指针访问数组元素

一旦我们有了指向数组第一个元素的指针,我们就可以使用指针算术来访问数组中的其他元素。

#include <iostream>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int* ptr = arr;

    // 使用指针访问数组元素
    for (int i = 0; i < 5; i++) {
        std::cout << *(ptr + i) << " "; // 等同于 arr[i]
    }
    std::cout << std::endl;

    return 0;
}

3. 指针和数组的关系

在C++中,数组名在很多情况下会被隐式地转换为指向其第一个元素的指针。但是,有几个重要的区别:

  1. 大小信息丢失:当数组名被用作指针时,它不再携带关于数组大小的信息。因此,通过指针遍历数组时,我们需要知道数组的大小。
  2. 类型不同:尽管在大多数上下文中数组名可以像指针一样使用,但它们的类型是不同的。数组名是一个常量指针,指向数组的第一个元素,并且它的类型是“N个T类型的数组”,其中N是数组的大小,T是元素的类型。而指针是一个指向T类型对象的变量。
  3. 使用 sizeof 操作符:对数组使用 sizeof 会返回整个数组的大小(以字节为单位),而对指针使用 sizeof 会返回指针本身的大小(这取决于平台和编译器)。

4. 使用指向数组的指针进行排序

下面是一个简单的示例,展示了如何使用指向数组的指针来对数组进行排序(这里使用冒泡排序作为示例)。

#include <iostream>

void bubbleSort(int* arr, int n) {
    for (int i = 0; i < n-1; i++) {
        for (int j = 0; j < n-i-1; j++) {
            if (*(arr + j) > *(arr + j + 1)) {
                // 交换 arr[j] 和 arr[j+1]
                int temp = *(arr + j);
                *(arr + j) = *(arr + j + 1);
                *(arr + j + 1) = temp;
            }
        }
    }
}

int main() {
    int arr[5] = {5, 3, 8, 4, 2};
    int n = sizeof(arr)/sizeof(arr[0]);

    bubbleSort(arr, n);

    for (int i = 0; i < n; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

四、传递数组给函数

在C++中,传递数组给函数通常是通过传递数组的指针来完成的。由于数组名在大多数情况下会被解释为指向其第一个元素的指针,因此你可以直接将数组名作为参数传递给函数。然而,这种方式并不会传递数组的大小,所以通常还需要将数组的大小作为另一个参数传递给函数。

方法1:传递数组名和大小

这是最常见的方法,你将数组名(实际上是指向数组第一个元素的指针)和数组的大小作为两个独立的参数传递给函数。

#include <iostream>

// 函数声明,接收指向int的指针和数组的大小
void printArray(int* arr, int size) {
    for (int i = 0; i < size; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
}

int main() {
    int myArray[5] = {1, 2, 3, 4, 5};
    // 传递数组名和大小给函数
    printArray(myArray, 5);
    return 0;
}

方法2:使用引用传递数组(不推荐用于原始数组)

需要注意的是,在C++中你不能直接传递数组的引用(如 void func(int (&arr)[5]); 这样的声明在函数模板之外是不允许的,因为它要求数组的大小在编译时已知)。然而,你可以通过传递指向数组的指针来模拟这种行为,或者如果你在处理的是固定大小的数组,并且希望避免传递大小参数,你可以考虑使用模板(但这不是传递数组的“引用”,而是类型推导)。

方法3:使用模板和引用传递(对于固定大小的数组)

虽然这不是直接传递数组给函数的标准方式,但如果你在处理固定大小的数组,并且想要避免传递大小参数,你可以使用模板。

#include <iostream>

// 模板函数,用于处理固定大小的数组
template<size_t N>
void printFixedArray(int (&arr)[N]) {
    for (size_t i = 0; i < N; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
}

int main() {
    int myArray[5] = {1, 2, 3, 4, 5};
    // 使用模板函数,不需要传递大小
    printFixedArray(myArray);
    return 0;
}

注意事项

  • 当通过指针传递数组时,请确保在函数内部不会越界访问数组。
  • 传递数组时,并不会复制数组本身,而是传递了指向数组第一个元素的指针。因此,函数内部对数组元素的修改将影响原始数组。
  • 如果你正在处理动态分配的数组(例如,使用 new 关键字分配的数组),请确保在不再需要时释放内存(使用 delete[])。然而,在传递动态分配的数组给函数时,你通常只需要传递指向数组的指针,而不需要传递数组的大小(如果函数内部有逻辑来确定大小的话),但最佳实践是始终传递大小以避免潜在的错误。

五、从函数返回数组

在C++中,直接从函数返回一个数组本身是不被直接支持的,因为数组名在表达式中通常会被视为指向其第一个元素的指针,而不是一个可以返回的对象。但是,有几种方法可以模拟从函数返回数组的行为。

方法1:返回指向静态数组的指针

这种方法涉及在函数内部定义一个静态数组,并返回指向该数组的指针。然而,这种方法有局限性,因为它返回的总是同一个数组的引用,可能在多线程环境下导致问题,并且数组的大小在编译时就已确定。

#include <iostream>

int* returnArray() {
    static int arr[] = {1, 2, 3, 4, 5};
    return arr;
}

int main() {
    int* myArray = returnArray();
    for (int i = 0; i < 5; i++) {
        std::cout << myArray[i] << " ";
    }
    std::cout << std::endl;
    return 0;
}

方法2:使用 std::arraystd::vector

std::array 是一个固定大小的数组容器,而 std::vector 是一个可变大小的数组容器。它们都提供了复制和移动语义,因此可以直接从函数返回。

使用 std::array

#include <iostream>
#include <array>

std::array<int, 5> returnArray() {
    return {1, 2, 3, 4, 5};
}

int main() {
    std::array<int, 5> myArray = returnArray();
    for (int i : myArray) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

使用 std::vector

#include <iostream>
#include <vector>

std::vector<int> returnArray() {
    return {1, 2, 3, 4, 5};
}

int main() {
    std::vector<int> myArray = returnArray();
    for (int i : myArray) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

方法3:返回指向动态分配数组的指针(需要手动管理内存)

这种方法涉及在堆上动态分配数组,并返回指向该数组的指针。调用者需要负责在不再需要时释放内存。

#include <iostream>

int* returnArray(int size) {
    int* arr = new int[size];
    for (int i = 0; i < size; i++) {
        arr[i] = i + 1;
    }
    return arr;
}

int main() {
    int* myArray = returnArray(5);
    for (int i = 0; i < 5; i++) {
        std::cout << myArray[i] << " ";
    }
    std::cout << std::endl;
    delete[] myArray; // 不要忘记释放内存
    return 0;
}

在这里插入图片描述

六、相关链接

  1. Visual Studio Code下载地址
  2. Sublime Text下载地址
  3. 「C++系列」C++简介、应用领域
  4. 「C++系列」C++ 基本语法
  5. 「C++系列」C++ 数据类型
  6. 「C++系列」C++ 变量类型
  7. 「C++系列」C++ 变量作用域
  8. 「C++系列」C++ 常量知识点-细致讲解
  9. 「C++系列」C++ 修饰符类型
  10. 「C++系列」一篇文章说透【存储类】
  11. 「C++系列」一篇文章讲透【运算符】
  12. 「C++系列」循环
  13. 「C++系列」判断
  14. 「C++系列」函数/内置函数
  15. 「C++系列」数字/随机数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1955894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件上传漏洞(ctfshow web151-161)

Web151 F12修改源代码 exts后面png改为php 这样就可以上传php的文件了 Web152&#xff1a; 考点&#xff1a;后端不能单一校验 就是要传图片格式&#xff0c;抓个包传个png的图片 然后bp抓包修改php后缀解析 然后放包 Web153-web156 在php代码中可以使用“{}”代替“[]” …

Go语言实战:基于Go1.19的站点模板爬虫技术解析与应用

一、引言 1.1 爬虫技术的背景与意义 在互联网高速发展的时代&#xff0c;数据已经成为新的石油&#xff0c;而爬虫技术则是获取这种“石油”的重要工具。爬虫&#xff0c;又称网络蜘蛛、网络机器人&#xff0c;是一种自动化获取网络上信息的程序。它广泛应用于搜索引擎、数据分…

机械学习—零基础学习日志(高数14——函数极限概念)

零基础为了学人工智能&#xff0c;真的开始复习高数 后续的速度要加快了~&#xff01;~~~&#xff01;&#xff01; 概念 如何理解 方法一&#xff1a;吴军老师——无穷小是一种动态概念 函数极限&#xff0c;更多表达的是一种动态趋势&#xff0c;而不是一种静态的数值。以…

linux脚本:自动检测的bash脚本,用于检查linux的系统性能

目录 一、要求 二、脚本介绍 1、脚本内容 2、解释 3、使用方法&#xff1a; &#xff08;1&#xff09;脚本文件 &#xff08;2&#xff09;赋予权限 &#xff08;3&#xff09;执行结果 三、相关命令介绍 1、top &#xff08;1&#xff09;定义 &#xff08;2&…

Springboot 整合Elasticsearch

1 java操作ES方式 1.1 操作ES 9300端口(TCP) 但开发中不在9300进行操作 ES集群节点通信使用的也是9300端口如果通过9300操作ES&#xff0c;需要与ES建立长连接 可通过引入spring-data-elasticsearch:transport-api.jar不在9300操作原因&#xff1a;1.springboot版本不同&…

Hive多维分析函数——With cube、Grouping sets、With rollup

有些指标涉及【多维度】的聚合&#xff0c;大的汇总维度&#xff0c;小的明细维度&#xff0c;需要精细化的下钻。 grouping sets&#xff1a; 多维度组合&#xff0c;组合维度自定义&#xff1b;with cube&#xff1a; 多维度组合&#xff0c;程序自由组合&#xff0c;组合为…

学习react-Provider解决props需要层层传递问题

1.组件数据传递问题 数据传递&#xff1a;A(顶级组件&#xff09;-》B组件&#xff08;子组件&#xff09;、C组件&#xff08;孙子组件&#xff09;…很多组件 这样得通过props层层传递到下面的组件 还有另一种解决方法&#xff0c;即通过全局对象来解决&#xff0c;使用Prov…

Android 10.0 framework默认沉浸式状态栏功能实现

1. 前言 在10.0的系统rom定制化开发中,在实现状态栏的某些定制化开发中,在某些产品需要实现沉浸式状态栏,就是需要app 能全屏显示同样也能显示状态栏,接下来就来分析下相关的功能实现 如图: 2.framework默认沉浸式状态栏功能实现的核心类 frameworks\base\core\java\andro…

SpringCloud+FastAPI 打造AI微服务

Nacos注册微服务 注册接口服务&#xff08;java&#xff09;和图像ocr服务(python) springcloud业务层 fastapi推理层 postman调用接口层&#xff0c;接口层再通过openfegin,调用注册在nacos上推理层的微服务 参考文章SpringCloudPython 混合微服务&#xff0c;如何打造AI分布式…

Python数值计算(13)

1. 数学知识 虽然在给定了N个点以后&#xff0c;通过这个点的最小幂多项式是确定的&#xff0c;但是表达方式可不止一种&#xff0c;例如前面提到的系数方式&#xff0c;根方式&#xff0c;还有插值的Lagrange形式等。这里介绍另外一种表达方式&#xff1a; 显然这个式子最高次…

p28 vs环境-C语言实用调试技巧

int main() { int i0; for(i0;i<100;i) { printf("%d",i); } } 1.Debug 和Release的介绍 Debug通常称为调试版本&#xff0c;它包含调试信息&#xff0c;并且不做任何优化&#xff0c;便于程序员调试程序。 Release称为发布版本&#x…

束搜索(与贪心、穷举对比)

一、贪心搜索 1、基于贪心搜索从Y中找到具有最高条件概率的词元&#xff0c;但贪心可能不是最优解 2、比如 &#xff08;1&#xff09;贪心&#xff1a;.5*.4*.2*.1.0024 &#xff08;2&#xff09;另外&#xff1a;.5*.3*.6*.6.0054 二、穷举搜索 &#xff08;1&#xff0…

网络协议二 : 使用Cisco Packet Traceer工具模拟网络环境

1. 安装 Cisco Packet Tracer 2. 两个pc直连 2.1 打开 packet tracer 软件&#xff0c;弄两个pc上去&#xff0c; 2.2 然后使用 线 将 两台PC链接起来&#xff0c;链接的时候&#xff0c;会使用线&#xff0c;如果你不知道用什么线&#xff0c;可以使用自动连接线 2.3 配置IP …

UDP程序设计

UDP协议概述 UDP&#xff0c;User Datagram Protocol&#xff0c;用户数据报协议&#xff0c;是一个简单的面向数据报(package-oriented)的传输层协议&#xff0c;规范为&#xff1a;RFC 768。 UDP提供数据的不可靠传递&#xff0c;它一旦把应用程序发给网络层的数据发送出去…

NumpyPandas:Pandas库(50%-100%)

目录 前言 一、排序 1.使用索引排序 2.使用变量值排序 二、计算新变量 1.新变量为常量 2.根据原变量新增列 3.基于一个原变量做函数运算 4.在指定位置插入新列 三、修改替换变量值 1.对应数值替换 2.指定范围替换 四、虚拟变量变换 五、数值变量分组 六、数据分组…

Anaconda目录

安装目录 Anaconda 在默认情况下会安装到 C:\ProgramData\Anaconda3&#xff0c;而 conda 环境和包会安装在 C:\Users\username\.conda\ 目录下。 备注&#xff1a;我是在windows下安装 的Anaconda。我的安装目录是C:\Program Files\Anaconda3 pkgs目录 在以上两个目录下都有…

QQ微信头像制图工具箱小程序纯前端源码

微信小程序源码&#xff0c;经测试QQ小程序也可以完美运行&#xff0c;所以给大家分享一下这个QQ微信头像制图工具箱小程序纯前端源码。 主要功能有文字九格、头像挂件生成、爆趣九宫格、形状九宫格、创意长图、情侣头像、猫狗交流器。 这个QQ微信小程序源码是纯前端的&#x…

隧道可视化:实时监控保障行车安全

通过图扑可视化实现隧道的实时监控、数据分析及智能报警系统&#xff0c;提供全面的隧道管理和决策支持&#xff0c;提升行车安全&#xff0c;优化维护策略&#xff0c;确保交通顺畅。

notepad++如何跨文件搜索(比如搜索某个目录里的文件)

notepad如何跨文件搜索&#xff08;比如搜索某个目录里的文件&#xff09; notepad的搜索结果一直是比较迷&#xff0c;搜出一堆乱七八糟的东西&#xff0c;明显是缓存了&#xff0c;文件已经改名了都还不被notepad意识到

文案创作用这四款AI写作神器,告别熬夜赶稿!

都说懒人有懒福&#xff0c;现在的工具也越来越便捷于我们的日常和办公等等各种场景当中&#xff0c;其中文案的撰写和创作上也是令人脑瓜子疼的事情&#xff0c;所以锁着人工智能的兴起&#xff0c;ai智能写作工具助力我们快速地写作适合的文章&#xff0c;一起来看看下面这四…