指针专栏2 --- 区分:指针函数 & 函数指针

  • 指针函数:本质是函数,返回值为指针
  • 函数指针:本质是指针,存放函数入口地址

(一)指针函数

1.基础定义

带有指针类型返回值的普通函数,就叫指针函数。

本质 = 函数,只是它 return 返回一个内存地址(指针)

(1)通用语法

返回值类型* 函数名(形参列表);

(2)示例

char* test(int a);

解析:

char*:函数返回 char‑类型指针

test:函数名字

(int a):函数接收一个 int 参数

int* add(int x,int y);

//返回int类型指针

2.核心规则:什么地址可以 return、什么绝对不能返回

(1)禁止返回:栈区临时地址

函数内部普通局部变量、局部数组存放在栈区; 函数运行结束之后栈空间自动释放销毁,返回该地址会造成野指针、程序崩溃。

char *bad(void)
{
    char buf[32] = "hello world";
    return buf; 
    //错误!buf是栈上局部数组,函数结束内存回收
}
(2)允许返回的 5 类地址

1)static 静态变量地址

static 变量存放于静态存储区,函数结束内存不会销毁

char *fun1(void)

{

        static char str[] = "hello";

        return str;

}

2)全局变量的地址

全局变量生命周期等于整个程序运行周期

3)字符串常量区地址

char *fun2(void)

{

        return "hello world";

        //字符串常量存放在只读常量区,生命周期常驻

}

4)函数形参传进来的地址

地址来自函数外部,不归本函数栈管理,例如 strcpy 返回 dest 指针

char *strcpy(char *dest, const char *src);

5)malloc 堆区申请的内存地址

堆内存不会随函数结束自动释放,需要手动 free 回收

#include <stdlib.h>
char *fun3(void)
{
    char *p = (char*)malloc(32);
    return p;
}

3. 指针函数简单实操示例

#include <stdio.h>

char* get_str(int num)
{
    static char arr[][10] = {"星期一","星期二","星期三"};
    return arr[num];
}

int main(void)
{
    printf("%s",get_str(1));
    return 0;
}

4. 易错补充

  • 不要混淆 char *p()(指针函数) 和 char (*p)()(函数指针) 括号优先级决定类型;
  • 返回字符串常量指针之后,不能修改常量区字符,只读;
  • 返回堆地址记得后续 free,避免内存泄漏。

(二)函数指针

1. 基础定义

本质是指针变量,专门存放函数的入口地址; C 语言当中,单独书写的函数名本身就是函数入口地址。

2. 语法详解

通用格式:

返回值类型 (*指针名)(形参列表);

  • 括号必不可少,(*指针名)强制先识别它是指针;
  • 如果写成 *指针名() 编译器会识别成指针函数。

示例

(1)int (*pfun)(int,int);

解析:

(1)pfun 是指针变量,64 位环境占 8 字节

(2)它只能指向:返回 int、拥有两个 int 形参的函数

(2)char *(*p)(char *);

指向:返回 char*、参数为 char* 的函数

3. 函数指针完整使用流程

① 初始化为空指针

int (*pfun)(int,int) = NULL;

② 定义普通函数

int add(int a,int b)
{
    return a + b;
}

③ 给函数指针赋值

函数名就是入口地址,直接赋值即可

pfun = add;

④ 通过函数指针调用目标函数

两种写法等价

int res1 = add(3,5);
int res2 = pfun(3,5);

4. 函数指针核心用途 —— 回调函数

将函数指针当作参数传递给另一个函数,被传入的函数就叫做回调函数。

作用:

1)降低代码耦合度

2)一套代码可以动态切换不同功能函数,减少重复代码

回调简单示例:

#include <stdio.h>

int add(int a,int b)
{
    return a+b;
}
int sub(int a,int b)
{
    return a-b;
}
//接收函数指针作为形参
void calc(int (*func)(int,int),int x,int y)
{
    printf("%d\n",func(x,y));
}

int main(void)
{
    calc(add,10,3);
    calc(sub,10,3);
    return 0;
}

(三)整理总结

1.对比

对比项目指针函数函数指针
本质是函数是指针变量
优先级解析char *fun(),先看 fun () 是函数,返回 char*char (*p)(),*p 先执行,p 为指针
内存占用函数没有单独占用变量空间指针变量,64 位占 8 字节
作用返回一块内存地址保存函数入口、实现回调

2.易混点

(1)char *p[5]指针数组:数组,存放 char * 指针

(2)char (*p)[5]数组指针:指针,指向 char [5] 数组

(3)char *p()指针函数:函数,返回 char*

(4)char (*p)()函数指针:指针,指向无参 char 返回值函数

分辨口诀:先看括号

  • ()包住 * 变量名 → 指针
  • 不带括号、先碰到 [] → 数组
  • 不带括号、先碰到 () → 函数

3.补充

(1)函数指针类型必须和指向的函数 返回值、参数个数、参数类型完全一致,否则报错;

(2)函数名、& 函数名都是入口地址,pfun=addpfun=&add 在 C 语言里面等价;

(3)数组指针、函数指针一定要加括号改变运算符优先级;

(4)指针函数千万不要返回局部栈变量地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值