当前位置:网站首页 > 技术博客 > 正文

json字符串(cJSON使用详细教程 | 一个轻量级C语言JSON解析器)



JSON 全称 JavaScript Object Notation,即 JS对象简谱,是一种轻量级的数据格式。

它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁、层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传输效率。

JSON对象是一个无序的"名称/值"键值对的集合:

  • 以"“开始,以”"结束,允许嵌套使用;
  • 每个名称和值成对出现,名称和值之间使用""分隔;
  • 键值对之间用""分隔
  • 在这些字符前后允许存在无意义的空白符;

对于键值,可以有如下值:

  • 一个新的json对象
  • 数组:使用"“和”"表示
  • 数字:直接表示,可以是整数,也可以是浮点数
  • 字符串:使用引号表示
  • 字面值:false、null、true中的一个(必须是小写)

示例如下:

 
  

cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。

cJSON项目托管在Github上,仓库地址如下:

https://github.com/DaveGamble/cJSON

使用Git命令将其拉取到本地:

 
  

从Github拉取cJSON源码后,文件非常多,但是其中cJSON的源码文件只有两个:

使用的时候,只需要将这两个文件复制到工程目录,然后包含头文件即可,如下:

 
  

cJSON的设计思想从其数据结构上就能反映出来。

cJSON使用cJSON结构体来表示一个JSON数据,定义在中,源码如下:

 
  

cJSON的设计很巧妙。

首先,它不是将一整段JSON数据抽象出来,而是将其中的一条JSON数据抽象出来,也就是一个键值对,用上面的结构体 来表示,其中用来存放值的成员列表如下:

  • :用于表示该键值对的名称;
  • :用于表示该键值对中值的类型;
  • :如果键值类型(type)是字符串,则将该指针指向键值;
  • :如果键值类型(type)是整数,则将该指针指向键值;
  • :如果键值类型(type)是浮点数,则将该指针指向键值;

其次,一段完整的JSON数据中由很多键值对组成,并且涉及到键值对的查找、删除、添加,所以使用链表来存储整段JSON数据,如上面的代码所示:

  • 指针:指向下一个键值对
  • 指针指向上一个键值对

最后,因为JSON数据支持嵌套,所以一个键值对的值会是一个新的JSON数据对象(一条新的链表),也有可能是一个数组,方便起见,在cJSON中,数组也表示为一个数组对象,用链表存储,所以:

在键值对结构体中,当该键值对的值是一个嵌套的JSON数据或者一个数组时,由指针指向该条新链表。

封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。

首先来讲述一下链表中的一些术语:

  • 头指针:指向链表头结点的指针;
  • 头结点:不存放有效数据,方便链表操作;
  • 首节点:第一个存放有效数据的节点;
  • 尾节点:最后一个存放有效数据的节点;

明白了这几个概念之后,我们开始讲述创建一段完整的JSON数据,即如何创建一条完整的链表。

  • ① 创建头指针:
 
  
  • ② 创建头结点,并将头指针指向头结点:
 
  
  • ③ 尽情的向链表中添加节点:
 
  

上面讲述,一段完整的JSON数据就是一条长长的链表,那么,如何打印出这段JSON数据呢?

cJSON提供了一个API,可以将整条链表中存放的JSON信息输出到一个字符串中:

 
  

使用的时候,只需要接收该函数返回的指针地址即可。

单纯的讲述方法还不够,下面用一个例子来说明,封装出开头给出的那段JSON数据:

 
  

编译运行:

 
  

实验结果如图:

实验结果

该JSON数据链表的关系如图:

JSON关系图

解析JSON数据的过程,其实就是剥离一个一个链表节点(键值对)的过程。

解析方法如下:

  • ① 创建链表头指针:
 
  
  • ② 解析整段JSON数据,并将链表头结点地址返回,赋值给头指针:

解析整段数据使用的API只有一个:

 
  
  • ③ 根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址
 
  
  • ④ 如果JSON数据的值是数组,使用下面的两个API提取数据:
 
  

下面用一个例子来说明如何解析出开头给出的那段JSON数据:

 
  

编译:

 
  

运行结果如图:

运行结果

在本示例中,因为我提前知道数据的类型,比如字符型或者浮点型,所以我直接使用指针指向对应的数据域提取,在实际使用时,如果提前不确定数据类型,应该先判断type的值,确定数据类型,再从对应的数据域中提取数据

cJSON的所有操作都是基于链表的,所以cJSON在使用过程中大量的使用从堆中分配动态内存的,所以在使用完之后,应当及时调用下面的函数,清空cJSON指针所指向的内存,该函数也可用于删除某一条数据:

 
  

注意:该函数删除一条JSON数据时,如果有嵌套,会连带删除。

cJSON在支持自定义malloc函数和free函数,方法如下:

  • ① 使用来连接自定义malloc函数和free函数:
 
  
  • ② 初始化钩子cJSON_Hooks
 
  

                            

版权声明


相关文章:

  • 安全测试包含哪些内容2025-10-03 11:30:01
  • 接口自动化测试工具2025-10-03 11:30:01
  • linux 添加用户组新成员2025-10-03 11:30:01
  • 去耦和旁路电容的区别2025-10-03 11:30:01
  • java中引用类型是什么2025-10-03 11:30:01
  • srand和rand函数2025-10-03 11:30:01
  • mysql索引的使用和原理2025-10-03 11:30:01
  • flowable工作流收费吗2025-10-03 11:30:01
  • sql编写技巧2025-10-03 11:30:01
  • javagui工具2025-10-03 11:30:01