「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};
如果初始化时提供的元素少于数组的大小,则未明确初始化的元素将被自动初始化为零(对于内置类型如 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++系列」数字/随机数
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。