函数指针与指针函数的区别
1. 函数指针
首先,它是一个指针,这个指针指向一个函数,或者说这个指针存放着函数的地址
#include <iostream>
// 声明函数
int add(int x, int y);
// 定义函数
int add(int x, int y)
{
return x + y;
}
int main()
{
// 将函数指针ptr指向函数add,或者说将函数add的地址赋给函数指针ptr,此时称:指针指向一个函数
int (*ptr)(int, int) = &add;
// 通过指针ptr,来调用函数,相当于int result = add(7, 8);
// 通过函数指针ptr来使用函数,函数的返回值与直接调用add函数相同,所以返回值可直接赋值给result
int result = ptr(7, 8);
// 输出result的值
std::cout << "result: " << result << std::endl;
return 0;
}
函数指针的语法:int (*ptr)(int, int)
*ptr必须被括号括起来,否则不是函数指针
2. 指针函数
首先,它是一个函数,这个函数的返回值是一个指针,即return时,是return一个地址到函数的调用处
#include <iostream>
// 声明指针函数
int *add(int x, int y);
// 定义指针函数
int *add(int x, int y)
{
/**
* 单独出现的int(x + y)会执行强制类型转换比如int a = int(x + y)
* 但在new int(x + y)中,它是初始化语法,两者语义不同
*/
// 在堆上分配内存
int *sum = new int(x + y);
// 返回堆内存地址
return sum;
}
int main()
{
// 将调用add指针函数返回的地址赋给指针变量result
int *result = add(7, 8);
// 解引用result指针变量,得到值进行输出
std::cout << "result: " << *result << std::endl;
// 必须手动释放内存
delete result;
return 0;
}
C语言实现:
#include <stdio.h>
#include <stdlib.h>
// 声明指针函数
int *add(int x, int y);
// 定义指针函数
int *add(int x, int y)
{
// 使用malloc在堆上分配内存
int *sum = (int*)malloc(sizeof(int));
/**
* stdout(对应printf)通常是行缓冲的
* 意味着当遇到换行符\n或缓冲区满时才会输出内容,如果程序崩溃,未刷新的缓冲区内容可能丢失
*
* stderr(对应fprintf)默认无缓冲
* 错误信息会立即输出,即使程序中途崩溃,也能确保错误信息被及时显示,调试时很有用
*/
// 检查内存分配是否成功
if (sum == NULL) {
// 使用fprintf将信息输出到标准错误流stderr,而不是printf的标准输出流stdout
fprintf(stderr, "Memory allocation failed\n");
exit(EXIT_FAILURE);
}
// 将计算结果存入分配的内存中
*sum = x + y;
return sum;
}
int main()
{
// 调用函数获取堆内存地址
int *result = add(7, 8);
// 输出结果
printf("result: %d\n", *result);
// 释放堆内存
free(result);
return 0;
}
典型的错误使用方式:
#include <iostream>
// 声明指针函数
int *add(int x, int y);
// 定义指针函数
int *add(int x, int y)
{
// sum是局部变量,存储在栈上
int sum = x + y;
// 将指针ptr指向变量sum,或者说将变量sum的地址赋给ptr
int *ptr = ∑
/**
* 函数返回后, sum的内存会被回收,ptr成为悬垂指针
* 悬垂指针:一个指向了无效的内存地址的指针
* 由于add函数结束后,sum变量所在的内存空间已经被释放
* 释放了内存之后,指针还指向原来的地址,这时候那个地址已经被系统回收了
* 被回收的地址所指向的变量以及变量的值也已经失效了
* 如果进行访问,就会出现问题
*/
return ptr;
}
int main()
{
/**
* 当add()函数执行完毕时,栈帧被销毁,sum的内存被回收
* 此时result指针指向的是已被释放的内存,
* 访问*result会导致未定义行为,可能输出错误的值,程序崩溃或输出看似正常但存在隐患
*/
// 调用add指针函数,会返回一个地址,赋给指针变量result
int *result = add(7, 8);
// 解引用result,结果理论上输出15,但实际可能存在错误隐患
std::cout << "result: " << *result << std::endl;
return 0;
}
浙公网安备 33010602011771号