C++ 数组指针
数组和指针是C++中两个基础但又容易混淆的概念。当这两个概念结合时,常常会给初学者带来困惑。本文将全面介绍C++中的数组指针,帮助你理解它们之间的关系和正确使用方法。
数组与指针的基础关系
在C++中,数组名在大多数情况下会自动转换为指向数组第一个元素的指针。这是理解数组指针的关键基础。
int numbers[5] = {10, 20, 30, 40, 50};
int* ptr = numbers; // ptr指向数组的第一个元素
// 以下两种表达式等价
std::cout << numbers[0] << std::endl; // 输出: 10
std::cout << *ptr << std::endl; // 输出: 10
输出结果:
10
10
备注
虽然数组名常常会转换为指针,但数组名本身并不是指针变量。它是一个固定地址的常量,不能被赋予新值。
数组指针的语法
在C++中,有几种与数组相关的指针类型:
- 指向数组元素的指针(最常见)
- 指向整个数组的指针(数组指针)
指向数组元素的指针
int numbers[5] = {10, 20, 30, 40, 50};
int* ptr = numbers; // 指向int的指针,指向数组第 一个元素
// 通过指针访问数组元素
for (int i = 0; i < 5; i++) {
std::cout << *(ptr + i) << " "; // 指针算术运算
}
输出结果:
10 20 30 40 50
指向整个数组的指针(真正的数组指针)
int numbers[5] = {10, 20, 30, 40, 50};
int (*arrayPtr)[5] = &numbers; // arrayPtr是指向包含5个int元素的数组的指针
// 访问数组元素
std::cout << (*arrayPtr)[0] << std::endl; // 输出: 10
std::cout << (*arrayPtr)[2] << std::endl; // 输出: 30
输出结果:
10
30
警告
int* ptr[5]
和int (*ptr)[5]
是不同的!前者是一个包含5个int指针的数组,后者是指向包含5个int元素的数组的指针。括号很重要!
指针算术与数组索引
指针和数组紧密相关,以至于可以使用相似的语法来访问元素:
int numbers[5] = {10, 20, 30, 40, 50};
int* ptr = numbers;
// 以下表达式都等价于numbers[2]
std::cout << numbers[2] << std::endl; // 使用数组索引
std::cout << *(numbers + 2) << std::endl; // 数组名作为指针
std::cout << *(ptr + 2) << std::endl; // 指针算术
std::cout << ptr[2] << std::endl; // 指针索引
输出结果:
30
30
30
30
这展示了指针索引和数组索引的等价性:ptr[i]
等价于 *(ptr + i)
。
数组指针的内存模型
为了更好地理解数组指针,让我们看看它们在内存中的表示:
多维数组与指针
多维数组与指针的关系更为复杂,但遵循相同的原则:
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 指向矩阵第一行的指针
int* rowPtr = matrix[0];
std::cout << rowPtr[2] << std::endl; // 输出: 3
// 指向整个二维数组的指针
int (*matrixPtr)[3][4] = &matrix;
std::cout << (*matrixPtr)[1][2] << std::endl; // 输出: 7
// matrix实际上是一个数组指针类型:int (*)[4]
int (*rowsPtr)[4] = matrix;
std::cout << rowsPtr[1][2] << std::endl; // 输出: 7
输出结果:
3
7
7