繁体   English   中英

试图理解C中的函数指针

[英]Trying to understand function pointers in C

我正在尝试理解函数指针并且正在捣乱。 我已经看到了K&R中的排序示例以及其他一些类似的示例。 我的主要问题是计算机实际上在做什么。 我创建了一个非常简单的程序来尝试查看基础知识。 请参阅以下内容:

#include <stdio.h>

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23,(int(*)(void*,void*))(i==1?func0:func1));//34 and 23 are arbitrary inputs



}

void myfunc(int x, int y, int(*somefunc)(void *, void *)){

    int *xx =&x;
    int *yy=&y;

    printf("%i",somefunc(xx,yy));


}

int func0(int *x, int *y){

    return (*x)*(*y);

}

int func1(int *x, int *y){

    return *x+*y;
} 

程序要么根据某个变量相乘或相加两个数字(i在主函数中 - 应该是主要的参数)。 fun0乘以两个整数,func1将它们相加。

我知道这个例子很简单,但是如何传递一个函数指针,可以在函数myfunc中放入一个条件? 即在myfunc中有以下内容:

if(i == 1)printf("%i",func0(xx,yy));

else printf("%i",func1(xx,yy));

如果我这样做,结果将是相同的但不使用函数指针。

您对函数指针如何工作的理解很好。 您没有看到的是软件系统如何从使用函数指针中受益。 在使用不了解其他组件的组件时,它们变得很重要。

qsort()就是一个很好的例子。 qsort将允许您对任何数组进行排序,并且实际上并不知道组成数组的内容。 因此,如果你有一个结构数组,或更可能指向结构的指针,你将不得不提供一个可以比较结构的函数。

struct foo {
  char * name;
  int magnitude;
  int something;
};

int cmp_foo(const void *_p1, const void *_p2)
{
  p1 = (struct foo*)_p1;
  p2 = (struct foo*)_p2;

  return p1->magnitude - p2->magnitude;
}

struct foo ** foos;
// init 10 foo structures...

qsort(foos, 10, sizeof(foo *), cmp_foo);

然后将根据幅度字段对foos数组进行排序。

如您所见,这允许您对任何类型使用qsort - 您只需提供比较功能。

函数指针的另一个常见用法是回调,例如在GUI编程中。 如果希望在单击按钮时调用函数,则在设置按钮时将提供指向GUI库的函数指针。

如何将函数指针传递给函数myfunc中的条件

有时候不可能在那里设置一个条件:例如,如果你正在编写一个排序算法,并且你不知道你提前排序的是什么,你根本就不能提出条件; 函数指针允许您将一段计算“插入”主算法,而不会跳过箍。

至于机制如何工作,这个想法很简单:所有编译的代码都位于程序存储器中,CPU从某个地址开始执行它。 有指令使CPU在地址之间跳转,记住当前地址和跳转,调用先前跳转的地址并返回到它,等等。 当你调用一个函数时,CPU需要知道的一件事就是它在程序存储器中的地址。 函数的名称代表该地址。 您可以直接提供该地址,也可以将其分配给指针以进行间接访问。 这类似于通过指针访问值,除非在这种情况下您间接访问代码,而不是访问数据。

首先,您永远不能将函数指针强制转换为不同类型的函数指针。 这是C中的未定义行为(C11 6.5.2.2)。

处理函数指针时,一个非常重要的建议是始终使用typedef。

因此,您的代码可以/应该重写为:

typedef int (*func_t)(int*, int*);

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23, (i==1?func0:func1)); //34 and 23 are arbitrary inputs
}

void myfunc(int x, int y, func_t func){

要回答这个问题,当您不知道函数的性质时,您希望使用函数指针作为参数。 这在编写通用算法时很常见。

以标准C函数bsearch()为例:

void *bsearch (const void *key, 
               const void *base,
               size_t nmemb, 
               size_t size,
               int (*compar)(const void *, const void *));
              );

这是一种通用的二进制搜索算法,搜索任何形式的一维arrray,包含未知类型的数据,例如用户定义的类型。 这里,“比较”函数比较两个未知性质的对象是否相等,返回一个数字来表示这一点。

“如果分别考虑密钥对象,该函数应返回小于,等于或大于零的整数,以小于,匹​​配或大于数组元素。”

该函数由调用者编写,调用者知道数据的性质。 在计算机科学中,这被称为“功能对象”或有时称为“仿函数”。 它在面向对象的设计中经常遇到。

一个例子(伪代码):

typedef struct  // some user-defined type
{
  int* ptr;
  int  x;
  int  y;
} Something_t;

int compare_Something_t (const void* p1, const void* p2)
{
  const Something_t* s1 = (const Something_t*)p1;
  const Something_t* s2 = (const Something_t*)p2;

  return s1->y - s2->y;  // some user-defined comparison relevant to the object
}

...

Something_t  search_key = { ... };
Something_t  array[] = { ... };
Something_t* result; 

result = bsearch(&search_key,
                 array,
                 sizeof(array) / sizeof(Something_t), // number of objects
                 sizeof(Something_t), // size of one object
                 compare_Something_t // function object
                );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM