6

c语言入门24,函数指针和指针函数

 3 years ago
source link: https://blog.popkx.com/introduction-to-c-language-24-function-pointer-and-pointer-function/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

c语言入门24,函数指针和指针函数

发表于 2018-11-27 20:11:45   |   已被 访问: 444 次   |   分类于:   C语言   |   暂无评论

在第22节,我们弄清了数组指针指针数组的区别和联系,现在趁热打铁,一起来看看函数指针指针函数

初学者看到这里,可能会觉得 C 语言是一门喜欢咬文嚼字的编程语言,其实弄懂了,你自然也会这么称呼它们的。

781b25194d3348a0e4a0af40be4293e3.png

回想一下 22 节,我们只要把“数组”像“int”一样看作是一种数据类型,数组指针和指针数组就具有很明显的区别了。int 指针是指向 int 型数据,那数组指针就指向数组的指针。int 数组是一个存放 int 数据的数组,那指针数组就是存放指针的数组。在 C 语言中,函数也是一种类型,那
函数指针就是指向函数的指针。

函数指针怎么定义呢?请看下面这个例子:

#include <stdio.h>
void hello(char* name)
{
    printf("hello, %s\n", name);
}
int main()
{
    void (*f)(char *) = hello;
    f("Jim");
    return 0;
}
e0a5bee22be18694098c1193905bc625.png

分析定义函数指针的表达式 void (* f )(char * ) 和分析数组指针的定义方式是相似的,() 的优先级高,所以 f 先和 * 结合,因此 f 首先是一个指针,什么类型呢?* f 外面是一个函数原型的格式,参数是 char* ,返回值是 void,所以 f 是一个函数类型的指针。而 hello 函数恰好参数是 char* 类型,返回值是 void 类型,因此可以让 f 指向 hello。也可以写成:
void (*f)(char *) =&hello;

可以通过函数指针调用它指向的函数,例如上面的 f("Jim"),也可以以 (* f)("Jim") 的形式调用它指向的函数。应该注意到了,单独写 f 的时候,它是一个函数指针,并没有函数调用。想调用函数,需要加上“()”符号。

可以把 "()"理解为函数调用的运算符,它的左侧要求是函数指针。

初学者看到这里,可能有些疑问,例如为什么初始化 f 时,既可以把 hello 直接赋值给 f,也可以把 &hello 赋值给 f?再例如,为什么通过 f 调用函数时,既可以直接 f("Jim"),也可以 (* f)("Jim")?其实做个试验就明白了,我们把 &hello,hello,* hello 地址打印出来,请看:

printf("&hello: %p\n", &hello);
printf(" hello: %p\n", hello);
printf("*hello: %p\n", *hello);

编译执行,会发现其实这三者是相等的,所以上面介绍的那些使用方式虽然略有不同,程序也可以正常工作。

1f9b750ca1b15e127d27674949d9ba36.png

不过,使用函数指针时,有些程序员更习惯下面这么用,这样一眼就能看出使用的是函数指针,当然,究竟使用哪种主要取决于个人习惯。

  • 把 hello 当作函数指针时,使用 &hello。
  • f 是指向函数的指针,通过 f 调用函数时,使用 (* f)(...)。

好了,现在知道怎么使用函数指针了,只是,函数指针的定义方式有些繁琐,如果我想定义多个同样类型的函数,要写好多重复代码,这不是“不优雅”吗?的确,应该尽量避免重复代码,好在 C 语言有 typedef 关键字。

typedef         unsigned char         uchar;
uchar i = 0;
7df5da4809835689c3a85db00da77342.png

typedef 关键字使得我们可以用其他符号代替较繁琐的数据类型,例如上例代码,我们使用 uchar 符号代替了 “unsigned char”类型,以后想定义 unsigned char 类型的变量,直接用 uchar 就可以了,在上例中,我们用 uchar 定义了一个 unsigned char 类型的变量 i。函数指针的定义方式也可以用 typedef 关键词简化:

typedef   void (*FUN)(char *);
FUN f = &hello;
(*f)("Jim");

我们使用 FUN 符号代替了函数指针类型,这种函数的参数类型为 char* ,返回值为 void。以后遇到这种类型的函数,直接使用 FUN 符号就可以定义出对应的函数指针。

7217128b7b7c923a4bbbf939f3857530.png

似乎又是一个比较陌生的词,不过我们对 int 函数还是挺熟悉的,int 函数是返回 int 数据的函数,那指针函数就是返回指针的函数。就这么简单?是的,就这么简单。下面给出一个指针函数的使用实例,请看:

#include <stdio.h>
char *str1 = "hello, i am Jim\n";
char *str2 = "hello, i am Tom\n";
char *get_str()
{
    static char i = 0;
    if((i ++)%2)
        return str1;
    else
        return str2;
}
int main()
{
    printf("%s", get_str());
    printf("%s", get_str());
    return 0;
}

get_str 函数返回值是 char 指针类型的,所以 get_str 是一个指针函数。它的调用方式和 int 等其他类型函数的调用一样,指针函数实在没什么特别的。

70844494dfc74ae787d8ba0e02b26758.png

指针函数是一个函数,它的返回值是指针类型。函数指针是一个指针,它指向函数,通过函数指针可以调用它指向的函数,通过函数指针,我们可以让 C 语言仿 C++ 实现“类”的封装,接下来会介绍。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK