【深入C指针】第三章:函数与指针

什么是函数指针?本文介绍了函数指针巧妙的用法。


第三章:指针和函数

3.0 导言

指针与函数之间有什么关系,什么是程序栈?

以上便是本章讨论的内容。

3.1 程序栈

举一个求阶乘的例子说明:

int fun(int n){
    if(n!=1)return n*fun(n-1);
    return 1;
}
int main(){
    int a = fun(3);
    printf("%d\n",a);
}

结果:

6

从栈的角度用图说明上面例子的流程:

【深入C指针】第三章:函数与指针

解释:

前四张图掩饰了push压栈的过程,整个函数会存储到内存栈中。
函数中自然包含了变量int n

后面四张图展示了pop出栈过程,同时return n*fun(n-1)给下面的函数中。

3.2 函数指针

函数指针是持有函数地址的指针。

人们使用函数指针的一个顾虑是这种做法可能会导致程序运行变慢,处理器可能无法配合流水线做分支预测。
分支预测是处理器用来推测哪块代码会被执行的技术。
流水线是常用的提升处理器性能的硬件技术,通过重叠指令的执行来实现。
在这种机制下,处理器会处理它认为能执行的分支,如果预测正确,那么就不需要丢弃当前流水线中的指令。

函数指针对性能的影响要视具体情况而定。
在表查找等场景中使用函数指针可以缓解性能问题。
在本节中,我们会学习如何声明函数指针,如何使用函数指针来支持其他的执行路径,还会探索能够充分发挥函数指针潜能的技术。

3.2.1 声明函数指针

举些例子:

int (*f1)(double);      //传入double,返回int
void (*f2)(char*);      //传入char指针,无返回值
double* (*f3)(int,int); //传入两个int,返回double指针

注意不要吧返回指针的函数和函数指针搞混了。

下面的例子中:

f4是函数,返回一个整数指针;
f5是返回整数的函数指针;
f6是返回整数的函数指针。

int *f4();
int (*f5)();
int *(*f6);

3.2.2 使用函数指针

约定俗成用fptr作为函数指针的前缀。

简单的例子:求整数的平方。

要用函数指针来调用square函数,需要把square函数的地址赋给函数指针,如下所示。就像数组名字一样,我们用的是函数本身的名字,它会返回函数的地址。我们还声明了一个整数并将其传递给函数:

int (*fptr1)(int);

int square(int num){
    return num*num;
}

int main(){
    int n=5;
    fptr1 = square; //此处把square函数的地址赋值给了函数指针fptr1
    printf("%d squared is %d \n",n,fptr1(n));
}

Output:

5 squared is 25

另外,以下两行代码效果一样。编译器会忽略&

fptr1 = square;
fptr1 = □

再来一个例子:这是一个传递加法函数和减法函数的例子。

int add(int n1,int n2){
    return n1+n2;
}
int subtract(int n1,int n2){
    return n1-n2;
}

typedef int (*fptrOearation)(int,int);

int compute(fptrOearation op,int n1,int n2){
    return op(n1,n2);
}

int main(){
    printf("%d\n",compute(add,4,5));
    printf("%d\n",compute(subtract,5,6));
}

3.3 小结

函数指针基础用法。

评论区 0