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

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;
}

(0)

相关推荐

  • C 语言指针变量详细介绍

    数据在内存中的地址也称为指针,如果一个变量存储了一份数据的指针,我们就称它为指针变量. 在C语言中,允许用一个变量来存放指针,这种变量称为指针变量.指针变量的值就是某份数据的地址,这样的一份数据可以是数组.字符串.函数,也可以是另外的一个普通变量或指针变量. 现在假设有一个 char 类型的变量 c,它存储了字符 'K'(ASCII码为十进制数 75),并占用了地址为 0X11A 的内存(地址通常用十六进制表示).另外有一个指针变量 p,它的值为 0X11A,正好等于变量 c 的地址,这种情况我

  • 深入分析C语言中结构体指针的定义与引用详解

    指向结构体类型变量的使用首先让我们定义结构体:struct stu{char name[20];long number;float score[4];} ;再定义指向结构体类型变量的指针变量:struct stu *p1, *p2 ;定义指针变量p 1.p 2,分别指向结构体类型变量.引用形式为:指针变量→成员:[例7-2] 对指向结构体类型变量的正确使用.输入一个结构体类型变量的成员,并输出. 复制代码 代码如下: #include <stdlib.h> /*使用m a l l o c (

  • C语言指针学习经验总结浅谈

    这篇C语言指针学习经验总结主要是我入职以来学习C指针过程中的点滴记录.文档里面就不重复书上说得很清楚的概念性东西,只把一些说得不清楚或理解起来比较费解的东西做一下讲解,希望能达到以下三个目的 1.通过写这些东西,把我脑袋中关于C的模糊的知识清晰化.2.给初转C的同事们一点提示和帮助.3.也希望各位前辈检查一下文档中是否有理解偏差的地方.1 指针的概念分解      指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址. 要搞清一个指针需要搞清指针的四方面的内容: 1.指针的类型2.指

  • C语言入门之指针用法教程

    本文针对C语言初学者详细讲述了指针的用法,并配以实例进行说明.具体分析如下: 对于C语言初学者来说,需要明白指针是啥?重点就在一个"指"上.指啥?指的地址.啥地址?内存的地址. 上面说明就是指针的本质了. 这里再详细解释下.数据存起来是要存在内存里面的,就是在内存里圈出一块地,在这块地里放想放的东西.变量关心的是这块地里放的东西,并不关心它在内存的哪里圈的地:而指针则关心这块地在内存的哪个地方,并不关心这块地多大,里面存了什么东西. 指针怎么用呢?下面就是基本用法: int a, b,

  • C语言中常量指针与指针常量区别浅析

    常量指针是指--指向常量的指针,顾名思义,就是指针指向的是常量,即,它不能指向变量,它指向的内容不能被改变,不能通过指针来修改它指向的内容,但是指针自身不是常量,它自身的值可以改变,从而指向另一个常量.指针常量是指--指针本身是常量.它指向的地址是不可改变的,但地址里的内容可以通过指针改变.它指向的地址将伴其一生,直到生命周期结束.有一点需要注意的是,指针常量在定义时必须同时赋初值.注:也有人将这两个名称的定义与含义反过来认为:"指针常量:顾名思义它的中心词是"常量"这是重点

  • c语言指针之二级指针示例

    二级指针的概念 首先任何值都有地址,一级指针的值虽然是地址,但这个地址做为一个值亦需要空间来存放,是空间就具有地址,这就是存放地址这一值的空间所具有的地址,二级指针就是为了获取这个地址,一级指针所关联的是其值(一个地址)名下空间里的数据,这个数据可以是任意类型并做任意用途,但二级指针所关联的数据只有一个类型一个用途,就是地址,指针就是两个用途提供目标的读取或改写,那么二级指针就是为了提供对于内存地址的读取或改写指针的表现形式是地址,核心是指向关系指针运算符"*"的作用是按照指向关系访问

  • 解析C语言中空指针、空指针常量、NULL & 0的详解

    什么是空指针常量(null pointer constant)?[6.3.2.3-3] An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 这里告诉我们:0.0L.'\0'.3 - 3.0 * 17 (它们都是"integer constant expression")以及 (void*

  • C语言数组指针的小例子

    1.功能:输入6个学生的5门课程成绩,计算出每个学生的平均分和每门课程的平均分.2.C语言实现代码:(其实就是用二维数组来实现的,二维数组的引用传递使用数组指针来完成) 复制代码 代码如下: #include <stdio.h>#define STUDENT 5#define SCORE 6void input_array(float (*score)[STUDENT]);void avg_score(float (*score)[STUDENT]);void avg_course(float

  • C语言指针的长度和类型深入分析

    指针是C语言的精髓,本文就以实例的形式详细分析了C语言的长度和类型.对于初学者深入理解C语言程序设计有很好的参考价值.具体分析如下: 一般来说,如果考虑应用程序的兼容性和可移植性,指针的长度就是一个问题,在大部分现代平台上,数据指针的长度通常是一样的,与指针类型无关,尽管C标准没有规定所有类型指针的长度相同,但是通常实际情况就是这样.但是函数指针长度可能与数据指针的长度不同. 指针的长度取决于使用的机器和编译器,例如:在现代windows上,指针是32位或是64位长 测试代码如下: #inclu

  • 关于C语言指针赋值的问题详解

    一个代码: 复制代码 代码如下: #include<stdio.h>#include<stdlib.h>#define uchar unsigned char#define uint unsigned int void display(uchar *p); char h[4] = {'A','B','C','\0'};char e[4] = {'E','F','L','\0'};char l[4] = {'M','N','O','\0'};char o[4] = {'X','Y',

  • C语言的指针类型详细解析

    指针存储了内存的地址,同时指针是有类型的,如int*,float*,那么,一个自然的猜想就是指针变量应该存储这两方面的信息:地址和指针类型,比如,就像下面的结构体: 复制代码 代码如下: struct pointer{    long address;    int type;} 举个例子:打印sizeof(int*),值为4,可见4字节是存储内存地址用的,反过来就说明指针并没有存储类型信息的地方,那么指针的类型信息存放在哪儿呢?下面剖析一段简单的代码. 复制代码 代码如下: // ma.cpp

随机推荐