做学校子网站,网站建设 合肥,个人 备案 多个网站吗,如何做网店网站我们经常会听到这样的说法#xff0c;不懂得函数指针就不是真正的C语言高手。我们不管这句话对与否#xff0c;但是它都从侧面反应出了函数指针的重要性#xff0c;所以我们还是有必要掌握对函数指针的使用。先来看看函数指针的定义吧。 函数是由执行语句组成的指令序列或者… 我们经常会听到这样的说法不懂得函数指针就不是真正的C语言高手。我们不管这句话对与否但是它都从侧面反应出了函数指针的重要性所以我们还是有必要掌握对函数指针的使用。先来看看函数指针的定义吧。 函数是由执行语句组成的指令序列或者代码这些代码的有序集合根据其大小被分配到一定的内存空间中这一片内存空间的起始地址就成为函数的地址不同的函数有不同的函数地址编译器通过函数名来索引函数的入口地址为了方便操作类型属性相同的函数c/c引入了函数指针函数指针就是指向代码入口地址的指针是指向函数的指针变量。 因而“函数指针”本身首先应该是指针变量只不过该指针变量指向函数。这正如用指针变量可指向整形变量、字符型、数组一样这里是指向函数。C在编译时每一个函数都有一个入口地址该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后可用该指针变量调用函数就如同用指针变量可引用其他类型变量一样在这些概念上是一致的。函数指针有两个用途调用函数和做函数的参数。 函数指针的声明方法为 数据类型标志符 (指针变量名) (形参列表); 一简单的函数指针的应用。 返回类型(*函数名)(参数表) [cpp] view plaincopy char (*pFun)(int); char glFun(int a){ return;} void main() { pFun glFun; (*pFun)(2); } 第一行定义了一个指针变量pFun。首先我们根据前面提到的“形式1”认识到它是一个指向某种函数的指针这种函数参数是一个int型返回值是char类型。只有第一句我们还无法使用这个指针因为我们还未对它进行赋值。 第二行定义了一个函数glFun()。该函数正好是一个以int为参数返回char的函数。我们要从指针的层次上理解函数——函数的函数名实际上就是一个指针函数名指向该函数的代码在内存中的首地址。 然后就是可爱的main()函数了它的第一句您应该看得懂了——它将函数glFun的地址赋值给变量pFun。main()函数的第二句中“*pFun”显然是取pFun所指向地址的内容当然也就是取出了函数glFun()的内容然后给定参数为2。 下面的程序说明了函数指针调用函数的方法 [cpp] view plaincopy #include stdio.h int max ( int x, int y){ return xy?x:y;} int min ( int x, int y){ return xy?x:y;} void main () { int ( *f ) ( int x, int y)max; //fmax;/span printf ( %d,%d\n, max (2,6), (f)(5,4)); fmin; printf (%d,%d\n , min (2,6), (f)(5,4)); } 注意以上代码的红色部分我们将会在接下来的代码分析部分进行讲解读者也可以思考下如果运行注释部分结果是否还是正确的呢?f是指向函数的指针变量所以可把函数max()赋给f作为f的值即把max()的入口地址赋给f,以后就可以用f来调用该函数实际上f和max都指向同一个入口地址不同就是f是一个指针变量不像函数名称那样是死的它可以指向任何函数就看你想怎么做了。在程序中把哪个函数的地址赋给它它就指向哪个函数。而后用指针变量调用它因此可以先后指向不同的函数。不过注意指向函数的指针变量没有和--运算用时要小心。 函数括号中的形参可有可无视情况而定,不过在某些编译器中这是不能通过的。 执行结果如下 在上面的描述中留下过一个问题就是运行注释部分fmax;结果是否还是正确的呢?下面我就给出上面两个运行结果的对别然后来分析下原因。 把注释部分加进去的运行结果为 对比以上的运行结果可以看出fmax语句被执行时的结果和没有被执行时的结果是一样的。为什么会出现这样的结果呢?答案是这是编译器处理的max本身就是个地址它没有放到任何变量里自然没有取它的地址一说。 二使用typedef更直观更方便 typedef 返回类型(*新类型)(参数表) [cpp] view plaincopy typedef char (*PTRFUN)(int); PTRFUN pFun; char glFun(int a){ return;} void main() { pFun glFun; (*pFun)(2); } typedef的功能是定义新的类型。第一句就是定义了一种PTRFUN的类型并定义这种类型为指向某种函数的指针这种函数以一个int为参数并返回char类型。后面就可以像使用int,char一样使用PTRFUN了。第二行的代码便使用这个新类型定义了变量pFun此时就可以像使用形式1一样使用这个变量了。 [cpp] view plaincopy #include stdio.h void FileFunc() { printf(FileFunc\n); } void EditFunc() { printf(EditFunc\n); } void main() { typedef void (*funcp)(); funcp pfun FileFunc; pfun(); pfun EditFunc; pfun(); } 许多C/C的面试题都喜欢出一些关于指针的题目比如说出下列式子的含义 [cpp] view plaincopy void * (*(*fp1)(int))[10]; float (*(*fp2)(int, int, float))(int); typedef double (*(*(*fp3)())[10])(); fp3 a; int (*(*fp4)[10])(); 对于fp1:我们从里向外一点一点分析首先(*fp1)(int)这说明fp1是一个函数指针它有一个int类型的参数然后我们来找这个函数指针类型的返回值注意到*(*fp1)(int)所以我们可以断定它的返回值是一个指针指针指向什么呢 我们可以看到最外层剩余的部分是void* [10]因此这个函数的返回值是一个指针这个指针指向一个包含十个void*类型数据的数组。 综上fp1是一个函数指针它所指向的函数有一个int类型的参数并且这个函数的返回值是一个指针这个指针指向一个包含10个void*元素的数组。 对于fp2 就不再赘述了。fp2是一个函数指针它所指向的函数有三个参数参数类型分别为int,int,float它的返回值是一个函数指针这个函数指针所指向的函数具有一个int类型的参数且返回类型为float。 对于fp3 fp3被定义为一个函数指针类型这种函数指针所指向的函数的参数为空它的返回值是一个指针这个指针指向一个包含10元素的函数指针数组这些函数指针所指向的函数的参数为空返回值为double。 对于fp4 fp4是一个指针这个指针指向一个包含10元素的函数指针数组这些函数指针所指向的函数的参数为空返回值为int。 《C陷阱与缺陷》中以下面一个例子对函数指针进行了讲解如下 (*(void(*)())0)(); 如果能明白上边几个例子的含义那么这个简直就是小case啊 函数指针程序举例 在库函数和系统调用中有许多函数的原型都设计了函数指针现在举几个例子来加深大家对函数指针的理解。 1、线程创建的函数 [cpp] view plaincopy #include pthread.h int pthread_create(pthread_t *restrict thread, pthread_attr_t *restrict attr,void *(*start_routine)(void *),void *restrict arg); 该函数的功能就是创建一个线程第三个参数就是函数指针 2、信号注册的函数 [cpp] view plaincopy #include stdio.h typedef void (*sighandler_t)(int); sighandler_t signal(int sigum,sighandle_t handler); 当然我们也已用方法一来定义 [cpp] view plaincopy #include stdio.h void (*signal(int sig,void(*func)(int))) (int); 顺便提一下库函数调用和系统调用的区别 通过这个问题可以判断候选人是否具有丰富的编程经验以及是否具有找出这类问题答案的敏锐感觉。简明的回答是函数库调用是语言或应用程序的一部分而系统调用是操作系统的一部分。你要确保弄懂“trap自陷”这个关键字的含义。系统调用是在操作系统内核发现一个“trap”或中断后进行的。 ※函数库调用 VS 系统调用函数库调用 系统调用 在所有的ANSI C编译器版本中C库函数是相同的 各个操作系统的系统调用是不同的 它调用函数库中的一段程序或函数 它调用系统内核的服务 与用户程序相联系 是操作系统的一个入口点 在用户地址空间执行 在内核地址空间执行 它的运行时间属于“用户时间” 它的运行时间属于“系统”时间 属于过程调用调用开销较小 需要在用户空间和内核上下文环境间切换开销较大 在C函数库libc中有大约300个函数 在UNIX中大约有90个系统调用 典型的C函数库调用system fprintf malloc 典型的系统调用chdir fork write brk 库函数调用通常比行内展开的代码慢因为它需要付出函数调用的开销。但系统调用比库函数调用还要慢很多因为它需要把上下文环境切换到内核模式。