c语言指针与函数的关系,指针和函数的关系

本文详细介绍了C语言中的函数指针,包括如何声明和使用函数指针,以及函数指针与函数的关系。通过示例代码解释了如何通过函数指针调用函数,展示了函数指针数组的运用,并探讨了指针函数和函数指针的混合使用。此外,还提到了函数指针在文件处理程序中的应用,以及复杂的函数声明解析方法。
摘要由CSDN通过智能技术生成

Wanghaha2333参考文章

指针和函数的关系

1、函数指针(指向函数的指针)

一个函数在编译之后,会占据一部分内存,而它的函数名,就是这段函数的首地址。

可以把一个指针声明成为一个指向函数的指针。

C 语言规定函数名会被转换为指向这个函数的指针,除非这个函数名作为 & 操作符或 sizeof 操作符的操作数(注意:函数名用于 sizeof 的操作数是非法的)。也就是说 f = test; 中 test 被自动转换为 &test,而 f = &test; 中已经显示使用了 &test,所以 test 就不会再发生转换了。因此直接引用函数名等效于在函数名上应用 & 运算符,两种方法都会得到指向该函数的指针。

指向函数的指针必须初始化,或者具有 0 值,才能在函数调用中使用。

与数组一样:

(1)禁止对指向函数的指针进行自增运算++

(2)禁止对函数名赋值,函数名也不能用于进行算术运算。

示例1:

int fun1(int,int);

int fun1(int a, int b){

return a+b;

}

int main(){

int (*pfun1)(int,int);

pfun1=fun1;//这里&fun1和fun1的值和类型都一样,用哪个无所谓

int a=(*pfun1)(5,7); //通过函数指针调用函数。

}

示例2:

#include

#include

int Max(int x, int y) //定义Max函数

{

int z;

if (x > y) {

z = x;

}else {

z = y;

}

return z;

}

int main() {//定义一个函数指针

int(*p)(int, int);

int a, b, c;//把函数Max赋给指针变量p, 使p指向Max函数

p = Max;

printf("please enter a and b:");

scanf("%d%d", &a, &b);//通过函数指针调用Max函数

c = (*p)(a, b);

printf("a = %d\nb = %d\nmax = %d\n", a, b, c);

system("pause");

return 0;

}​

示例2:

#include ​ ​

void test( )​{​

printf("test called!/n");​

}​ ​

int main( )​{​

void (*f) ( );​

f = test; ​

f ( );​

(*f)( );​

//test++; // error,标准禁止对指向函数的指针进行自增运算​

//test = test + 2; // error,不能对函数名赋值,函数名也不能用于进行算术运算​

printf("%p/n", test);​

printf("%p/n", &test);​

printf("%p/n", *test);​

return 0;

​}

运行结果为:

test called!

​test called!

​004013EE​004013EE​004013EE

这里的玄学就是 *test 为什么能和上面两个之前介绍过的输出一样的值。

首先来看函数名 test,是一个符号用来标识一个函数的入口地址,在使用中函数名会被转换为指向这个函数的指针,指针的值就是函数的入口地址,&test 在前面已经说了:显示获取函数的地址。*test 可以认为由于 test 已经被转换成了函数指针, 指向这个函数,所以 *test 就是取这个指针所指向的函数名,而又根据函数名会被转换指向该函数的指针的规则,这个函数也转变成了一个指针,所以 *test 最终也是一个指向函数 test 的指针。也就是说:*test --> *(&test) --> test --> &test。

上述关系十分重要!

为了更加明确,把示例 1 做补充:

#include

int fun1(int,int);

int fun1(int a, int b){

return a+b;

}

/* 要调用上面定义函数的主函数 */

int main (){

int (*pfun1)(int,int);

pfun1=fun1;//这里&fun1和fun1的值和类型都一样,用哪个无所谓

int a=(*pfun1)(5,7); //通过函数指针调用函数。

printf("%d\n",a);

int e = fun1(5,7);

printf("%d\n",d)

int b = (&fun1)(5,7);

printf("%d\n",b);

int c = (*fun1)(5,7);

printf("%d",c);

return 0;

}

//根据关系 *fun1==*&fun1==fun1==&fun1 可知,以上的运行结果会得到4个5+7。

//因此在下面的函数指针数组实例中,action[2]()就相当于这里的(&fun1(5,7)),这点务必搞清楚。

2、指针函数(返回值为指针的函数)

所谓指针函数,就是返回指针的函数。在前面笔记中“从函数返回数组”中已经介绍。

C 语言的库函数中有很多都是指针函数,比如字符串处理函数,下面给出一些函数原型:

char *strcat( char *dest, const char *src );​

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

​char *strchr( const char *s, int c );​

char *strstr( const char *src, const char *sub );

3、两者混用(不常用)

注意函数的返回值不仅仅局限于指向变量的指针,也可以是指向函数的指针。

首先来看这个声明:*int (*function(int)) (double*, char); 要了解此声明的含义,首先来看 function(int),将 function 声明为一个函数,它带有一个 int 型的形式参数,这个函数的返回值为一个指针,正是函数指针 int (*) (double*, char); 这个指针指向一个函数,此函数返回 int 型并带有两个分别是 double* 型和 char 型的形参。

如果使用typedef可以将这个声明简化:(没看懂。。。。之后的结构体再补充)

typedef int (*ptf) (double*, char);​

ptf function( int );

另一个例子:void (*signal (int sig, void (*func) (int siga)) ) ( int siga );

现在要分析的是 signal,因为紧邻 signal 的是优先级最高的括号,首先与括号结合,所以 signal 为一个函数,括号内为 signal 的两个形参,一个为int型,一个为指向函数的指针。接下来从向左看,* 表示指向某对象的指针,它所处的位置表明它是 signal 的返回值类型,现在可以把已经分析过的 signal 整体去掉,得到 void (*) ( int siga )。又是一个函数指针,这个指针与 signal 形参表中的第二个参数类型一样,都是指向接受一个 int 型形参且不返回任何值的函数的指针。

用 typedef 可以将这个声明简化:

typedef int (*p_sig) (double*, char);​

p_sig signal(int sig, p_sig func);

这个 signal 函数是 C 语言的库函数,在 signal.h 中定义,用来处理系统中产生的信号。

4、函数指针数组

假设现在有一个文件处理程序,通过一个菜单按钮来选择相应的操作(打开文件,读文件,写文件,关闭文件)。这些操作都实现为函数且类型相同,分别为:

void open();

void read();

void write();

void close();

现在定义一个函数指针类型的别名PF:typedef void (*PF) ( );

把以上 4 种操作取地址放入一个数组中,得到:

PF file_options[ ] = {

&open,

&read,

&write,

&close

};

如果不使用 typedef,那么分析起来就会比较复杂,结果是 void (*file_options[ ]) ( );

这个数组中的元素都是指向不接受参数且不返回任何值的函数的指针,因此这是一个函数指针数组。接下来,定义一个函数指针类型的指针action并初始化为函数指针数组的第一个元素:PF* action = file_options;,如果不好理解,可以类比一下:

int ia[4] = {0, 1, 2, 3};

int *ip = ia;,

这里 PF 相当于 int,这样应该比较好懂了。

复习:

int ia[4] = {0, 1, 2, 3};

int *ip = ia; //ia就是&ia[0],因此ip指向ia[0]。与此同时ip[1]的含义又和*(ip+1)一样。

printf("%p\n",ip);

printf("%p\n",ip+1);

printf("%d\n",ip[1]);

printf("%d\n",*(ip+1));​/*输出结果0x7ffee4cca9b00x7ffee4cca9b411*/

通过对指针 action 进行下标操作可以调用数组中的任一操作,如:action[2]( ) 会调用 write 操作,以此类推。在实际中,指针 action 可以和鼠标或者其他 GUI 对象相关联,以达到相应的目的。

5、函数与指针的复杂声明(不做要求,一般用 typedef 代替它)

只举一个例子:int *(*(*fp)(int)) [10];

阅读步骤:

1.从未定义的变量名开始阅读 -------------------------------------------- fp

2.往右看,什么也没有,遇到了),因此往左看,遇到一个* ------ 一个指向某对象的指针

3.跳出括号,遇到了(int) ----------------------------------- 一个带一个int参数的函数

4.向左看,发现一个* --------------------------------------- (函数)返回一个指向某对象的指针

5.跳出括号,向右看,遇到[10] ------------------------------ 一个10元素的数组

6.向左看,发现一个* --------------------------------------- 一个指向某对象指针

7.向左看,发现int ----------------------------------------- int类型

所以 fp 是指向函数的指针(函数指针), 该函数返回一个指向数组的指针,此数组有 10 个 int* 型的元素。

int *(*(*fp)(int)) [10];

(*fp)(int)是一个指向函数的指针ptr*(*fp)(int)相当于一个指针ptr1(指针函数的返回值)最后剩下int *ptr1[10],可以理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值