函数返回指针
指针本质上也是一种数据类型(就像int
、char
),其中存储了另外一个数据的地址,因此将一个指针作为返回类型是完全可行的。
但是,需要考虑的是,在什么情况下,我们会需要函数返回一个指针类型?
#include <stdio.h>
#include <stdlib.h>
int Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int x = 2, y = 4;
int z = Add(x, y);
printf("Sum = %d\n", z);
}
我们定义了一个加和函数Add
,它从main
函数中接收两个参数,并将二者求和的值返回给main
。
需要注意的是,就像我们之前提到的那样,这里的x,y,z
都是main
函数里的局部变量,而a, b
则都是Add函数中的局部变量。
并且这种函数传参的方式我们之前已经讲过,成为值传递。
要将函数的传参方式改为地址传递,只需改为以下程序:
#include <stdio.h>
#include <stdlib.h>
int Add(int* a, int* b)
{
int c = (*a) + (*b);
return c;
}
int main()
{
int x = 2, y = 4;
int z = Add(&x, &y);
printf("Sum = %d\n", z);
}
函数返回指针
#include <stdio.h>
#include <stdlib.h>
int* Add(int* a, int* b)
{
int c = (*a) + (*b);
return &c;
}
void printHello()
{
printf("Hello\n");
}
int main()
{
int x = 2, y = 4;
int* ptr = Add(&x, &y);
// printHello();
printf("Sum = %d\n", *ptr);
}
以上代码在测试时是正常的,但是如果在打印结果之前再多调用一个函数printHello
,则会导致输出错误。
但是我们将上面的程序中的Add
函数改为:
int* Add(int* a, int* b)
{
int* c = (int*)malloc(sizeof(int));
*c = (*a) + (*b);
return c;
}
这样,程序就可以正常地工作了。
函数指针
函数指针的定义和使用
下面这个程序定义和使用了一个函数指针:
#include <stdio.h>
int Add(int a, int b)
{
return a + b;
}
int main()
{
int c;
int (*p)(int, int);
p = &Add;
c = (*p)(2, 3);
printf("%d\n", c);
}
声明函数指针的语法是:int (*p)(int, int)
,这条语句声明了一个接收两个整型变量作为参数,并且返回一个整型变量的函数指针。
注意函数指针可以指向一类函数,即可以说,指针p
指向的类型是输入两整型,输出一整型的这一类函数,即所有满足这个签名的函数,都可以赋值给p
这个函数指针。
另外,要注意指针要加括号。否则int *p(int, int)
,是声明一个函数名为p
,接收两个整型,并返回一个整型指针的函数。
函数指针赋值:p = &Add
,将函数名为Add
的函数指针赋值给p
。同样注意只要满足p
声明时的函数签名的函数名都可以赋值给p
。
函数指针的使用:int c = (*p)(2, 3),先对p解引用得到函数Add
,然后正常传参和返回即可。
还有一点,在为函数指针赋值时,可以不用取地址符号&
,仅用函数名同样会返回正确的函数地址。与之匹配的,在调用函数的时候也不需要再解引用。这种用法更加常见。
int (*p)(int, int);
p = Add;
c = p(2, 3);
再强调一下:注意函数指针可以指向一类函数,即可以说,指针p
指向的类型是输入两整型,输出一整型的这一类函数,即所有满足这个签名的函数,都可以赋值给p
这个函数指针。用不同的函数签名来声明的函数指针不能指向这个函数。
如以下这些函数指针的声明都是不能指向Add
函数的:
void (*p)(int, int);
int (*p)(int);
int (*p)(int, char);
函数指针的使用案例(回调函数)
回调函数的概念
这里使用函数指针的案例都围绕着这么一个概念:函数指针可以用作函数参数,而接收函数指针作为参数的这个函数,可以回调函数指针所指向的那个函数。
#include <stdio.h>
void A()
{
printf("Hello !\n");
}
void B(void (*ptr)())
{
ptr();
}
int main()
{
void (*p)() = A;
B(p);
B(A);
return 0;
}
或者我们可以直接在主函数中B(A)
,而不需要上面那写两句先复制给p
,再调用p
。
在上面的例程中,将函数A()
的函数指针传给B()
,B()
在函数体内直接通过传入的函数指针调用函数A()
,这个过程成为回调。
这里函数指针被传入另一个函数,再被用函数指针进行回调的函数A()
成为回调函数。