指针与函数

我们一提到指针函数和函数指针的时候,就有很多人弄不懂。下面详细为大家介绍C语言中指针函数和函数指针。

指针函数

当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。

格式:

类型说明符 * 函数名(参数)  

由于返回的是一个地址,所以类型说明符一般都是int。

在c语言中,函数也是一种类型,可以定义指向函数的指针。我们知道,指针变量的内存单元存放一个地址值,而函数指针存放的就是函数的入口地址(位于.text段)。下面看一个简单的例子:

#include <stdio.h>  
   
void say_hello(const char *str)  
{
     
    printf("Hello %s\n", str);  
}  
   
int main(void)  
{
     
    void (*f)(const char *) = say_hello;  
    f("Guys");  
    return 0;  
}  

分析一下变量f的类型声明void (*f)(const char *),f首先跟*号结合在一起,因此是一个指针。(*f)外面是一个函数原型的格式,参数是const char *,返回值是void,所以f是指向这种函数的指针。而say_hello的参数是const char *,返回值是void,正好是这种函数,因此f可以指向say_hello。注意,say_hello是一种函数类型,而函数类型和数组类型类似,做右值使用时自动转换成函数指针类型,所以可以直接赋给f,当然也可以写成void (*f)(const char *) = &say_hello;,把函数say_hello先取地址再赋给f,就不需要自动类型转换了。

可以直接通过函数指针调用函数,如上面的f(“Guys”),也可以先用*f取出它所指的函数类型,再调用函数,即(*f)("Guys")。可以这么理解:函数调用运算符()要求操作数是函数指针,所以f(“Guys”)是最直接的写法,而say_hello(“Guys”)或(*f)("Guys")则是把函数类型自动转换成函数指针然后做函数调用。

函数指针

函数指针可以实现面向对象编程,可以实现软件分层设计(回调函数)。

指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:

类型说明符 (*函数名)(参数)  

其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。

指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。

例如:

void (*fptr)();  

把函数的地址赋值给函数指针,可以采用下面两种形式:

fptr=&Function;   
fptr=Function;  

取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。

可以采用如下两种方式来通过指针调用函数:

x=(*fptr)();
x=fptr();

第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。下面举一个例子:

void (*funcp)();   
void FileFunc(),EditFunc();   

int main(void)   
{
      
	funcp=FileFunc;   
	(*funcp)();   
	funcp=EditFunc;   
	(*funcp)();   
}   

void FileFunc()   
{
       
	printf("FileFunc\n");
}   

void EditFunc()   
{
      
	printf("EditFunc\n");   
}  

程序输出为:

FileFunc 
EditFunc

下面再举几个例子区分函数类型和函数指针类型。首先定义函数类型F:

typedef int F(void);  

这种类型的函数不带参数,返回值是int。那么可以这样声明f和g:

F f, g;相当于声明:

int f(void);  int g(void);  

下面这个函数声明是错误的:

F h(void);  

因为函数可以返回void类型、标量类型、结构体、联合体,但不能返回函数类型,也不能返回数组类型。而下面这个函数声明是正确的:

F *e(void);  

函数e返回一个F *类型的函数指针。如果给e多套几层括号仍然表示同样的意思:

F *((e))(void);  

但如果把*号也套在括号里就不一样了:

int (*fp)(void);  

这样声明了一个函数指针,而不是声明一个函数。fp也可以这样声明:

F *fp;  

函数指针强化

诀窍:挖取函数指针变量声明格式当中的函数变量名就是该函数指针的具体类型!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jJivTTOC-1632721608640)(images/函数指针引用.png)]

#include <stdio.h>#include <stdlib.h>
//01.在C语言当中,当形参位于函数声明位置的时候://  可以不用指明形参名称;但是函数实现的时候需要指明形参名称!
int add(int, int);int add(int a, int b){
       return a + b;}int sub(int a, int b){
       return a - b;}int mul(int a, int b){
       return a * b;}int divv(int a, int b){
       return a / b;}int getmin(int a, int b){
       return a < b ? a : b;}int getmax(int a, int b){
       return a > b ? a : b;}
//02.采用函数指针作为形参可以实现固化接口的作用
//  固化接口+动化逻辑!
void op(int(*pFun)(int, int), int a, int b){
       printf("%d \n", pFun(a, b));}
//02.只要作为声明的格式,就可以进行函数形参的省略!
//  1.区分函数调用和读取函数指针常量所存储的函数入口点地址
//  2.对于函数指针变量没有自变的说法,因为毫无意义!//03.区分函数指针变量和函数指针变量的类型!
int main01(void){
       
//错误的定义方式,因为类型不匹配    
//int(*pFun)(int, int) = add(1, 2);
//不行:函数调用-->返回结果-->被当做函数调用地址!-->错误现象    
//参数名可以省略,声明的结构    int(*pFun)(int, int) = add;    
//p1++;//函数指针变量,没有变的说法!    
//p2++;    //p3 + n;    
//int(*pFun)(int, int);
//函数指针    
//int (*)(int, int)
//函数指针的类型    
int(* get() )(int, int);
//一个返回值为函数指针,参数为void类型的函数常量指针    
//难度解析:规律剖析    
//  原始:int(*get(int(*y)(int, int), double))(int, int);    
//  剖析:int(*        get(        int (*y)(int, int), double      )       )(int, int)    
//  解析:一个返回值为函数指针(int (*)(int, int)),参数为函数指针(int(*y)(int, int))和双精度浮点型(double)的函数指针常量    
//  特点:函数实现的时候,所有形参必须具备形参名称!   
 //      作为函数的返回值类型声明不需要进行名称说明!    
//  拓展:指向该函数指针的函数指针变量声明格式    
//  int (*(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hi_space

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值