百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

「C语言」函数指针与指针函数(c指针函数和函数指针)

citgpt 2024-07-10 14:45 13 浏览 0 评论

最近在阅读cJSON的源代码,在看见如下代码是产生了,深深地疑惑,这个是什么声明?用来干嘛的?

void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);

在读懂这两句代码之前我们先来了解熟悉两个概念——函数指针和指针函数,想必和我一样处于C语言入门阶段的小伙伴对这两个概念并不是十分熟悉,接下来我们一起学习一下。

「C语言」函数指针与指针函数(c指针函数和函数指针)

函数指针

函数指针首先它是一个指针变量,其次它是指向函数的,正如每个变量都有地址,我们知道每一个函数也是都有一个入口地址的,函数指针指向的就是函数的入口地址。

我们来看一下函数指针的声明:

/*声明一个函数指针*/
//正确的写法  这是一个函数指针
int (*a)(void *);//a是一个函数指针,它所指向的函数有一个void*类型的参数,返回类型是int

//错误的写法  这是一个指针函数
int *b(void *);//b是一个函数,这个函数带有一个void*类型的参数,返回类型是int

函数指针是一个指针,它需要指向一个函数的地址,对它的赋值方法有两种:

//test是函数指针 
int (*test)(int x, int y)
    
//function是一个函数    
test = &Function;
test = function;

这两种赋值方法都是等价的,与数组一样,函数名代表了一个函数的入口地址。

对于函数指针的调用也有两种方法:

test = (*test)();
test = test();

这两种方法也是相同的,当然为了使得代码更清楚可以使用带*运算符的,表明这是对指针的解引用。

下面我们通过一个简单的代码来看看如何使用函数指针:

#include <stdio.h>

int function();

int main(void)
{
    //函数指针赋值 
    //两种写法都可以看个人喜好
    //int (*test)(void) = function;  
    int (*test)() = &function;
    
    //函数指针调用
    //同样的两种方式
    //test();
    (*test)();

    return 0;
}

int function()
{
    printf("Here!\n");

}

//输出结果:
Here!

指针函数

指针函数与函数指针相比会更好理解,同时它也更常见一些,它的本质就是一个函数,其返回值的类型为指针。下面我们看一下代码:

#include <stdio.h>

int *test();
int main(void)
{
    int *y;
    y = test();
    
    return 0;
}

int *test()
{
 	printf("Here!\n");
}

//输出结果:
Here!

实际案例

下面开始分析有关代码,首先是cJSON_Hooks结构体

typedef struct cJSON_Hooks {
      void *(*malloc_fn)(size_t sz);
      void (*free_fn)(void *ptr);
} cJSON_Hooks;

这一部分一开始也是困扰了很久,对于刚开始入门C语言的小伙伴来说,这两句声明到底是什么意思,为什么要这样做,想必会是一头雾水。首先根据上文介绍的我们可以清楚知道:

  • malloc_fn是一个函数指针,它所指向的函数具有一个size_t类型的参数,返回void类型的指针。
  • free_fn是一个函数指针,它所指向的函数具有一个void*类型的指针,无返回值。

那么为什么是这样声明呢,我们可以来看一下头文件<stdlib.h>中的malloc和free的函数原型:

void* malloc(size_t size);
void free(void* p);
  • 这里我们看到malloc的参数是size_t类型,返回的是一个void*类型的指针。
  • free的参数是void*的指针,无返回值,void*类型的指针是为了能够释放各种类型的参数的内存。

于是通过对比我们就可以知道,cJSON_Hooks结构体实际上做的事情就是声明用户自定义的malloc和free函数指针。

cJSON.c中:

static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;
  • 这里声明了两个静态函数指针(cJSON_malloc和cJSON_free),并且分别将它们各自指向malloc函数和free函数。
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
    if (!hooks) { /* Reset hooks */
        cJSON_malloc = malloc;
        cJSON_free = free;
        return;
    }

	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free;
}
  • 如果hooks未声明,则对两个函数指针进行重置。
  • 如果hooks以声明,则判断hooks的malloc_fn和free_fn是否存在,如果存在则让分别cJSON_malloc和cJSON_free指向它,如果不存在,则使用默认的malloc和free函数。
  • 以上代码主要作用其实是提供一个接口让用户定义自己的内存管理函数,如果没有定义,则使用默认的函数。

相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: