对于对cJSON不太熟的同学来说,容易踩到这个坑。特记录一下。
小坑现象:有归属的json对象itemA调用cJSON_AddItemToObject添加到其他对象中,会带入itemA的next对象。
比如有一个带有itemA的json对象root_a如下:
{
"f_name":"f_value",
"itemA":{
"nameA":"valueA"
},
"l_name":"l_value"
}
现在有个需求,需要将itemA的内容取出来添加到另外应该json对象root_b中。
获取itemA的函数:
cJSON *itemA;
itemA=cJSON_GetObjectItem(root_a,"itemA");
root_b如下:
{
"name1":"value1",
"name2":"value2"
}
想通过调用cJSON_AddItemToObject达到的目标效果如下:
即执行:
cJSON_AddItemToObject(root_b,"itemA",itemA);
期望的结果:
{
"name1":"value1",
"name2":"value2",
"itemA":{
"nameA":"valueA"
}
}
但执行以下的函数调用后的实际结果如下:
{
"name1":"value1",
"name2":"value2",
"itemA":{
"nameA":"valueA"
},
"l_name":"l_value"
}
可以看到函数将后面的对象l_name也一起加入到了root_b中。不知道这个是cJSON的bug还是就是这样设计的,根据cJSON的结构体来分析,cJSON_AddItemToObject将itemA对象的next的值也加入到了root_b中。
正确的方法:
在这种情况下,采用cJSON_AddItemReferenceToObject来实现,不要用cJSON_AddItemToObject函数。
itemA的内存释放不归属于root_b,而是归属于root_a。
即执行:
cJSON_AddItemReferenceToObject(root_b,"itemA",itemA);
就能得到正确的结果。
两个函数的区别说明如下:
/向对象中添加键值对,值的类型与相关函数有关/
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
/* 将对象的引用附加到指定的数组/对象。当您想要将现有的cJSON添加到新的cJSON中,但又不想破坏现有的cJSON时,请使用此选项 */
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
附:cJSON结构体:
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
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 valueint;
/* The item's number, if type==cJSON_Number */
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;