《C语言教程》19章 函数指针和函数数组


许多人听到这个名字就感到害怕,指针本身就没有完全搞懂,又有什么双重指针,现在这个东东非把我头搞昏不可。其实并没有那么可怕,但前面所讲的基础的确必须扎实。经小雅一分析,你会觉得指针并不难,真正难的是你没有找到好教程(玩笑)。

一、指向标签的指针

指针的好处就是,你只要对指针变量赋一个地址,你就可以通过这个地址去代替那个变量,从而操作那个变量上的数据。指针变量如果没有赋值,就不能操作数据,因此你必须要将某个变量的地址赋给指针变量,也就是让这个指针有了空间。动态分配空间也是先申请一块空间,然后将这块空间的地址赋给这个指针变量。

在C语言中不仅仅是变量的地址可以赋给指针,goto语句用的标签也可以赋给指针。标签其实就是一个地址,学过汇编语言的人就特别清楚这一点。下面这个例子是在Red Hatt Linux下用gcc编译实现的,遗憾的是Windows下并不支持。不过,如果我们能理解指针的功能也就达到目的了。

#include <stdio.h>

int main(void)
{
    void *ptr ;
    int num;

    scanf("%d", &num);
    if (num < 10) {
        ptr = &&succeed ;
    } else {
        ptr = &&failure ;
    }
    goto *ptr ;

succeed:
    printf("成功!") ;
    return 0;

failure:
    printf("失败!") ;
    return -1 ;
}

二、指向函数的指针

函数指针并不是指函数的地址象指针一样可以被赋值,而是指将函数的固定地址赋给指针变量,从而用指针来代替函数名来操作。

一个函数定义好之后,它和变量一样,也有一个固定的地址,我们把这个地址赋给指针变量,这个指针就可以充当函数来使用。但要注意一点,函数的地址赋给指针变量的方法有点特殊,不能与普通变量一样赋值,否则编译系统就会误解成指针和函数结果的某种运算了。


#include <stdio.h>

//申明一个函数指针的类型。相当于函数申明。
typedef int (*pType) (int) ;

int fact(int number) 
{
    int i , ret = 1 ;

    for (i=1; i<=number; i++) {
        ret *= i ;
    }

    return ret ;
}

int main(void)
{
    int num ;

    pType pt;     //定义一个函数指针类型的变量

    pt = fact;    //将函数fact的地址赋给pt

    scanf("%d", &num);
    printf("%d的阶层=%d \n", num, fact(num));    //这是普通的函数调用
    printf("%d的阶层=%d \n", num, (*pt)(num));   //这是函数指针的调用方法。注意:*pt一定要用括号括起来。

    return 0;
}

上例中typedef语句在后面章节中细说,是用来自定义一个数据类型。当前的语句是typedef的特殊用法,pType是数据类型的名称,可以自己定,一般习惯用法全用大写。*pType两边的括号是必须的,是定义函数指针的标志。(*pType)前面的“int”数据类型是函数的返回值的数据类型,不是任意指定的,是你想要函数指针指向的函数的返回值的数据类型,当前例子中“fact”的返回值的数据类型。(*pType)后面和括号是参数,当前例子中“fact”后面的数据类型相一致。

上例中如果没有第04行的申明,第21行也可改为直接定义。“int (*pt) (int) ;”

三、函数指针的应用

函数指针经常被使用,但初学者或一般的开发者却很少使用。限于自身水平不高,小雅也只能很肤浅地、象征性地举例说明。


#include <stdio.h>

//申明一个函数指针的类型
typedef void (*pType) (int, int) ;

void max(int m, int n) 
{
    printf("最大值=[%d]\n", m>n ? m : n) ;
    return ;
}

void min(int m, int n) 
{
    printf("最小值=[%d]\n", m<n ? m : n) ;
    return ;
}

void fsq(int m, int n)
{
    printf("平方和=[%d]\n", m * m + n * n) ;
    return ;
}

//定义一个用函数指针做参数的函数
void process(int num1, int num2, pType pt) {
    (*pt)(num1, num2);
}

int main(void)
{
    int x, y, i ;
    pType arr[] = {max, min, fsq};    //定义一个函数指针类型的数组

    printf("请输入x和y的值:");
    scanf("%d,%d", &x, &y) ;

    //用法一
    process(x, y, max);    //将函数max的地址作实参数
    process(x, y, min);    //将函数min的地址作实参数
    process(x, y, fsq);    //将函数fsq的地址作实参数

    printf("\n");

    //用法二
    for (i=0; i<3; i++) {
        arr[i](x, y);      //循环调用三个函数
    }

    return 0;
}