文章目录
- 一、数组
- 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};
如果初始化时提供的元素少于数组的大小,则未明确初始化的元素将被自动初始化为零(对于内置类型如 int
、float
等)。
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::array
或 std::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++系列」数字/随机数