C语言中函数与指针的应用总结

所属分类: 软件编程 / C 语言 阅读数: 113
收藏 0 赞 0 分享

1. 首先,在C语言中函数是一种function-to-pointer的方式,即对于一个函数,会将其自动转换成指针的类型.

复制代码 代码如下:

#include<stdio.h>

void fun()
{
}

int main(void)
{
   printf("%p %p %p\n", &fun, fun, *fun);
   return 0;
}


-------------------------------------------------------------------------------------------

这三个值的结果是一样的. 其实对于最后的那个*fun, 即使前面加上很多个*号, 其结果也不变, 即**fun, ***fun的结果都是一样的.
对于这个问题, 因为之前讲过函数是一种function-to-pointer方式, 其会自动转换成指针的类型, &fun是该函数的地址, 为指针类型, fun是一个函数, 会转换成其指针类型, 而对于*fun, 由于fun已经变成了指针类型, 指向这个函数, 所以*fun就是取这个地址的函数, 而又根据function-to-pointer, 该函数也转变成了一个指针, 所以以此类推, 这三个值的结果是相同的.

===================================================
2. 如何调用一个地址上的函数
如果知道了一个函数所在的地址, 可以将其强制转化成某一种类型的函数指针, 然后再根据这个指针去调用这个地址的函数. 如:

复制代码 代码如下:

#include<stdio.h>

void f(int i)
{
   printf("i = %d\n", i);
}

int main(void)
{
   unsigned long add;
   add = (unsigned long)f;
   ((void (*)(int))add)(10);
   (*(void (*)(int))add)(20);
   return 0;
}


---------------------------------------------------------------------------------------
使用(void (*)(int))的方式可以将一个地址转换成一个带int参数且没有返回值的函数的指针类型, 然后再去调用, 由于第1点中讲的function-to-pointer, 所以最后两条语句中加与不加那个*号效果都是一样的. 在嵌入式方面经常用到这种方式.
=====================================================

3. 函数指针数组的用法.
有时候需要定义一个数组, 其内容为一系列的函数指针, 然后对其进行调用, 如:
复制代码 代码如下:

#include<stdio.h>
int max(int v1, int v2)
{
   return (v1 > v2 ? v1 : v2);
}

int min(int v1, int v2)
{
   return (v1 < v2 ? v1 : v2);
}

int sum(int v1, int v2)
{
   return (v1 + v2);
}


复制代码 代码如下:

int main(void)
{
   int (*p[3])(int, int);
   p[0] = max;
   p[1] = min;
   p[2] = sum;

   printf("p[0] = %d\n", (p[0])(3, 5));
   printf("p[1] = %d\n", (p[1])(4, 6));
   printf("p[2] = %d\n", (p[2])(1, 2));
   return 0;
}


-----------------------------------------------------------------------------------------
虽然感觉这种方法有点累赘, 但是也算是一种使用的方式, 所以介绍一下.
============================================

4.返回一个指向数组的指针的方式

可以让函数返回一个指向数组的一个指针, 如:

复制代码 代码如下:

#include<stdio.h>
#include<stdlib.h>
int (*p())[10]
{
   int (*m)[10];
   int i;
   m = (int (*)[10])malloc(10 * sizeof(int));
   if (m == NULL) {
      printf("malloc error\n");
      exit(1);
   }
   for (i = 0; i < 10; i++)
      *(*m+i) = i+1;

   return m;
}

复制代码 代码如下:

int main(void)
{
   int (*a)[10];
   int i;
   a = p();
   for (i = 0; i < 10; i++)
      printf("%d ", *(*a+i));
   printf("\ndone\n");

   return 0;
}


-------------------------------------------------------------------
这种方式中,int (*a)[10]是一个指向一维数组的一个指针, 而p()也是返回一个指向一维数组的一个指针.
===================================================

5.返回一个函数指针的指针

/============================================/
/ 在看到快速排序的例子中使用到返回指针的函数.所以特此查找到这篇文章,觉得很好... /
/============================================/

对这个问题, signal()函数是最好的例子.
void (*signal (int signo, void (*func)(int)))(int);
很多朋友刚开始看这个函数定义的时候是不太懂, 其实可以一步一步地慢慢看, 我以前是这样分析的, 希望能对大家有用.
int (*p)();
这是一个函数指针, p所指向的函数是一个不带任何参数, 并且返回值为int的一个函数.
int (*fun())();
这个式子与上面式子的区别在于用fun()代替了p,而fun()是一个函数,所以说就可以看成是fun()这个函数执行之后,它的返回值是一个函数指针,这个函数指针(其实就是上面的p)所指向的函数是一个不带任何参数,并且返回值为int的一个函数.

所以说signal()可以看成是signal()函数(它自己是带两个参数,一个为整型,一个为函数指针的函数), 而这个signal()函数的返回值也为一个函数指针,这个函数指针指向一个带一个整型参数,并且返回值为void的一个函数.

=================================
signal函数返回的其实是指向以前的信号处理程序的指针, 所以举一个例子来说明返回指向函数的指针的用法.

复制代码 代码如下:

#include<signal.h>
#include<stdlib.h>
#include<stdio.h>

void sig_fun2(int signo)
{
   printf("in sig_fun2:%d\n", signo);
}

void sig_fun1(int signo)
{
   printf("in sig_fun1:%d\n", signo);
}

int main(void)
{
   unsigned long i;
   if (signal(SIGUSR1, sig_fun1) == SIG_ERR) {
      printf("signal fun1 error\n");
      exit(1);
   }

   (signal(SIGUSR1, sig_fun2))(30);

   printf("done\n");
   return 0;
}


====================================================
6. 使用函数指针作为参数的情况 (以前的记录提到过.)
在函数的参数中, 可能会带有一个函数指针, 这在signal()函数中是出现了的.
其实在很多排序函数中就是使用的这个参数为函数指针的方式来进行调用的.比如Quicksort

例如:

复制代码 代码如下:

#include<stdio.h>

int max(int v1, int v2)
{
   return (v1 > v2 ? v1 : v2);
}

int min(int v1, int v2)
{
   return (v1 < v2 ? v1 : v2);
}

int sum(int v1, int v2)
{
   return (v1 + v2);
}

int fun(int a, int b, int (*call)(int, int))
{
   return (call(a, b));
}

int main(void)
{
   printf("max=%d\n", fun(1, 2, max));
   printf("min=%d\n", fun(3, 4, min));
   printf("sum=%d\n", fun(5, 6, sum));
   return 0;
}


更多精彩内容其他人还在看

用标准c++实现string与各种类型之间的转换

这个类在头文件中定义, < sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本
收藏 0 赞 0 分享

C++如何通过ostringstream实现任意类型转string

再使用整型转string的时候感觉有点棘手,因为itoa不是标准C里面的,而且即便是有itoa,其他类型转string不是很方便。后来去网上找了一下,发现有一个好方法
收藏 0 赞 0 分享

C/C++指针小结

要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区
收藏 0 赞 0 分享

C++ 类的静态成员深入解析

在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象
收藏 0 赞 0 分享

C++类的静态成员初始化详细讲解

通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域操作符来指出静态成员所属的类.但如果静态成员是整型或是枚举型const,则可以在类声明中初始化
收藏 0 赞 0 分享

C++类静态成员与类静态成员函数详解

静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值
收藏 0 赞 0 分享

C++中的friend友元函数详细解析

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样
收藏 0 赞 0 分享

static全局变量与普通的全局变量的区别详细解析

以下是对static全局变量与普通的全局变量的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助
收藏 0 赞 0 分享

C++ explicit关键字的应用方法详细讲解

C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?下面就让我们一起来看看这方面的知识吧
收藏 0 赞 0 分享

教你5分钟轻松搞定内存字节对齐

随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
收藏 0 赞 0 分享
查看更多