「C++系列」数组

·零落· 2024-08-16 10:35:02 阅读 71

文章目录

一、数组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. 声明数组

数组的声明需要指定数组的类型和大小。例如,声明一个整型数组 <code>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++中,数组名在很多情况下会被隐式地转换为指向其第一个元素的指针。但是,有几个重要的区别:

大小信息丢失:当数组名被用作指针时,它不再携带关于数组大小的信息。因此,通过指针遍历数组时,我们需要知道数组的大小。类型不同:尽管在大多数上下文中数组名可以像指针一样使用,但它们的类型是不同的。数组名是一个常量指针,指向数组的第一个元素,并且它的类型是“N个T类型的数组”,其中N是数组的大小,T是元素的类型。而指针是一个指向T类型对象的变量。使用 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;

}

在这里插入图片描述

六、相关链接

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



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。