一、指针的本质与内存模型
指针是C/C++的核心特性,本质是内存地址的变量化表示。每个变量在内存中占据连续的字节空间,地址是内存单元的唯一编号(如0x0028FF40
)。指针变量存储的是目标数据的首地址,通过地址间接操作数据。
内存模型示例:
int num = 97; // 假设分配在地址0x0028FF40
int* p = # // p存储0x0028FF40,*p解引用得到97
- 步长:指针类型决定地址增减的步长(如
int*
步长为4字节,char*
为1字节)。
二、指针的声明与操作
-
声明与初始化
int* p; // 声明int型指针 int a = 10; p = &a; // p指向a的地址 int* q = NULL; // 空指针,避免野指针问题
-
核心操作符
&
:取地址符,获取变量内存地址(如&a
)。*
:解引用符,访问指针指向的值(如*p = 20
修改a的值)。
-
指针运算
三、多级指针与复杂类型
-
int pp = &p; // pp存储p的地址 pp = 30; // 修改a的值为30
-
指针与数组
-
void (*funcPtr)(int) = &myFunction; // 声明并赋值 funcPtr(10); // 调用函数
-
函数指针
//三种写法都可以
int *fun(int x,int y);
int * fun(int x,int y);
int* fun(int x,int y);
四、指针与动态内存管理
-
动态分配
- C:
malloc/calloc
分配堆内存,需手动释放(free
)。 - C++:
new/delete
支持类型安全:int* arr = new int; // 动态数组 delete[] arr; // 释放内存
- C:
-
智能指针(C++)
unique_ptr
:独占所有权,禁止拷贝。shared_ptr
:引用计数,自动释放内存。
五、高级应用与注意事项
-
const int* p1; // 指向常量的指针(值不可改) int* const p2; // 指针常量(地址不可改)
-
内存安全
-
与引用的区别
引用是别名(编译期优化),指针是实体变量,支持运算和多级间接访问。
六、典型应用场景
- 数据结构:链表、树的节点链接。
- 函数参数:传递大型结构体避免拷贝。
- 系统编程:直接操作硬件寄存器或内存映射。
总结
指针是C/C++高效性和灵活性的核心,但也带来内存管理的复杂性。理解其底层机制(地址、步长、类型)和现代实践(智能指针、RAII)是掌握关键。建议结合调试工具(如Valgrind)验证内存操作安全性。
demo
#include <iostream>
using namespace std;// 定义结构体用于示例
struct Student {int age;string name;
};int main() {// 1. 基础变量指针 int a = 10;int* p1 = &a;*p1 = 20;cout << "基础指针: " << a << endl; // 输出 20 [7]()// 2. 空指针与野指针 int* p2 = nullptr; // 安全空指针 // int* p3; // 未初始化野指针(注释避免运行时崩溃)// 3. 数组指针操作 int arr[] = {1,2,3,4,5};int* p4 = arr;cout << "数组指针: " << *(p4 + 2) << endl; // 输出 3 [3]()// 4. 字符串指针 const char* str = "Hello";cout << "字符串指针: " << str[1] << endl; // 输出 'e' [6]()// 5. 结构体指针 Student s = {20, "Tom"};Student* p5 = &s;cout << "结构体指针: " << p5->name << endl; // 输出 Tom [5]()// 6. 动态内存分配 int* p6 = new int(100);cout << "动态内存: " << *p6 << endl;delete p6; // 必须释放 [7]()// 7. 多维数组指针 int matrix[2][3] = {{1,2,3}, {4,5,6}};int (*p7)[3] = matrix;cout << "多维数组: " << p7[1][2] << endl; // 输出 6 [3]()// 8. 函数指针 int (*funcPtr)(int, int) = [](int x, int y) { return x + y; };cout << "函数指针: " << funcPtr(3,5) << endl; // 输出 8 [6]()return 0;
}