IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> cJSON学习 -> 正文阅读

[C++知识库]cJSON学习

最近在做数据上三大云平台的项目,用的是MQTT协议,阿里云、腾讯云、华为云那边解析数据用的是json格式,下发的也是json格式,所以特地学一下json的封装和解析过程,以及其API的使用,作了以下笔记。

一、概述

cJSON是一个仅有一个.h文件,一个.c文件组成的JSON解析器,它是由纯C(ANSI C89)实现的,跨平台性较好。cJSON是采用链表存储的。

cJSON库在使用的时候只需要如下两步:将cJSON.c(或者库文件)和cJSON.h添加到项目中即可;如果在命令行中进行链接还需要加上-lm表示链接math库。

二、下载安装

git clone https://github.com/DaveGamble/cJSON.git

使用的时候找到cJSON.c和cJSON.h 文件将其添加到项目工程中,然后包含头文件cJSON.h即可。

二、基本语法

(1)JSON表示方法

以"{“开始,以”}"结束
数据在键/值对中;
数据由逗号分开;
花括号保存对象;
方括号保存数组;

(2)JSON的三种语法

键/值对key:value,中间用冒号分开,键要加双引号,但值不一定,例如"name":“zcx”。
对象放在花括号中,可用包含多个键值对,例如{“name”:“zcx”,“address”:“深圳”}。
数组JSON数组放在方括号中,数组成员可以是对象、值、也可以是数组,例如[“小明”,“二狗”,“翠花”,{“adress”:“北京”}]。

(3)JSON的值

可以是:数字(整数或浮点数)、字符串(在双引号中)、布尔值(true或false)、数组(在方括号中)、一个json对象(在花括号中)、null。

(4)JSON两种结构

**对象:**对象在js中表示为“{}”括起来的内容,数据结构为{key:value,key:value,…}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值.

**数组:**数组在js中是中括号“[]”括起来的内容,数据结构为[“java”,“javascript”,“vb”,…],取值方式和所有语言中一样,使用索引获取。

经过对象、数组2种结构就可以组合成复杂的数据结构了。

三、cJSON数据结构

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

/* The cJSON structure: */
typedef struct cJSON
{
	//next指针:指向下一个键值对
    struct cJSON *next;
    
    //prev指针指向上一个键值对
    struct cJSON *prev;
    
    //在键值对结构体中,当该键值对的值是一个嵌套的JSON数据或者一个数组时,由child指针指向该条新链表。
    struct cJSON *child;
    
    //type:用于表示该键值对中值的类型;
    int type;

	//valuestring:如果键值类型(type)是字符串,则将该指针指向键值;
    char *valuestring;

	//valueint:如果键值类型(type)是整数,则将该指针指向键值;
    int valueint;

	//valuedouble:如果键值类型(type)是浮点数,则将该指针指向键值;
    double valuedouble;

	//String:用于表示该键值对的名称;
    char *string;
} cJSON;

cJSON将其中一条json数据(键值对)抽象出来,用上面的结构体表示。但是往往一段完整的json数据不只一个数据,而且还需要进行增删改查等操作,所以其使用了链表的形式进行存放json数据,json中,数组也表示一个对象,用链表存储。

四、cJSON封装过程

封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。熟悉一下单链表,以及一些术语:

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

在这里插入图片描述

不过cJSON用的可不是单链表存储数据,而是双亲孩子兄弟表示法,因为其一个节点数据结构里面包含了三个指针,分别是next、prev、child。

明白了这几个概念,我们就可以知道一个cJSON数据是如何创建的。

(1)创建头指针:

cJSON*	cjson_test = NULL;

(2)创建头节点,并将头指针指向头节点:

cjson_test = cJSON_CreateObject();

(3)向链表添加节点:


//创建一个数组对象,返回一个cJSON结构体类型的指针。
cJSON *cJSON_CreateArray();

cJSON_AddNullToObject(cJSON * const object, const char * const name);

//向对象添加true布尔值
cJSON_AddTrueToObject(cJSON * const object, const char * const name);

//向对象添加false布尔值
cJSON_AddFalseToObject(cJSON * const object, const char * const name);

//向对象添加布尔值
cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);

//向对象添加数
cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);

//向对象添加字符串
cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);

cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);

cJSON_AddObjectToObject(cJSON * const object, const char * const name);

//向对象添加一个数组对象
cJSON_AddArrayToObject(cJSON * const object, const char * const name);

//创建一个字符串对象,传入一个char *类型的字符串,返回一个cJSON结构体类型的指针。
cJSON *cJSON_CreateString(const char *string);

//向数组对象中添加一个键值,传入参数array为cJSON *结构体类型的指针,为数组对象,item为添加如数字对象中的对象指针。
void cJSON_AddItemToArray(cJSON *array, cJSON *item);

//向json对象中添加一对键值,object为json对象,string为加入一对键值中的name,item为加入一对键值中的value。
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);

//释放一个cJSON对象占用的内存空间。
void cJSON_Delete(cJSON *c)

(4)输出cJSON数据

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

(char *) cJSON_Print(const cJSON *item);

使用的时候,只需要定义一个指针,然后让这个指针指向这个函数返回的地址即可。

(5)使用实例

//main.h
#include <stdio.h>
#include "cJSON.h"

int main()
{
    cJSON *temp_item = cJSON_CreateObject();
    cJSON_AddNumberToObject(temp_item, "Temperature", 33.21);
    cJSON *ack_item = cJSON_CreateObject();
    cJSON_AddNumberToObject(ack_item, "ack", 0);

    cJSON*root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "method","thing.service.property.post");
    cJSON_AddStringToObject(root, "id", "device");
    cJSON_AddItemToObject(root, "sys",ack_item);
    cJSON_AddItemToObject(root, "params",temp_item);
    cJSON_AddStringToObject(root, "version","1.0.0");

    char *str = cJSON_Print(root);
    printf("%s\n", str);

    return 0;
}

运行结果:
在这里插入图片描述

五、cJSON数据解析

解析JSON数据的过程,其实就是将整个cJSON数据包剥离一个一个链表节点(键值对)的过程。
四个常用的cJSON解析函数:

(1)cJSON_Parse

cJSON *cJSON_Parse(const char *value);

**作用:**将一个JSON数据包,按照cJSON结构体的结构序列化整个数据包,并在堆中开辟一块内存存储cJSON结构体

**返回值:**成功返回一个指向内存块中的cJSON的指针,失败返回NULL

(2)cJSON_GetObjectItem

cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);

**作用:**获取JSON字符串字段值

**返回值:**成功返回一个指向cJSON类型的结构体指针,失败返回NULL

(3)cJSON_Delete

void   cJSON_Delete(cJSON *c);

作用:释放位于堆中cJSON结构体内存
返回值:无

#include <stdio.h>
#include "cJSON.h"

int main()
{
    char * str = "{\
        \"method\":       \"thing.service.property.post\",\
        \"id\":   \"device\",\
        \"sys\":  {\
                \"ack\":  0\
        },\
        \"params\":       {\
                \"Temperature\":  33.21,\
                \"datime\":\"2022.5.4\"\
        },\
        \"version\":      \"1.0.0\"\
    }";

    cJSON *obj = cJSON_Parse(str);//将一个json格式字符串按照json格式结构序列化,存在链表里面
    cJSON *version_obj = cJSON_GetObjectItem(obj, "version");
    printf("version:%s\n", version_obj->valuestring);

    cJSON *params_obj = cJSON_GetObjectItem(obj, "params");
    printf("Temperature:%f\n", params_obj->child->valuedouble);//需要注意的是params 的值是一个对象,所以params_obj用了一个child指针指向了一个链表,该节点存放了所以如果要拿Temperature的值,就需要用child指针访问该对象
	printf("datime:%s\n", params_obj->child->next->valuestring);//如果要取data的值,就需要用next指向该链表的下一个节点。
    return 0;
}

运行结果:
在这里插入图片描述

注意事项

在进行json数据解析时,如果不知道你取的该节点的值是什么类型时,可以用该节点中type来判断,然后再用valuedouble,valuestring或valueint获取该节点的值。

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

(void) cJSON_Delete(cJSON *item);
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 10:59:30  更:2022-05-05 11:01:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:58:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码