`
switchlau
  • 浏览: 54441 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

(转) 关于指针与函数的几点小结

阅读更多

http://bbs.chinaunix.net/viewthread.php?tid=993238&extra=page%3D1%26amp%3Bfilter%3Ddigest

心血来潮, 想对函数指针的几个用法小结一下, 都是平常容易见到的, 如果还有其它不觉的用法也请朋友们不吝赐教.若有错误之处,还请指正.

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

 

#include<stdio.h>

void fun()
{
}

int main()
{
        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()
{
        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()
{
        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()
{
        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的一个函数.所以说对于
void (*signal(int signo, void (*fun)(int)))(int);
  
就可以看成是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()
{
        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()函数中是出现了的, 另外再写个例子如:

#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()
{
        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;
}

 


其实在很多排序函数中就是使用的这个参数为函数指针的方式来进行调用的.

草草地总结了一下, 希望能有一些用.  

分享到:
评论

相关推荐

    void指针小结

    ### void指针小结 #### 一、概述 在C/C++编程语言中,`void`关键字及其关联的`void`指针类型常常让初学者感到困惑。由于对其概念理解不深,导致在实践中出现各种错误。本文旨在深入探讨`void`关键字的含义及其在...

    第8章 指针-6从函数返回字符串1

    小结一下,理解以下几点至关重要: 1. 字符串的存储位置以及字符指针的指向。 2. 区分指向字符串常量和字符数组的指针。 3. 使用指针作为参数传递字符串(字符数组)给函数。 4. 通过函数返回指向字符串的指针来...

    C++你最好不要做的几点小结

    C++编程语言中,有几项实践应当避免,特别是对于初学者来说,这些做法可能会导致意想不到的错误或性能问题。以下是一些需要注意的关键点: 1. **不要使用引用作为返回值**: 引用是一种别名,它不创建新对象,而是...

    关于C++知识点的一些小结

    在基类中声明一个虚函数,派生类可以重写这个虚函数,当基类指针或引用调用这个虚函数时,实际执行的是派生类的版本。虚函数的关键字是`virtual`。 3. 作用: 多态的作用在于实现代码的复用和封装,使得程序设计...

    singleton、回调函数、sizeof等小结.docx

    在C++中,回调函数通常与C语言的函数指针密切相关,但在现代C++中,可以使用函数对象(Functors)、Lambda表达式或者std::function来实现更安全、更灵活的回调机制,避免了C风格回调函数的一些限制和潜在问题。...

    C语言教程课件Ch10指针复习.ppt

    本篇教程课件主要涵盖了以下几个关于指针的知识点: 1. **指针的概念**: 指针是一个变量,其值为另一个变量的内存地址。它存储了变量在内存中的位置,允许我们通过指针间接访问和修改该位置的值。 2. **变量的...

    C语言中网络地址与二进制数之间转换的函数小结

    以下是关于C语言中用于网络地址与二进制数转换的几个关键函数的详细说明: 1. **inet_ntoa() 函数**: - 这个函数用于将网络二进制的IP地址转换为人类可读的点分十进制格式(即网络地址)。函数原型如下: ```c ...

    Keil_C使用经验小结

    使用指针时需要注意以下几点: - 指针类型应与所指向的数据类型匹配。 - 对于片外RAM的访问,应使用适当的MOVX指令。 - 避免野指针的出现,确保指针初始化正确。 #### 六、函数 函数是程序的基本构建块,Keil C...

    CC++数组名与指针区别深入探索

    通过对上述示例的理解,我们可以总结出以下几点: - 数组名在很多情况下可以被视为指向数组首元素的常量指针。 - 指针提供了更灵活的操作方式,可以动态地指向不同的内存区域。 - 在使用`sizeof`运算符时,需要注意...

    基于指针的数据类型与指针运算小结

    本篇文章将详细讲解指针的数据类型和指针运算的相关知识点。 首先,我们来看指针的数据类型。指针变量是用来存储内存地址的变量,它们的类型通常基于它们所指向的数据类型。以下是几种常见的指针数据类型: 1. `...

    课程学习中c++ 的一点小结

    - 在C++中,`void*` 不能直接存储函数指针或类成员函数的地址。 - `void*` 常用于动态内存分配的上下文中,例如`malloc()` 和 `calloc()` 函数返回`void*` 类型。 **动态内存分配与 void 指针:** 在C语言中,`void...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar

    10.8 有关指针的数据类型和指针运算的小结 167 10.8.1 有关指针的数据类型的小结 167 10.8.2 指针运算的小结 167 10.8.3 void 指针类型 168 11 结构体与共用体 11.1 定义一个结构的一般形式 170 11.2 结构类型变量的...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar )

    10.8 有关指针的数据类型和指针运算的小结 167 10.8.1 有关指针的数据类型的小结 167 10.8.2 指针运算的小结 167 10.8.3 void 指针类型 168 11 结构体与共用体 11.1 定义一个结构的一般形式 170 11.2 结构类型变量的...

    c 语言 指针 专门讲解

    #### 小结 通过本文的讲解,希望读者能对C语言中的指针有一个更加深入的理解。虽然复杂的类型可能会让初学者感到困惑,但只要掌握了正确的解析方法,就能够轻松应对。此外,合理使用指针不仅能提高代码的效率,还能...

    VC++常用的共用函数100多页

    ◆将一个CWnd指针转换成一个控件ID(整数)注意用GetDlgItem()函数是从一个控件ID转换成一个CWnd的指针◆ 28 ◆如果在对话框中自定义一个消息的方法,假设对话框名为CXX◆ 28 ◆消息传递◆ 29 ◆在一个函数引用另外的...

    c入门基础 基础

    根据提供的标题、描述以及部分章节内容,我们可以整理出关于 C 语言的基础知识点概览。这份资料旨在为初学者提供一个全面的学习指南,帮助他们更好地理解 C 语言的基本概念和技术要点。 ### C 语言入门基础 #### 1...

    关于C语言程序设计小结

    从标题和内容中,我们可以总结出以下几个知识点: 1. 程序设计思想的重要性:在编写程序时,初学者往往容易过度关注语法规则,而忽略了程序的架构和算法设计。一个优秀的程序员不仅要在语法上精通,更要拥有扎实的...

Global site tag (gtag.js) - Google Analytics