C语言中如何解析JSON数组对象
在C语言开发中,处理JSON数据是常见需求,尤其是解析JSON数组对象(如[{"key1":"value1"},{"key2":"value2"}]这样的结构),由于C语言本身没有内置JSON解析支持,我们需要借助第三方库来实现,本文将以轻量级且广泛使用的cJSON库为例,详细介绍如何在C语言中解析JSON数组对象,包括环境搭建、核心API使用、完整代码示例及常见问题处理。
JSON数组对象的基本结构
JSON数组对象是值的有序集合,用方括号[]包裹,值之间用逗号分隔,每个值可以是基本类型(字符串、数字、布尔值、null)或嵌套的JSON对象/数组。
[
{"name": "Alice", "age": 25, "scores": [90, 85, 95]},
{"name": "Bob", "age": 30, "isStudent": false},
null,
"single_value"
]
解析时,我们需要逐层访问:先解析外层数组,再遍历数组中的每个元素(对象/基本值),最后提取对象中的键值对。
cJSON库简介与环境搭建
为什么选择cJSON?
- 轻量级:核心代码仅单个文件,无外部依赖,适合嵌入式或资源受限环境。
- API简单:提供直观的函数创建、解析、遍历JSON数据。
- 功能完整:支持JSON对象、数组、字符串、数字等所有类型,支持深拷贝和释放内存。
环境搭建
(1)获取cJSON源码
从GitHub仓库(https://github.com/DaveGamble/cJSON)下载最新源码,或直接下载cJSON.h和cJSON.c文件。
(2)集成到项目
将cJSON.h放在项目头文件目录,cJSON.c添加到编译源文件列表中,在Linux环境下使用gcc编译:
gcc your_program.c cJSON.c -o your_program -lm
(-lm是链接数学库,部分版本可能需要)
cJSON核心API解析JSON数组
解析JSON数组的核心流程是:解析字符串 → 获取数组对象 → 遍历数组元素 → 处理每个元素(对象/基本值),以下是关键API及使用方法。
解析JSON字符串为cJSON对象
使用cJSON_Parse()函数将JSON格式字符串解析为cJSON对象(指针),失败时返回NULL。
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
const char* json_str = "[{\"name\":\"Alice\",\"age\":25},{\"name\":\"Bob\",\"age\":30}]";
cJSON* root = cJSON_Parse(json_str);
if (!root) {
printf("JSON解析失败: %s\n", cJSON_GetErrorPtr());
return -1;
}
// 解析成功,后续操作root...
cJSON_Delete(root); // 释放内存
return 0;
}
检查并获取数组对象
cJSON中,数组类型通过cJSON_IsArray()判断,通过cJSON_GetArraySize()获取数组长度。
if (!cJSON_IsArray(root)) {
printf("错误:根节点不是数组\n");
cJSON_Delete(root);
return -1;
}
int array_size = cJSON_GetArraySize(root);
printf("数组长度: %d\n", array_size); // 输出: 2
遍历数组元素
使用cJSON_GetArrayItem()按索引获取数组元素,或通过cJSON_ArrayForEach()宏遍历所有元素(推荐后者,更安全)。
(1)按索引遍历
for (int i = 0; i < array_size; i++) {
cJSON* item = cJSON_GetArrayItem(root, i);
if (!item) continue;
// 处理item...
}
(2)使用cJSON_ArrayForEach遍历(推荐)
cJSON* item = NULL;
cJSON_ArrayForEach(item, root) {
// 处理item...
}
处理数组中的对象元素
若数组元素是JSON对象(如示例中的{"name":"Alice"}),需通过cJSON_IsObject()判断,并用cJSON_GetObjectItem()获取键值对。
cJSON_ArrayForEach(item, root) {
if (!cJSON_IsObject(item)) {
printf("元素 %d 不是对象,跳过\n", (int)(item - root)); // item-root为索引(非严格,仅示例)
continue;
}
cJSON* name = cJSON_GetObjectItem(item, "name");
cJSON* age = cJSON_GetObjectItem(item, "age");
if (cJSON_IsString(name) && cJSON_IsNumber(age)) {
printf("姓名: %s, 年龄: %d\n", name->valuestring, age->valueint);
}
}
// 输出:
// 姓名: Alice, 年龄: 25
// 姓名: Bob, 年龄: 30
处理嵌套数组和复杂类型
若数组元素包含嵌套数组(如"scores":[90,85,95])或基本类型(如null、字符串),需递归或按类型处理:
// 示例JSON: [{"name":"Alice","scores":[90,85,95]}, "hello", null]
cJSON_ArrayForEach(item, root) {
if (cJSON_IsObject(item)) {
cJSON* scores = cJSON_GetObjectItem(item, "scores");
if (cJSON_IsArray(scores)) {
printf("%s的分数: ", cJSON_GetObjectItem(item, "name")->valuestring);
cJSON* score = NULL;
cJSON_ArrayForEach(score, scores) {
if (cJSON_IsNumber(score)) {
printf("%d ", score->valueint);
}
}
printf("\n"); // 输出: Alice的分数: 90 85 95
}
} else if (cJSON_IsString(item)) {
printf("字符串元素: %s\n", item->valuestring); // 输出: 字符串元素: hello
} else if (cJSON_IsNull(item)) {
printf("null元素\n"); // 输出: null元素
}
}
内存释放
cJSON动态分配内存,解析完成后必须用cJSON_Delete()释放整个JSON树,避免内存泄漏。
cJSON_Delete(root); // 释放root及其所有子节点
完整代码示例
以下是一个完整的示例,解析包含对象、嵌套数组和基本值的JSON数组,并提取关键信息:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
void parse_json_array(const char* json_str) {
// 1. 解析JSON字符串
cJSON* root = cJSON_Parse(json_str);
if (!root) {
printf("JSON解析失败: %s\n", cJSON_GetErrorPtr());
return;
}
// 2. 检查是否为数组
if (!cJSON_IsArray(root)) {
printf("错误:输入不是JSON数组\n");
cJSON_Delete(root);
return;
}
// 3. 遍历数组元素
printf("开始解析JSON数组:\n");
cJSON* item = NULL;
cJSON_ArrayForEach(item, root) {
if (cJSON_IsObject(item)) {
printf("--- 对象元素 ---\n");
// 提取字符串字段
cJSON* name = cJSON_GetObjectItem(item, "name");
if (name && cJSON_IsString(name)) {
printf("姓名: %s\n", name->valuestring);
}
// 提取数字字段
cJSON* age = cJSON_GetObjectItem(item, "age");
if (age && cJSON_IsNumber(age)) {
printf("年龄: %d\n", age->valueint);
}
// 提取嵌套数组
cJSON* scores = cJSON_GetObjectItem(item, "scores");
if (scores && cJSON_IsArray(scores)) {
printf("分数: [");
cJSON* score = NULL;
cJSON_ArrayForEach(score, scores) {
if (cJSON_IsNumber(score)) {
printf("%d", score->valueint);
if (score->next) printf(", "); // 最后一个元素不加逗号
}
}
printf("]\n");
}
} else if (cJSON_IsString(item)) {
printf("--- 字符串元素 ---\n");
printf("值: %s\n", item->valuestring);
} else if (cJSON_IsNull(item)) {
printf("--- null元素 ---\n");
printf("值: null\n");
} else if (cJSON_IsNumber(item)) {
printf("--- 数字元素 ---\n");
printf("值: %d\n", item->valueint


还没有评论,来说两句吧...