如何用json-c处理多JSON对象:遍历、计数、缓冲区及内存释放问题
使用json-c处理多JSON对象的问题解答
嘿,我来帮你解决这几个json-c使用的问题,咱们一个个来捋清楚:
问题1:遍历多个对象并获取总数
首先要注意,你的JSON文档里是两个独立的JSON对象,不是标准的JSON数组(用[]包裹的结构),所以json_tokener_parse()只会解析第一个对象就停止了。要处理这种非标准的多JSON对象文件,你需要用到json-c的增量解析能力,通过json_tokener分步解析内容:
- 初始化一个
json_tokener对象,用来逐步处理输入数据 - 循环解析,每成功解析出一个完整对象就计数加一,同时处理该对象的字段
- 直到文件所有内容都被处理完毕,最终的计数就是对象总数
问题2:避免固定大小Buffer,逐个读取对象
固定buffer的问题确实会在对象数量多或者单个对象过大时触发异常,而增量解析刚好能解决这个问题:不需要一次性读取整个文件,而是每次读取一小段数据(比如128字节,大小可以按需调整),喂给json_tokener,它会自动拼接数据、判断是否能解析出完整对象。这种方式既不会因为buffer过小截断数据,也不会占用过多内存,完全实现逐个读取解析对象的需求。
问题3:内存释放的正确姿势
你当前的free(name); free(password);这类操作是完全错误的!因为json_object_object_get_ex()获取的指针是指向父JSON对象内部的子对象引用,这些对象的内存由json-c的引用计数机制管理,你不能直接用free()释放它们。
正确的内存管理方式:
- 对于每个完整解析出的JSON对象,处理完毕后调用
json_object_put(obj)来减少引用计数,当计数归0时,json-c会自动释放该对象及其所有子对象的内存 - 不要手动释放子对象指针,否则会触发内存错误或double free
- 初始化的
json_tokener对象,最后要用json_tokener_free()销毁
修改后的完整示例代码
#include <stdio.h> #include <stdlib.h> #include <json-c/json.h> int main(){ FILE* fichier = NULL; char buffer[128]; // 用小buffer即可,增量解析不需要大内存 struct json_tokener *tok = json_tokener_new(); struct json_object *obj; int object_count = 0; enum json_tokener_error err; fichier = fopen("../../data/Personne.json", "r"); if (fichier == NULL) { printf("Une ERREUR est survenue lors du chargement des différents comptes\n"); json_tokener_free(tok); return 1; } // 增量解析循环:逐步读取文件并解析对象 while (fread(buffer, 1, sizeof(buffer), fichier) > 0) { obj = json_tokener_parse_ex(tok, buffer, sizeof(buffer)); // 循环检查是否解析出完整对象(buffer中可能包含多个对象) while ((err = json_tokener_get_error(tok)) == json_tokener_success) { object_count++; printf("=== 对象 %d ===\n", object_count); struct json_object *name, *password, *salt, *email; json_object_object_get_ex(obj, "name", &name); json_object_object_get_ex(obj, "password", &password); json_object_object_get_ex(obj, "salt", &salt); json_object_object_get_ex(obj, "email", &email); printf("name : %s\n", json_object_get_string(name)); printf("password : %s\n", json_object_get_string(password)); printf("salt : %s\n", json_object_get_string(salt)); printf("email : %s\n", json_object_get_string(email)); // 释放当前解析出的对象 json_object_put(obj); // 尝试解析buffer中剩余的内容 obj = json_tokener_parse_ex(tok, "", 0); } // 如果是"需要更多数据"的错误,继续读取文件;其他错误则终止 if (err != json_tokener_continue) { printf("解析错误: %s\n", json_tokener_error_desc(err)); break; } } // 处理文件末尾可能剩余的未解析对象 obj = json_tokener_parse_ex(tok, "", 0); if ((err = json_tokener_get_error(tok)) == json_tokener_success) { object_count++; printf("=== 对象 %d ===\n", object_count); struct json_object *name, *password, *salt, *email; json_object_object_get_ex(obj, "name", &name); json_object_object_get_ex(obj, "password", &password); json_object_object_get_ex(obj, "salt", &salt); json_object_object_get_ex(obj, "email", &email); printf("name : %s\n", json_object_get_string(name)); printf("password : %s\n", json_object_get_string(password)); printf("salt : %s\n", json_object_get_string(salt)); printf("email : %s\n", json_object_get_string(email)); json_object_put(obj); } printf("\n总共有 %d 个对象\n", object_count); // 清理所有资源 fclose(fichier); json_tokener_free(tok); return 0; }
代码核心说明
- 用
json_tokener实现增量解析,小buffer循环读取文件,避免内存占用问题 - 每解析出一个完整对象就计数、处理字段,然后通过
json_object_put()释放对象内存 - 处理了文件末尾剩余数据的情况,确保所有对象都被解析
- 完全遵循json-c的内存管理规则,没有手动free子对象
内容的提问来源于stack exchange,提问作者magjico
相关产品推荐
相关产品推荐

