写在前面
对于指针, 我们一般关注的有以下两点: (1)解指针类型; (2)地址。
1. 多级指针
直观来看,多级指针就是一个“解指针的结果仍然为指针”的一种指针. 下面通过代码示例来具体看下:
#include <iostream>
int main() {
int value = 42;
int* ptr = &value; // 单级指针,指向变量 value
int** ptr2 = &ptr; // 二级指针,指向指针 ptr
int*** ptr3 = &ptr2; // 三级指针,指向指针 ptr2
std::cout << "Value: " << value << std::endl; // 输出变量值
std::cout << "Value via ptr: " << *ptr << std::endl; // 通过单级指针访问值
std::cout << "Value via ptr2: " << **ptr2 << std::endl; // 通过二级指针访问值
std::cout << "Value via ptr3: " << ***ptr3 << std::endl; // 通过三级指针访问值
return 0;
}
输出结果:
Value: 42
Value via ptr: 42
Value via ptr2: 42
Value via ptr3: 42
在这个示例中, ptr 是一个指向 value 的单级指针,ptr2 是一个指向 ptr 的二级指针,而 ptr3 是一个指向 ptr2 的三级指针。通过多级指针,我们可以间接地访问 value 的值。
2. 泛型指针
如果用同样的句式来理解泛型指针,那么它就是“一个解指针类型为空”的指针. 代码示例如下:
#include <iostream>
void printValue(void* ptr, char type) {
switch (type) {
case 'i': // int
std::cout << "Integer value: " << *static_cast<int*>(ptr) << std::endl;
break;
case 'f': // float
std::cout << "Float value: " << *static_cast<float*>(ptr) << std::endl;
break;
case 'd': // double
std::cout << "Double value: " << *static_cast<double*>(ptr) << std::endl;
break;
default:
std::cout << "Unknown type" << std::endl;
}
}
int main() {
int i = 42;
float f = 3.14f;
double d = 2.718;
void* ptr;
ptr = &i;
printValue(ptr, 'i');
ptr = &f;
printValue(ptr, 'f');
ptr = &d;
printValue(ptr, 'd');
return 0;
}
运行结果:
Integer value: 42
Float value: 3.14
Double value: 2.718
在上面的代码中,printValue 函数接收一个 void* 泛型指针和一个字符标识符 type,通过类型转换 (static_cast) 将泛型指针转换为特定类型的指针并输出对应的值。
泛型指针的使用注意
泛型指针 (void*) 则允许指针指向任何类型的数据,提供了一种通用的数据处理方式,但需要在使用时进行显式的类型转换, 例如上面的示例代码中函数printValue, 它在内部先通过static_cast类型转换函数 将泛型指针转换为特定类型的指针,再进行具体的处理。
3. 函数指针
对于函数, 比较关注的有三个要素: (1)首地址; (2)参数; (3)返回值。
有一种指针,保存的就是函数的首地址, 用来指向函数、调用函数等, 那就是函数指针。
对一个函数取地址, 其实就是取这个函数首地址的值。
函数指针的定义一般是这种格式: 返回型+函数指针名+入参类型。
return_type (*pointer_name) (parameter_types);
下面看一个具体的例子:
#include <iostream>
// 函数声明
void add(int a, int b);
void subtract(int a, int b);
int main() {
// 定义函数指针
void (*funcPtr)(int, int);
// 将函数指针指向具体的函数
funcPtr = &add;
funcPtr(5, 3); // 调用 add 函数
funcPtr = &subtract;
funcPtr(5, 3); // 调用 subtract 函数
return 0;
}
// 定义 add 函数
void add(int a, int b) {
std::cout << "Addition: " << (a + b) << std::endl;
}
// 定义 subtract 函数
void subtract(int a, int b) {
std::cout << "Subtraction: " << (a - b) << std::endl;
}
以上代码的解释:
-
定义函数指针:
在 main 函数中,我们定义了一个函数指针 funcPtr,它可以指向返回类型为 void,参数类型为 int, int 的函数。 -
将函数指针指向具体的函数:
通过将 funcPtr 分别指向 add 和 subtract 函数,我们可以使用同一个指针变量调用不同的函数。 -
通过指针调用函数:
使用函数指针调用函数的语法与直接调用函数相同。我们通过 funcPtr(5, 3) 调用了 add 和 subtract 函数。
函数指针的使用
函数指针常用于实现回调函数、事件处理器等。
它的一个常见用法是作为参数传递, 这种方式能够帮助我们实现在函数中调用其他函数。很多回调函数都是这样实现的。
#include <iostream>
// 函数声明
void add(int a, int b);
void subtract(int a, int b);
void executeOperation(void (*operation)(int, int), int x, int y);
int main() {
// 调用 executeOperation 并传递函数指针
executeOperation(&add, 5, 3);
executeOperation(&subtract, 5, 3);
return 0;
}
// 定义 add 函数
void add(int a, int b) {
std::cout << "Addition: " << (a + b) << std::endl;
}
// 定义 subtract 函数
void subtract(int a, int b) {
std::cout << "Subtraction: " << (a - b) << std::endl;
}
// 定义 executeOperation 函数
void executeOperation(void (*operation)(int, int), int x, int y) {
operation(x, y); // 通过函数指针调用函数
}
以上代码的解释:
-
定义 executeOperation 函数:
该函数接受一个函数指针 operation 和两个整数 x、y 作为参数。在函数体内,通过 operation 指针调用传递进来的函数。 -
在 main 函数中调用 executeOperation:
我们将 add 和 subtract 函数的地址作为参数传递给 executeOperation,并执行相应的操作。