千万不要点开,Cjson入门快速使用看这篇就够了(CJSON入门操作以及问题讲解,CJSON对象删除出错)

一、前言

在很多通讯领域,我们常用到json的通讯格式,然而在嵌入式开发当中我们在使用json格式的协议时,难免会使用到这一个cjson函数库。本文就是给一些CJSON快速入门的操作。
这一点一定要看啊,我们要首先明确我们的目的。加入我们不知道使用CJSON和JSON为了干什么,那么看这篇文章将将会十分困难。其实使用CJSON和JSON其实只是为了干一件事:那就是解析收到的数据和发送对方能够解析的数据,那么cjson就是我们用的工具,我们用这个工具来编辑和解析JSON格式的数据,知道这一点,下面的文章就很容易看懂了。

二、json讲解

我们要知道,这个东西只是一个数据交换格式,什么叫数据交换格式,就像一个电话簿一样,名字对应电话号码,好一点的可能还带着地址。但是就像我们打魂斗罗按baba上上下下左左右右可以挑出30条命一样,搞清楚是上上下下而不是下下上上对于我们打游戏没有用?我们只需要按出来就可以啦。同理,json也是这样,我们只需要是这个格式就可以啦。

2.1、json和cjson是什么

json百度百科:有时间可以看一下==json百度百科==
但是,其实也不用看,因为我们是要使用库的,已经有cjson库来帮我们处理数据,我们只需要将json数据当作一个黑盒子,然后使用cjson来添加、删除、解析和构造数据就可以啦。

2.2、json概述

JSON里面主要是按照键值对的方式来存储数据的,所以我们提取数据就按照键的名字直接提取,存入数据,就将想要存入的数据取一个名字(即字符串)然后放到JSON结构体里面就可以了。
这是一个典型的JSON结构体,我们可以看到,键名为“name”的值对应为"John Doe",而键名“address”的值则是一个用大括号括起来的数据,这是区别于c语言的一种数据类型,我们把它叫做对象。
给出一个json例子,让大家有个体会:

{
"name": "John Doe", 
"age": 18, 
"address": {"country" : "china", "zip-code": "10000"}
}

2.3、json数据类型分类

作为熟悉C语言的大家,json其实只有两种区别于c语言的数据类型,我们看看这两种就可以啦。
1、对象:json数据的主要单位,也就是一个用大括号括起来的数据,他包含的所有数据是各种键值对,键值对之间用逗号加以区分。注意我们用cjson操作时,也主要是对对象的操作
2、键值对:json数据的基本单位,键值对的键名必须是一个字符串,而键值则可以是int,double,string,array等各种数据。中间用冒号链接

/***对象*/
//对象:用大括号括起来的数据:
{“name”:"hello"}

/**键值对*/
//数组:用中括号括起来的数据:
{"array":[1,2,3]}
//字符串键值对
"key":"value"
//number键值对
"number":2

三、CJSON讲解

3.1、cjson安装:

这个是cjson的官方库,直接点击进,下载,解压缩
然后我们,可以看到很多文件,但是,我们不需要这么多,使用cjson只需要两个文件:

CJOSN.h
CJSON.c

把这两个文件添加进入自己的工程就可以啦,当然如果新手不知道怎么开始,将test.c这个文件也加进去,然后试验一下也是可以的。

3.2、cjson文件说明

我们只需要熟悉CJSON.h这个文件就可以,因为我们只需要调用这个.h里面的文件而已:

3.3、cjson函数讲解

3.3.1、json数据如何传输

我们现在已经知道json数据是一个结构体,那么如何传输结构体了?要知道,数据在网络或者无线通信中传输的都是二进制数据,我们如果要按照特殊的通讯协议来传输的话,我们就要按照这个协议解析。所以按照这个规则,我们直接双方都采用json格式的数据,然后采用相同的方式解析就可以啦。
这种方式大家都非常熟悉,我们直接将JSON数据转换成为字符串,然后传输,之后将字符串解析成JSON数据就可以啦

3.3.2、CJSON结构体:

/* The cJSON structure: */
typedef struct cJSON
{
//这些不用管
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;

//这些都要知道
    //该json对象的类型,可以是字符串,int,double....
    int type;
    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    //如果类型是字符串,那么键值的字符串的值存在这里
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
     //如果类型是int,那么值存在这里
    int valueint;
    /* The item's number, if type==cJSON_Number */
    //如果类型是double,那么值存在这里
    double valuedouble;
    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
  	//存放名字的地方
    char *string;
} cJSON;

3.3.3、CJSON解析和构造函数:

下面都是将JSON结构体转换为字符串数据的操作函数

//将CJSON数据转换为字符串(保留原来的格式:例如会保留空格和回车)
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
//将CJSON数据转换为字符串(删除所有格式,只保留文本)
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
//将CJSON数据转换为字符串(并且存储到一个buffer里面)
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
//将CJSON数据转换为字符串(储存到一个动态申请的空间中)
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);

下面都是将JSON字符串转换为JSON结构体的操作:

//将json字符串转换为结构体,并且将其赋给一个指针
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
//将json字符串转换为结构体,并且将其赋给一个指针,这个函数会提供一些操作选项来帮助开发者使用
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);

3.3.4、CJSON创建键值对的两种方法:

一、将CJSON对象加入:
这个方法关键在于,首先需要先创建一个对象然后再将他加入进去。

//常用
//将对象加入数组或者对象
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);

//按照需求
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
 * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
 * writing to `item->string` */
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
//这两个就是加入的时候不会覆盖原来的CJSON结构体
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);

二、直接将键值和名字填入构建为一个键值对
不需要构建新的结构体。

/* Helper functions for creating and adding items to an object at the same time.
 * They return the added item or NULL on failure. */
 //我们想添加什么数据就可以直接添加,不用另外构建CJSON结构体
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);

3.3.5、CJSON获取键值对的方法:

从json结构体里面提取我们想要的键值:

/* Returns the number of items in an array (or object). */
//获取数组大小
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
//获取数组里面的某一个值
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
//这个函数将某一个键值对,提取出来放到一个结构体中
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);

//以下都不常用
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);

/* Check if the item is a string and return its valuestring */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);

四、CJOSN操作实例

我们使用CJSON其实只有两种操作:
1、构建JSON结构,然后转换为字符串来发送或者做其他的。
2、解析别人发来的JSON字符串,然后转换为结构体,然后读取里面的数据,找到对应的值

4.1、创建自己的:创建,添加,变换

	/***************************创建*********************************/
	//构建最后用于存放JSON数据的字符串
	char * json_buffer = { 0 };
	//首先构造一个根对象指针:
	cJSON* root = NULL;
	//创建String对象指针:
	cJSON* string = NULL;
	//创建int对象指针:
	cJSON* int_number = NULL;
	//创建数组指针:
	cJSON* array = NULL;
	int the_array[3] = { 1,2,3 };
	//创建一个根对象,给root
	root = cJSON_CreateObject();
	//创建一个字符串对象,给string
	string = cJSON_CreateString("hello world");
	//创建一个int对象,给int_number
	int_number = cJSON_CreateNumber(10);
	//创建一个array对象,给array 
	array = cJSON_CreateIntArray(the_array, 3);
	/***************************添加*********************************/
	//将字符串string加入根对象,成为一个键值对:

	//方法一:添加对象
	cJSON_AddItemToObject(root,"string",string);
	//方法二:直接添加
	cJSON_AddStringToObject(root,"string_1","bye world");

		//添加剩下的
	cJSON_AddItemToObject(root,"int_number",int_number);
	cJSON_AddItemToObject(root,"array ",array);

	/***************************变换*********************************/
	json_buffer = cJSON_PrintUnformatted(root);
	printf("json_buffer is %s\n", json_buffer);

结果如下

json_buffer is {"string":"hello world","string_1":"bye world","int_number":10,"array ":[1,2,3]}

4.2、解析收到的:解析,获取,打印

	//JSON字符串
	const char* json_str = "{\"name\":\"json_test\",\"num\":\"520\",\"arry\":[1,2,3]}";
	cJSON* temp = 0;
	/****************************解析***********************************/
	cJSON* json = NULL;
	cJSON* name = NULL;
	cJSON* num = NULL;
	cJSON* arry = NULL;

	/****************************获取***********************************/
	//将字符串解析为一个结构体
	json = cJSON_Parse(json_str);
	name = cJSON_GetObjectItem(json,"name");
	num = cJSON_GetObjectItem(json, "num");
	arry = cJSON_GetObjectItem(json, "arry");

	printf("name is %s\n", name->valuestring);
	printf("num is %d\n", num->valueint);
	temp = cJSON_GetArrayItem(arry, 1);
	printf("arry[0] is %d\n", temp->valueint);

结果如下:

name is json_test
num is 0
arry[0] is 2

五、工程实例

下面就是各位最喜欢的环节:

/** CJSON使用例子
*   CJSON template
*	Author:jiang shan  (github: jianggogogo)
*	date:	2019.12.25
*	Note:   This file is open to learning.
*	
* licence:	
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "stdio.h"
#include "cJSON.h"
#include "stdlib.h"

//创建一个JSON数据并且转换为字符串
void Create_print()
{
	/***************************创建*********************************/
	//构建最后用于存放JSON数据的字符串
	char* json_buffer = { 0 };
	//首先构造一个根对象指针:
	cJSON* root = NULL;
	//创建String对象指针:
	cJSON* string = NULL;
	//创建int对象指针:
	cJSON* int_number = NULL;
	//创建数组指针:
	cJSON* array = NULL;
	int the_array[3] = { 1,2,3 };
	//创建一个根对象,给root
	root = cJSON_CreateObject();
	//创建一个字符串对象,给string
	string = cJSON_CreateString("hello world");
	//创建一个int对象,给int_number
	int_number = cJSON_CreateNumber(10);
	//创建一个array对象,给array 
	array = cJSON_CreateIntArray(the_array, 3);
	/***************************添加*********************************/
	//将字符串string加入根对象,成为一个键值对:

		//方法一:添加对象
	cJSON_AddItemToObject(root, "string", string);
	//方法二:直接添加
	cJSON_AddStringToObject(root, "string_1", "bye world");

	//添加剩下的
	cJSON_AddItemToObject(root, "int_number", int_number);
	cJSON_AddItemToObject(root, "array ", array);

	/***************************变换*********************************/
	json_buffer = cJSON_PrintUnformatted(root);
	printf("json_buffer is %s\n", json_buffer);

	cJSON_Delete(root);
}


//解析字符串并且读取里面的数据
void prase_print()
{
	//JSON字符串
	const char* json_str = "{\"name\":\"json_test\",\"num\":\"520\",\"arry\":[1,2,3]}";
	cJSON* temp = 0;
	/****************************解析***********************************/
	cJSON* json = NULL;
	cJSON* name = NULL;
	cJSON* num = NULL;
	cJSON* arry = NULL;

	/****************************获取***********************************/
	//将字符串解析为一个结构体
	json = cJSON_Parse(json_str);
	name = cJSON_GetObjectItem(json,"name");
	num = cJSON_GetObjectItem(json, "num");
	arry = cJSON_GetObjectItem(json, "arry");

	printf("name is %s\n", name->valuestring);
	printf("num is %d\n", num->valueint);
	temp = cJSON_GetArrayItem(arry, 1);
	printf("arry[0] is %d\n", temp->valueint);

	cJSON_Delete(json);
	free(json);
}
int main()
{
	printf("hello world\n");
	Create_print();
	return 0;
}


六、 问题和需要注意的地方

1.CJSON需要较多的堆栈空间,CJSON官方说:跑完他的test大概需要3k的空间:
所以在,单片机或者资源较少的地方使用CJSON时,注意空间分配
2.注意,每一个CJOSN结构体都是一个比较大的空间,我么使用完之后要及时delete,但是,一旦子对象被添加到父对象之后,删除父对象就会删除子对象,所以一旦我们删除了父对象再删除子对象会出现问题。
3.注意,cJSON_PrintUnformatted这种转换函数,会自动为指针申请空间,我们使用完之后一定要及时释放空间:
free。

七、结束语

本文是一篇CJSON的基础操作篇,但是作为一个新手,依然存在很多地方有问题,欢迎大家留言交流,指出错误,互相学习。

  • 24
    点赞
  • 125
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值