cJSON使用
- 1.简介
- 2.cJSON介绍
- 3.常用cJSON函数
-
- 1.解析类(JSON字符串->cJSON对象)
- [2. 打印类(cJSON 对象 → JSON 字符串)](#2. 打印类(cJSON 对象 → JSON 字符串))
- [3.创建类(构建 JSON 对象 / 数组)](#3.创建类(构建 JSON 对象 / 数组))
- [4.获取类(从 JSON 中取值)](#4.获取类(从 JSON 中取值))
- [5. 修改 / 替换类](#5. 修改 / 替换类)
- [6. 释放类(内存管理,必用!)](#6. 释放类(内存管理,必用!))
- 7.类型判断宏(辅助,避免出错)
- [4.综合示例(解析 + 创建 + 取值 + 释放)](#4.综合示例(解析 + 创建 + 取值 + 释放))
1.简介
json是一个轻量级的数据存储交换语言,其是通过键值对的形式存储的,例如:{ "key" : "value" }
键需要使用双括号括起来,值如果是字符串也需要使用双引号括起来。
2.cJSON介绍
cJSON 是轻量级的 C 语言 JSON 解析 / 构建库,核心围绕 cJSON 结构体展开
1.格式
cpp
{
"name": "小明",
"age": 53,
"interest": {
"basketball": "篮球",
"badminton": "羽毛球"
},
"color": [
"black",
"white"
],
"like": [
{
"game": "马里奥",
"price": 47.8
},
{
"game": "魂斗罗",
"price": 88
}
],
"vip": true,
"address": null
}

2.结构体
cpp
typedef struct cJSON {
struct cJSON *next,*prev; /* next是获取下一个元素数据,prev是获取前一个元素数据 */
struct cJSON *child; /* 获取第一个元素数据,当需要获取下一个时,就得使用next了. */
int type; /* 当前的json类型对象、数组、字符串、数字、null、true、false等 */
char *valuestring; /* 字符串值, if type==cJSON_String */
int valueint; /* 整形类型值, if type==cJSON_Number */
double valuedouble; /* 浮点数类型值, if type==cJSON_Number */
char *string; /* 这个是键 */
} cJSON;
type:
type类型通过下面定义的宏进行判断:
cpp
#define cJSON_False 0 // true
#define cJSON_True 1 // false
#define cJSON_NULL 2 // NULL
#define cJSON_Number 3 // 数字
#define cJSON_String 4 // 字符串
#define cJSON_Array 5 // 数组
#define cJSON_Object 6 // 对象
3.常用cJSON函数
1.解析类(JSON字符串->cJSON对象)
将JSON格式字符串解析为cJSON(根节点),是读取JSON的入口。
解析 JSON 字符串为 cJSON 根节点
c
cJSON *cJSON_Parse(const char *value);
- 参数:value = 待解析的 JSON 字符串
- 返回:成功返回根节点指针,失败返回 NULL
获取解析失败的位置
c
const char *cJSON_GetErrorPtr(void);
- 解析失败时调用,返回错误位置的字符串指针
示例:
c
const char *json_str = "{\"name\":\"Tom\",\"age\":20}";
cJSON *root = cJSON_Parse(json_str);
if (root == NULL) {
printf("解析失败:%s\n", cJSON_GetErrorPtr()); // 打印错误位置
return -1;
}
2. 打印类(cJSON 对象 → JSON 字符串)
将 cJSON 结构体转换为字符串,用于输出 / 存储 JSON。
转换为格式化 JSON 字符串(带缩进、换行,易读)
c
char *cJSON_Print(const cJSON *item);
- 返回的字符串需手动 free() 释放
换为紧凑格式 JSON 字符串(无空格 / 换行)
c
char *cJSON_PrintUnformatted(const cJSON *item);
- 同上,适合网络传输 / 存储
示例:
c
char *fmt_str = cJSON_Print(root); // 格式化输出
char *compact_str = cJSON_PrintUnformatted(root); // 紧凑输出
printf("格式化JSON:\n%s\n", fmt_str);
free(fmt_str); // 必须释放
free(compact_str);
3.创建类(构建 JSON 对象 / 数组)
手动构建 JSON 节点(对象、数组、字符串、数字等),是生成 JSON 的核心。
创建空 JSON 对象
c
cJSON *cJSON_CreateObject(void);
//示例
cJSON *obj = cJSON_CreateObject();
创建空 JSON 数组
c
cJSON *cJSON_CreateArray(void);
//示例
cJSON *arr = cJSON_CreateArray();
**创建字符串节点 **
c
cJSON *cJSON_CreateString(const char *s);
//示例
cJSON *str_node = cJSON_CreateString("Tom");
创建数字节点(整数 / 浮点通用)
c
cJSON *cJSON_CreateNumber(double num);
//示例
cJSON *num_node = cJSON_CreateNumber(20.5);
**创建布尔节点 **
c
cJSON *cJSON_CreateBool(cJSON_bool b);
//示例
cJSON *bool_node = cJSON_CreateBool(1); // true
**向对象添加键值对 **
c
cJSON_AddItemToObject(cJSON *obj, const char *key, cJSON *item);
//示例
cJSON_AddItemToObject(obj, "name", str_node);
**向数组添加节点 **
c
cJSON_AddItemToArray(cJSON *arr, cJSON *item);
//示例
cJSON_AddItemToArray(arr, num_node);
**一键添加键值对(无需手动创建节点) **
c
cJSON_AddStringToObject(obj, "name", "Tom");
cJSON_AddNumberToObject(obj, "age", 20);
cJSON_AddBoolToObject(obj, "is_student", 1);
示例(构建 JSON)
c
// 创建对象
cJSON *new_obj = cJSON_CreateObject();
// 一键添加键值对(简化宏)
cJSON_AddStringToObject(new_obj, "name", "Jerry");
cJSON_AddNumberToObject(new_obj, "age", 18);
// 创建数组并添加到对象
cJSON *hobbies = cJSON_CreateArray();
cJSON_AddItemToArray(hobbies, cJSON_CreateString("reading"));
cJSON_AddItemToObject(new_obj, "hobbies", hobbies);
4.获取类(从 JSON 中取值)
从解析后的 cJSON 对象 / 数组中提取指定值,需先判断节点类型避免出错。
大小写敏感获取对象的 key 节点(推荐)
c
cJSON *cJSON_GetObjectItemCaseSensitive(const cJSON *obj, const char *key);
//示例
cJSON *name = cJSON_GetObjectItemCaseSensitive(root, "name");
大小写不敏感获取 key 节点(不推荐)
c
cJSON *cJSON_GetObjectItem(const cJSON *obj, const char *key);
//示例
cJSON *name = cJSON_GetObjectItemCaseSensitive(root, "name");
获取数组长度
c
int cJSON_GetArraySize(const cJSON *arr);
//示例
int size = cJSON_GetArraySize(scores_arr);
获取数组指定索引的节点(idx 从 0 开始)
c
cJSON *cJSON_GetArrayItem(const cJSON *arr, int idx);
//示例
cJSON *score = cJSON_GetArrayItem(scores_arr, 0);
示例
c
// 1. 提取字符串(先判断是否为字符串类型)
cJSON *name = cJSON_GetObjectItemCaseSensitive(root, "name");
if (cJSON_IsString(name) && name->valuestring) {
printf("name: %s\n", name->valuestring);
}
// 2. 提取整数/浮点(先判断是否为数字类型)
cJSON *age = cJSON_GetObjectItemCaseSensitive(root, "age");
if (cJSON_IsNumber(age)) {
printf("age(int): %d\n", age->valueint); // 整数
printf("age(double): %.1f\n", age->valuedouble); // 浮点
}
// 3. 提取布尔(判断布尔类型)
cJSON *is_stu = cJSON_GetObjectItemCaseSensitive(root, "is_student");
if (cJSON_IsBool(is_stu)) {
printf("is_student: %s\n", cJSON_IsTrue(is_stu) ? "true" : "false");
}
// 4. 遍历数组
cJSON *scores = cJSON_GetObjectItemCaseSensitive(root, "scores");
if (cJSON_IsArray(scores)) {
int size = cJSON_GetArraySize(scores);
for (int i = 0; i < size; i++) {
cJSON *s = cJSON_GetArrayItem(scores, i);
if (cJSON_IsNumber(s)) {
printf("score[%d]: %.1f\n", i, s->valuedouble);
}
}
}
5. 修改 / 替换类
修改已存在的 JSON 节点(替换值、新增节点等)。
替换对象中指定 key 的节点
c
void cJSON_ReplaceItemInObject(cJSON *obj, const char *key, cJSON *new_item);
向对象添加节点引用(不复制内存,仅引用)
c
void cJSON_AddItemReferenceToObject(cJSON *obj, const char *key, cJSON *item);
示例:
c
// 替换 age 的值
cJSON *new_age = cJSON_CreateNumber(21);
cJSON_ReplaceItemInObject(root, "age", new_age);
6. 释放类(内存管理,必用!)
cJSON 是手动内存管理,解析 / 创建的节点必须释放,否则内存泄漏。
递归释放节点及其所有子节点
c
void cJSON_Delete(cJSON *node);
- 只需释放根节点,子节点会被递归释放
7.类型判断宏(辅助,避免出错)
取值前必须判断节点类型,否则可能访问空指针 / 错误成员:
c
cJSON_IsNull(item) // 是否为 NULL 类型
cJSON_IsTrue(item) // 是否为 true
cJSON_IsFalse(item) // 是否为 false
cJSON_IsBool(item) // 是否为布尔类型
cJSON_IsNumber(item) // 是否为数字类型
cJSON_IsString(item) // 是否为字符串类型
cJSON_IsArray(item) // 是否为数组类型
cJSON_IsObject(item) // 是否为对象类型
4.综合示例(解析 + 创建 + 取值 + 释放)
c
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main(){
// 1.解析JSON字符串
const char *json_str = "{\"name\":\"Tom\",\"age\":20,\"is_student\":true,\"scores\":[90.5, 85, 95]}";
cJSON *root = cJSON_Parse(json_str);
if (root == NULL) {
printf("解析失败:%s\n", cJSON_GetErrorPtr());
return -1;
}
// 2.提取数据
//提取字符串
cJSON *name = cJSON_GetObjectItemCaseSensitive(root, "name");
if (cJSON_IsString(name) && name->valuestring) {
printf("name: %s\n", name->valuestring);
}
//提取数字
cJSON *age = cJSON_GetObjectItemCaseSensitive(root, "age");
if (cJSON_IsNumber(age)) {
printf("age(int): %d\n", age->valueint); // 整数
printf("age(double): %.1f\n", age->valuedouble); // 浮点
}
// 3.创建新JSON
cJSON *new_obj = cJSON_CreateObject();
cJSON_AddStringToObject(new_obj, "name", "Jerry");
cJSON_AddNumberToObject(new_obj, "age", 18);
cJSON *hobbies = cJSON_CreateArray();
cJSON_AddItemToArray(hobbies, cJSON_CreateString("reading"));
cJSON_AddItemToObject(new_obj, "hobbies", hobbies);
// 4.打印新JSON字符串
char *fmt_str = cJSON_Print(new_obj);
printf("\n新JSON:\n%s\n", fmt_str);
// 5. 修改
cJSON_ReplaceItemInObject(new_obj, "age", cJSON_CreateNumber(25));
char *fmt_str2 = cJSON_Print(new_obj);
printf("\n修改后JSON:\n%s\n", fmt_str2);
//5.释放内存
cJSON_Delete(root);
cJSON_Delete(new_obj);
free(fmt_str);
free(fmt_str2);
return 0;
}
