详解C++中的指针、数组指针与函数指针
C++ 通过指针实现了高效的内存操作,但也伴随着潜在风险。本文深入解析 C++ 中变量指针、数组指针和函数指针的定义方式与核心用途,结合完整的代码实例展示从地址获取到函数调用的全过程,并系统梳理了数组指针与指针数组、引用传递与指针传递等关键概念的区别,旨在帮助读者建立清晰且安全的 C++ 内存管理认知。
理解指针与基础类型
在 C++ 程序中,所有的变量、常量以及函数都存储在特定的内存地址中。指针(Pointer)是一种特殊的变量,专门用于存储另一个变量的内存地址。它不仅能读取地址,还能间接操作该地址指向的内存数据。
除了 void* 这种通用空类型指针外,普通指针的数据类型必须与其所指向变量的数据类型保持一致。例如,int* 只能指向整型变量的地址。正确使用指针能让程序运行更高效,但使用不当(如解引用未初始化或越界的指针)会导致严重的运行时错误或安全漏洞。
三类指针的定义与方法
C++ 中最常见的指针分为三种:变量指针、数组指针和函数指针。下面分别说明其定义方式:
第1步:定义并使用变量指针
目的:获取单个变量的内存地址并进行读写访问。
核心操作:
- 声明:
int* p;声明一个指向整型的指针变量。 - 初始化(可选):
p = 0;将指针初始化为空地址(NULL),防止悬垂指针。 - 获取地址:使用取地址符
&,如p = &a;,让指针指向变量a。 - 访问内容:使用解引用符
*,如*p,读取或修改a的值。
第2步:定义并初始化数组指针
目的:使指针指向数组的首地址,从而遍历或访问数组元素。
核心操作:
- 定义数组:
int a[] = {0, 1, 2};。 - 指向首地址:
int* p = a;。注意,数组名a在表达式中退化为首元素的地址,即等价于&a[0]。
第3步:定义并调用函数指针
目的:通过指针对函数进行间接调用,常用于回调函数或动态分发机制。
核心操作:
- 定义函数原型:
int f();。 - 定义函数指针:
int (*pf)();。这里括号至关重要,确保pf先与*结合成为指针,再返回int类型。 - 赋值函数地址:
pf = f;。直接将函数名赋给指针。 - 调用函数:
(*pf)();。通过解引用函数指针来执行函数体。
以下代码完整演示了上述三种指针的使用场景及输出结果:
#include<iostream>
using namespace std;
// 定义被调用的函数
int f()
{
cout<<"测试函数指针的使用"<<endl<<endl;
return 0;
}
void main()
{
// ========== 变量指针的使用 ==========
cout<<"==========变量指针的使用=========="<<endl;
int a = 5;
int* p = 0; // 初始化指针为0
int* q; // 仅声明指针
q = &a; // 赋值指针,q现在指向a
cout<<"a = "<<a<<endl; // 直接输出变量值:5
cout<<"a = "<<*q<<endl; // 通过指针访问值:5
cout<<"p = "<<p<<endl; // 指针的地址值为0
cout<<"&a = "<<&a<<endl; // 直接获取a的物理地址
cout<<"&a = "<<q<<endl; // 通过指针获取a的物理地址(应与上一行一致)
// ========== 数组指针的使用 ==========
cout<<"==========数组指针的使用=========="<<endl;
int b[] = {0,1,2,3,4,5,6,7,8,9};
int* pb = b; // 数组指针指向b的首地址
cout<<pb<<endl // 第1个元素的地址
<<b<<endl // 数组名即首地址
<<*pb<<endl // 第1个元素的值(0)
<<(*pb+2)<<endl; // 第1个元素值加2(结果为2)
// ========== 函数指针的使用 ==========
cout<<"==========函数指针的使用=========="<<endl;
int (*pf)(); // 定义函数指针
pf = f; // 将函数f的地址赋值给pf
(*pf)(); // 通过指针调用函数
}
执行上述代码后,控制台将首先打印出各变量及其地址信息,随后执行函数指针调用的输出语句,结果如下所示:
数组指针 vs 指针数组
这是初学者容易混淆的两个概念,本质区别在于“谁是指针”:
- 数组指针(Array Pointer):本质是一个指针。它只占一个指针的空间(通常是 4 字节或 8 字节),用来指向整个数组的起始地址。定义为
int (*p)[N];。 - 指针数组(Pointer Array):本质是一个数组。它是一组存放指针的容器,数组内的每一个元素都是指向某个对象的指针。定义为
int* p[N];。
函数指针 vs 指针函数
区分的关键在于优先级与词意:
- 函数指针(Function Pointer):本质是指针。指向一段函数代码的入口地址。常用于实现策略模式或异步回调。
- 指针函数(Pointer Function):本质是函数。其返回值是一个指针。例如
int* get_pointer();。
参数传递:值、引用与指针
C++ 中函数参数的传递机制直接影响数据的可见性与修改范围:
1. 值传递(Value Pass)
形参是实参的一份完整拷贝。对形参的任何修改都不会影响实参。这种方式安全性最高,但在传递大型对象时会有性能开销。
2. 指针传递(Pointer Pass)
传递的是实参的地址(指针)。函数内部可以通过解引用操作直接修改外部实参的内容。由于只传递了地址(固定大小),适合处理大数据结构。
3. 引用传递(Reference Pass)
形参是实参的一个别名(Alias)。在语法上看起来像直接操作局部变量,但实际上底层是通过访问实参的内存地址实现的。对形参的操作等同于直接操作实参。引用必须在定义时初始化,且一旦绑定不可更改。
总结指针与引用的核心差异:
- 实体性质:指针是一个独立变量(保存地址),引用是已存在变量的别名。
- 可变性:指针可以随时改变指向(见异思迁),引用一经定义便不能改变目标(从一而终)。
- 空状态:指针可以为 NULL,引用必须指向有效对象。
- sizeof 行为:
sizeof(指针)得到的是指针本身的大小;sizeof(引用)得到的是其所指变量的大小。 - 自增运算:指针自增指向下一个内存单元;引用自增意味着所指对象值的增加。
- 安全性:引用是类型安全的,编译器会进行更多检查;指针灵活性高但容易出错。
以上就是C++中指针、数组指针与函数指针的详细解析与对比,更多关于C++基础知识点的应用技巧请持续关注本站!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













