C++中的数组与指针
在大多数C++书籍或教程中,数组和指针的知识总是放在一起让大家学习,这是为什么,它们之间有什么联系呢?
在C++中,数组与指针有着紧密的联系,主要体现在下面几个方面:
1、数组名即指针:
本质联系:在大多数情况下,数组名会被隐式转换为指向数组第一个元素的指针。
例如,对于一个数组 int arr[5];,表达式 arr 的值是数组第一个元素的地址(等价于 &arr[0]),其类型是指向 int 类型的指针 (int*)。
这意味着可以像使用指针一样来使用数组名进行地址运算。
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // 这里将数组名arr赋值给指针ptr,ptr指向arr[0]
for (int i = 0; i < 5; i++) {
std::cout << *(ptr + i) << " "; // 通过指针ptr访问数组元素,等价于arr[i]
}
2、通过指针访问数组元素:
相似的访问方式:通过指针的算术运算,可以像访问数组元素一样访问内存中的数据。
对指针进行加法运算(如 ptr + n),会根据指针指向的数据类型,移动相应字节数。
这与通过数组下标访问数组元素(如 arr[n])在原理上是相似的。
实际上,arr[n] 这种形式在编译器内部就是按照 *(arr + n) 来处理的。
指针运算原理
在 C++ 中,当对指针进行算术运算时,编译器会根据指针所指向的数据类型自动调整偏移量。
例如,对于int*类型的指针,ptr + 1实际上是将指针ptr的地址增加了sizeof(int)个字节。
在C++代码中,ptr是int*类型,当我们写ptr + 2时,它已经自动按照int类型的大小进行了偏移。
int类型在我们的计算机环境中是 4 字节,所以ptr + 2实际上是将ptr的地址增加了2 * sizeof(int)(即 8 字节)
例如,*(arr + i) 等价于 arr[i],表示数组中第 i 个元素。
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
// 以下两种方式访问数组元素效果相同
std::cout << arr[2] << " ";
std::cout << *(ptr + 2) << " ";
3、动态数组与指针:
动态内存分配:在 C++ 中,使用 new 运算符动态分配数组内存时,会返回一个指向分配内存首地址的指针。
例如,int *dynArr = new int[10]; 分配了一个包含 10 个 int 类型元素的动态数组,dynArr 就是一个指向该数组首元素的指针。
动态数组的释放也依赖于指针,使用 delete[] dynArr; 来释放通过 new[] 分配的内存。
int *dynArr = new int[10];
for (int i = 0; i < 10; i++) {
dynArr[i] = i; // 像访问普通数组一样访问动态数组
}
// 使用完后释放动态数组
delete[] dynArr;
4、函数参数传递:
数组参数的退化:当数组作为函数参数传递时,数组会退化为指针。
例如,函数声明 void func(int arr[10]) 和 void func(int *arr) 是等价的,编译器都将其视为 void func(int *arr)。这意味着在函数内部,无法直接获取数组的长度,需要额外传递数组长度信息。
void printArray(int *arr, int size) {
for (int i = 0; i < size; i++) {
std::cout << arr[i] << " ";
}
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
printArray(arr, 5);
return 0;
}
5、内存布局:
数组在内存中是连续存储的,而指针可以用来遍历这些连续的内存块。
理解这一点有助于编写高效的代码,尤其是在处理大量数据时。
6、指针数组与数组指针
指针数组:是一个数组,数组中的每个元素都是指针。例如,int ptrArr[5]; 定义了一个指针数组,数组中有 5 个 int 类型的指针。常用于管理多个动态分配的数组或对象。
数组指针:是一个指针,它指向一个数组。例如,int (*arrPtr)[5]; 定义了一个指向包含 5 个 int 元素数组的指针。在处理二维数组时,数组指针会很有用,因为二维数组本质上是数组的数组。
// 指针数组
int *ptrArr[5];
for (int i = 0; i < 5; i++) {
ptrArr[i] = new int(i);
}
// 数组指针
int arr[5] = {1, 2, 3, 4, 5};
int (*arrPtr)[5] = &arr;
为什么一起学习?
概念一致性:数组和指针的概念密切相关,一起学习可以帮助理解它们之间的内在联系,避免混淆。
实际应用:很多实际编程场景中,数组和指针常常结合使用,如字符串处理、动态内存管理等。
提高效率:理解数组和指针的关系有助于编写更高效、更灵活的代码,特别是在底层编程或性能关键的应用中。
通过同时学习数组和指针,可以更好地掌握C++的内存管理和数据操作机制,为更复杂的编程任务打下坚实的基础。