指针与函数
用指针作为函数的参数
引:函数参数可以为 int
、char
、float
等,这些参数只作为形参,所有操作都只在函数体内有效(除对指针的操作外)
一、传递指针给函数
-
传递普通(如int)型指针给函数
//通过函数将x,y进行值的转换 void swap(int *x, int *y); void main() { int x = 20, y = 10; swap(&x, &y); printf("x = %d, y = %d", x ,y); } void swap(int *x, int *y) { int t; t = *x; *x = *y; *y = t; } //结果:x = 10, y = 20
用指针作为函数参数,函数内改变被指针指向变量的值,在函数外值也会的改变。
-
传递指针数组给函数
//通过函数求数组元素之和 #include <stdio.h> int sum(int *arr); int main() { int num[5] = {1000, 2, 3, 17, 50}; int a; a = sum( num ) ; printf("sum is: %d\n", a ); return 0; } int sum(int *arr) { int i, b = 0; for (i = 0; i < 5; i++) { b += arr[i]; } return b; }
二、从函数返回指针
-
返回值为指针的函数声明
数据类型 *函数名(参数列表) { 函数体 }
例:
int s; void mian() { int *r = sum(10, 9); printf("10 + 9 + %d", *r); } int *sum(int x, int y) { s = x + y; return &s; }
注意
C 语言不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量。
函数返回指针用于返回一个指向数组的指针,这样就实现了返回值为数组。 -
返回指向数组的指针的函数例题
生成 10 个随机数,并使用表示指针的数组名来返回它们#include <stdio.h> #include <time.h> #include <stdlib.h> int *getRandom( ) { static int r[10]; int i; srand( (unsigned)time( NULL ) ); for ( i = 0; i < 10; ++i) { r[i] = rand( ); } return r; //第一个数组元素的地址 } int main () { int *p; int i; **p = getRandom( ); //返回指向数组的指针** for ( i = 0; i < 10; i++ ) { printf("*(p + [%d]) : %d\n", i, *(p + i) ); } return 0; }
三、指向函数的指针
一个函数在编译之后,会占据一部分内存,而它的函数名,就是这段函数的入口地址.
可以把一个指针,声明成为一个指向函数的指针,将指针作为参数传递。
-
定义
数据类型 (*函数指针名)(); typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
注意事项
函数指针在进行“*”操作时,可以理解为执行该函数
函数的调用:(*p)(x, y);
int a=(*pfun)(5,7);
函数名会自动认为指向这个函数的指针
两种形式:函数指针名 = 函数名; 函数指针名 = &函数名int fun(int a, int b) { return a+b; } int main() { int (*pfun)(int,int); pfun = fun; int a = (*pfun)(5,7); }
指向函数的指针必须初始化,或者具有 0 值,才能在函数调用中使用
禁止对指向函数的指针进行自增运算++
禁止对函数名赋值,函数名也不能用于进行算术运算
*函数名 --> *(&函数名) --> 函数名 --> &函数名//在使用中函数名会被转换为指向这个函数的指针 int a(int m, int n) { return m+n; } void main() { a(1,2); printf("%p",*a); } //结果:0000000000401530
-
例题——比较三个数大小
#include <stdio.h> int max(int x, int y) { return x > y ? x : y; } int main(void) { int (* p)(int, int) = & max; // &可以省略 int a, b, c, d; printf("请输入三个数字:"); scanf("%d %d %d", &a, &b, &c); /* 与直接调用函数等价,d = max(max(a, b), c) */ d = p(p(a, b), c); printf("最大的数字是: %d\n", d); return 0; }
四、回调函数
函数指针作为某个函数的参数
回调函数就是一个通过函数指针调用的函数。
-
解释
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。
你的电话号码就叫回调函数,电话叫函数指针,
你把电话留给店员就叫登记回调函数,
店里后来有货了叫做触发了回调关联的事件,
店员给你打电话叫做调用回调函数,
你到店里去取货叫做响应回调事件。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就说这是回调函数。
-
实例分析
fun函数定义了三个参数,其中第三个参数是函数的指针,通过该函数来设置数组的值。
#include <stdlib.h> #include <stdio.h> // 回调函数 void fun( int *arr, int arrSize, int (*pRandom)(void) ) { int i; for(i=0; i<arrSize; i++) { *(arr+i) = pRandom(); //将函数的值赋给数组 } } // 获取随机值 int random(void) { return rand(); } int main(void) { int myarr[10]; int i; fun(myarr, 10, random); for(i=0; i<10; i++) { printf("%d\\n", myarr[i]); } }
-
优点
1)解耦: 在主入口程序中,把回调函数像参数一样传入库函数。这样一来,只要我们改变传进库函数的参数,就可以实现不同的功能,且不需要修改库函数的实现,变的很灵活。
2)主函数和回调函数是在同一层的,而库函数在另外一层。 如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数了。