C++:指针(Pointers)
目录
什么是指针?
为什么需要指针?
1. 访问堆(Access Heap)
2. 资源管理(Resource Management)
3. 参数传递(Parameter Passing)
如何声明和使用指针?
如何利用指针访问堆内存?
1. 使用 malloc 访问堆内存
2. 使用 new 访问堆内存
什么是指针?
指针是一个地址变量,用于存储数据的地址,而不是数据本身。
普通变量是数据变量,但指针是地址变量,用于间接访问数据。
所以,我们提出问题:为什么我们需要间接访问数据?
为什么需要指针?
1. 访问堆(Access Heap)
程序运行时,RAM(随机存取存储器,Random Access Memory)分为三部分:
-
代码部分(Code Section):存储程序的机器码(Machine Code),即编译后的指令。
-
栈(Stack):存储局部变量(Local Variables,如函数内的int、char),由系统自动分配和释放。栈大小有限,变量生命周期随函数作用域结束。
-
堆(Heap):更大的内存区域,程序员通过动态分配(Dynamic Allocation)使用,生命周期由程序员控制。
程序可以直接访问的部分是代码部分和栈内存,无法直接使用堆内存。所以说,堆内存在程序之外,那么该如何访问堆内存呢?这时就需要用到了指针。
堆内存的分配需要通过new操作符,分配后返回内存地址,存储在指针中。例如:
int* ptr = new int; // 在堆上分配一个整数,ptr存储其地址
*ptr = 10; // 通过指针访问堆内存,存储值10
没有指针,程序无法操作堆内存,也就无法实现动态数据结构或存储大块数据。
2. 资源管理(Resource Management)
程序运行在内存中,但需要访问外部资源,如文件(Files)、硬盘(Hard Disk)、互联网(Internet)(如网络套接字Socket)。这些资源位于程序外部,操作系统(Operating System)管理它们,程序无法直接访问其内容。
外部资源(如文件、硬盘、互联网连接)由操作系统分配句柄或内存地址,程序通过指针访问这些句柄。例如:
FILE* fp = fopen("data.txt", "r"); // 打开文件,fp指向文件句柄
if (fp != nullptr) {// 通过fp操作文件fclose(fp); // 关闭文件,释放资源
}
这里,fp是一个指针,指向操作系统分配的文件句柄(File Handle),程序通过它读写文件。
外部资源(如文件、硬盘、互联网)在程序外部,操作系统通过句柄或地址管理,指针是程序访问这些资源的唯一途径。指针通过地址共享资源,提高效率。
3. 参数传递(Parameter Passing)
-
C++默认使用值传递(Pass by Value),传递数据副本,函数内修改不影响原数据。复制大对象(如数组、结构体)效率低,且无法修改调用者的变量。
-
函数需要高效传递数据,有时需要修改原数据,或表示“无数据”状态。
指针支持按地址传递(Pass by Pointer),让函数直接操作调用者的内存。例如:
void swap(int* a, int* b) {int temp = *a; // 访问a的内存*a = *b; // 修改a的内存*b = temp; // 修改b的内存
}
int main() {int x = 10, y = 20;swap(&x, &y); // 传递x和y的地址// x现在是20,y是10
}
如何声明和使用指针?
这部分不再赘述,详细教程可以参考下面的学习网站:
C++ 指针 | 菜鸟教程
如何利用指针访问堆内存?
1. 使用 malloc 访问堆内存
malloc(Memory Allocation)是C语言的动态内存分配函数,C++中仍然可用,位于<cstdlib>头文件中。它分配原始内存,不初始化,适合C风格编程。
首先声明一个指针,指定指向的数据类型。
分配堆内存:
ptr = (int*)malloc(sizeof(int)); // 分配一个整数大小的内存
-
使用malloc分配指定大小的内存,返回void*类型地址,需强制转换为目标类型。
-
语法:ptr = (type*)malloc(size);
-
sizeof(int):计算整数类型的大小
-
(int*):将void*转换为int*。
访问内存(解引用,Dereference):
-
通过*操作符访问或修改指针指向的内存。
if (ptr != nullptr) {*ptr = 42; // 存储值42std::cout << *ptr; // 输出:42
}
释放内存:
-
使用free释放堆内存,防止内存泄漏(Memory Leak)。
free(ptr); // 释放内存
ptr = nullptr; // 避免悬空指针(Dangling Pointer)
2. 使用 new 访问堆内存
new是C++的动态内存分配操作符,位于<new>头文件中(通常无需显式包含)。它分配内存并初始化(对于类会调用构造函数),是C++的首选方式。
首先声明一个指针,指定指向的数据类型。
分配堆内存:
-
使用new分配内存,返回目标类型的指针,无需强制转换。
ptr = new int; // 分配一个整数的内存
访问内存:
-
通过*操作符访问或修改内存。
*ptr = 100; // 存储值100
std::cout << *ptr; // 输出:100
释放内存:
-
使用delete释放内存,防止内存泄漏。
delete ptr; // 释放内存
ptr = nullptr; // 避免悬空指针
分配动态数组:
-
使用new[]分配连续内存,适合动态数组。
int* arr = new int[5]; // 分配5个整数的数组
for (int i = 0; i < 5; i++) {arr[i] = i + 1; // 填充数组:1, 2, 3, 4, 5
}
delete[] arr; // 释放数组内存
arr = nullptr;
关键点
-
new自动匹配指针类型,无需强制转换,比malloc更安全。
-
对于类,new会调用构造函数,delete调用析构函数,适合面向对象编程。
-
数组用new[]分配,delete[]释放,匹配使用以避免未定义行为。