1.6 cJSON中的基本插入操作
cJSON中提供了一系列用于插入cJSON的item的一些函数,比如可以往某个cJSON的bject中插入一个某个名称的cJSON的item。也可以往某个数组类型的cJSON的item中插入一个item。但是需要注意的时,我们会发现cJSON所提供的这一系列插入函数都几乎有两个版本,一个是cJSON_AddXXX,另一个则是cJSON_AddXXXReference,前者只是插入一个item结点,后者则是插入结点的引用。这个地方需要着重理解一下。这涉及到了cJSON的内存管理机制,如果不清楚这两种函数的区别的话直接去使用,很容易导致内存的泄露或是程序的未知的崩溃的问题。
1.6.1 非引用方式往数组结点中插入结点
cJSON* arrayItem = cJSON_CreateArray();
cJSON* item = cJSON_CreateNumber(3.1415926);
//1.如果使用cJSON_AddItemToArray
cJSON_AddItemToArray(arrayItem, item);
//假设在这里释放item节点
cJSON_Delete(arrayItem);
//cJSON_Delete(item);//如果放开注释,这里会崩溃
//但是如果在这里释放arrayItem,那就会崩溃了(原因是,如果不是引用的方式往array里面插入结点,那么array作为item的父节点,array就会托管内部item的内存释放,因为释放的时候会判断item的是不是引用类型插入的,如果不是,那么释放的时候就会释放item的内存空间)
1.6.2 使用引用方式往数组结点中插入结点
cJSON* arrayItem = cJSON_CreateArray();
cJSON* item = cJSON_CreateNumber(3.1415926);
//1.如果使用cJSON_AddItemReferenceToArray以引用的方式往array中插入结点
cJSON_AddItemReferenceToArray(arrayItem, item);//如果是以引用的方式插入,那么插入到目标array之后,array会将插入的这个item标记为以引用方式插入的,那么释放array的时候就不会去释放item结点,这意味着,我们需要手动管理item的释放时机
//释放array结点
cJSON_Delete(arrayItem);
//假设在这里释放item节点
cJSON_Delete(item);//这里不会发生崩溃,因为插入的item结点是以引用方式插入的,array不会托管item结点的内存释放,item的内存释放由item自己维护

在介绍完上述的使用引用方式插入Item和使用非引用方式插入Item的区别之后,就可以开始轻轻松松的学习cJSON所提供的一系列cJSON_AddXXXX函数了。
以一个学生信息的基本结构作为例子来讲解如何往cJSON各种不同的结点中插入数据:
/*!假设要生成下面的JSON
* {
"Score": {
"Chinese": 96.5,
"Math": 90,
"English": 85
},
"Student Base Information": {
"Name": "LBXXPointer",
"Class": "Class 1 Of Level 3",
"Student ID": "2013120708",
"In School": true
},
"Base Information": {
"Home Address": "SiChuan Chengdu",
"Home Member": {
"Father": "XBR",
"Mother": "LEF"
}
}
}
*/
//0.假设有一个mainObject,这个mainObject管理着所有的插入的JSON的结点
cJSON* mainObject = cJSON_CreateObject();//创建了一个空的cJSON的Object作为主的JSON对象
cJSON* scoreObject = cJSON_CreateObject();//创建了一个空结点,用于存储分数对象
//1.将语文,数学,英语三门科目的分数插入到scoreArray中,并且
//1.1 创建语文分数结点并将语文成绩插入到语文分数结点中'Score':{'Chinese':xxx,'English':'XXXX'}
cJSON*chineseScoreObject = cJSON_CreateNumber(96.5);
cJSON_AddItemToObject(scoreObject, "Chinese", chineseScoreObject);//将一个数字插入到分数结点中
//1.2 创建数学分数结点,并将数学成绩结点插入到数学的分数结点中
cJSON* mathScoreObject = cJSON_CreateNumber(90.0);
cJSON_AddItemToObject(scoreObject, "Math", mathScoreObject);//将数学成绩插入到分数结点中
//1.3 创建英语分数结点并将英语成绩插入到英语分数结点中
cJSON* englishScoreObject = cJSON_CreateNumber(85.0);
cJSON_AddItemToObject(scoreObject, "English", englishScoreObject);//将英语成绩插入到英语分数结点中
//2.创建学生的基本信息结点(姓名,班级,学号,是否在读,基本信息:{家庭住址:LXXX,家庭成员:{'Father':'XXX','Monther':''XXXX'}})
//2.1 创建学生的基本信息结点{'Name':'XXX',Class:'XXX','ID':'XXXX','In School':'XXXX'}
cJSON* stuBaseInfoItem = cJSON_CreateObject();
//2.2 创建学生的姓名结点并添加值到结点中
cJSON* nameObject = cJSON_CreateString("LBXXPointer");
cJSON_AddItemToObject(stuBaseInfoItem, "Name", nameObject);
//2.3 创建学生的班级结点并将值添加到结点中
cJSON* classObject = cJSON_CreateString("Class 1 Of Level 3");
cJSON_AddItemToObject(stuBaseInfoItem,"Class",classObject);
//2.4 创建学生的学号结点并将值添加到结点中
cJSON* stuIdObject = cJSON_CreateString("2013120708");
cJSON_AddItemToObject(stuBaseInfoItem, "Student ID", stuIdObject);
//2.5 创建学生的是否在读的bool类型结点
cJSON_AddBoolToObject(stuBaseInfoItem, "In School", 1);
//2.6 创建基本信息结点{'Home Address':'XXXXX','Home Member':{'Father':'XXXX','Mother':'YYYY'}}
cJSON* baseInfoItem = cJSON_CreateObject();
///2.6.1 创建家庭住址结点
cJSON_AddStringToObject(baseInfoItem, "Home Address", "SiChuan Chengdu");
///2.6.2 创建家庭成员结点并将数据插入到家庭成员结点中
cJSON* homeMember = cJSON_CreateObject();
cJSON_AddStringToObject(homeMember, "Father", "XBR");
cJSON_AddStringToObject(homeMember, "Mother", "LEF");
///2.6.3 将家庭成员,家庭住址结点插入到基本信息结点中
cJSON_AddItemToObject(baseInfoItem, "Home Member", homeMember);
//3.组装最后的主JSON上下文
cJSON_AddItemToObject(mainObject, "Score",scoreObject);
cJSON_AddItemToObject(mainObject, "Student Base Information", stuBaseInfoItem);
cJSON_AddItemToObject(mainObject, "Base Information", baseInfoItem);
char* buf = cJSON_Print(mainObject);
cout << buf << endl;
cJSON_Delete(mainObject);
//总结:
//实际上在今后设计JSON格式模型的时候,需要根据实际的业务模型去推导出JSON中各个字段(是对象类型?还是数组类型?还是嵌套类型?还是单个JSON字段?),逐步在草稿纸上拆解各个JSON字段,分析清楚层级关系,然后逐个逐个实现即可
本节总结:
本节学习了cJSON的一系列插入操作相关的函数,然后着重介绍了使用引用方式插入结点和使用非引用方式插入结点的区别(使用非引用方式插入节点时,该节点所插入的那个cJSON对象若释放,那么就会带着插入的节点一起释放;若使用引用方式插入,那么该节点所插入的那个cJSON对象释放,则不会影响到原始的插入的节点。)
对cJSON中cJSON_Add系列函数的总结
| 函数名称 | 函数参数 | 函数作用 | 注意事项 |
| cJSON_AddItemToArray(cJSON *array, cJSON *item); |
array:要把item插入到哪个数组里面 item:要插入的item |
将一个item插入到某个数组类型的cJSON节点中 | 此函数属于非引用方式插入,那么若array被释放,那么item的原始指针所指向的空间也会被一并释放。(后续不能调用cJSON_Delete(item)再次释放内存) |
| cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); |
object:要把item插入到哪个目标object类型的cJSON中 string:该item在object中的名称 item:要插入的item |
将一个item插入到object类型的cJSON节点中,并且这个item在object中的名字为string | 此函数属于非引用方式插入,那么若object被释放,那么item的原始指针所指向的空间也会被一并释放。(后续不能调用cJSON_Delete(item)再次释放内存) |
| cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); |
array:要把item插入到哪个数组里面 item:要插入的item |
将一个item以引用的方式插入到某个数组类型的cJSON节点中 | 此函数属于引用方式插入,若array被释放,那么item的原始指针指向的空间不会被释放,后续需要手动管理item的内存释放时机(注:若item已经被cJSON_Delete释放,后续若对array进行访问或者是查找item节点,会导致内存崩溃) |
| cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); |
object:要把item插入到哪个目标object类型的cJSON中 string:该item在object中的名称 item:要插入的item |
将一个item以引用的方式插入到object类型的cJSON节点中,并且这个item在object中的名字为string | 此函数属于引用方式插入,若object被释放,那么item的原始指针指向的空间不会被释放,后续需要手动管理item的内存释放时机(注:若item已经被cJSON_Delete释放,后续若对object进行访问或者是查找item节点,会导致内存崩溃) |
| cJSON_AddNullToObject(cJSON * const object, const char * const name); |
object:要把空值插入到哪个object类型的cJSON的item中 name:这个空值被插入到object的item中之后的名字是什么 |
将一个空值以非引用的方式插入到object类型的cJSON节点中,然后这个函数的返回值就是插入的这个空值item的指针。这个指针拿到之后可以做修改空值的内容。 | 此函数相当于是创建了一个空值对象,然后把这个空值对象的item插入到了object中,插入的方式依然是非引用方式插入。即使得到插入的空值的item的指针,也不需要手动托管它的内存释放。只要object被delete,那么这个空值item对应的内存空间也会被释放。 |
| cJSON_AddTrueToObject(cJSON * const object, const char * const name); |
object:要把true值插入到哪个object类型的cJSON的item中 name:这个true值被插入到object之后item的名字是什么(json的键名称) |
将一个常量的true值以非引用的方式插入到object类型的cJSON节点中,这个函数的返回值实际上就是插入那个true值的item的指针,这个指针拿到之后也可以修改里面的内容。 | 此函数等价于cJSON* item = cJSON_CreateBool(1);cSJON_AddItemToObject(object,string,item);同样的也是以非引用的方式插入的,如果object被释放,那么true值对应的item的指针也被释放。 |
| cJSON_AddFalseToObject(cJSON * const object, const char * const name); |
object:要把false值插入到哪个object类型的cJSON的item中 name:这个false值被插入到object之后item的名字是什么(json的键名称) |
将一个常量的false值以非引用的方式插入到object类型的cJSON节点中,这个函数的返回值实际上就是插入那个false值的item的指针,这个指针拿到之后也可以修改里面的内容。 | 此函数等价于cJSON* item = cJSON_CreateBool(0);cSJON_AddItemToObject(object,string,item);同样的也是以非引用的方式插入的,如果object被释放,那么true值对应的item的指针也被释放。 |
| cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); |
object:要把boolean值插入到哪个object类型的cJSON的item中 name:这个boolean值被插入到object中之后的名字是什么(json键名称) boolean:boolean的取值是什么(true?false?) |
将一个指定了boolean值的值以非引用的方式插入到object类型的cJSON节点中,这个函数的返回值就是插入的那个boolean值的item指针。 | 此函数等价于cJSON*item = cJSON_CreateBool(boolean); cJSON_AddItemToObject(object,string,item);此函数仍然是非引用方式插入的。若object被释放,那么boolean值对应的item指针也被释放。 |
| cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); |
object:要把number值插入到哪个object类型的cJSON的item中 name:这个number item被插入到object之后的名字是什么(item的json键名称) number:要插入的数字值 |
将一个数字类型的item插入到object类型的cJSON节点中,这个函数的返回值就是插入的那个数字对应的item的指针。 | 此函数等价于cJSON*item = cJSON_CreateNumber(number); cJSON_AddItemToObject(object,string,item);此函数仍然是非引用方式插入的。若object被释放,那么number值对应的item指针也被释放。 |
| cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); |
object:要把string字符串值插入到哪个object类型的cJSON的item中 name:这个stirng item被插入到object之后的名字是什么(item在object中的键的名称) string:要插入的字符串的值 |
将一个字符串类型的item插入到object类型的cJSON节点中,这个函数的返回值就是插入的那个字符串对应的item的指针。 | 此函数等价于cJSON*item = cJSON_CreateString(string); cJSON_AddItemToObject(object,string,item);此函数仍然是非引用方式插入的。若object被释放,那么string值对应的item指针也被释放。 |
| cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); |
object:要把原始JSON串值插入到哪个object类型的cJSON的item中 name:这个原始JSON串item被插入到object之后的名字是什么(item在object中的键的名称) raw:要插入的原始JSON串(例如:"{'XXX':'XXX','YYY':'123'}") |
将一个原始的JSON串插入到object类型的cJSON节点中,此函数的返回值就是插入到object里面的raw串的item指针 | 此函数等价于cJSON*item = cJSON_CreateRaw(raw); cJSON_AddItemToObject(object,string,item);此函数仍然是非引用方式插入的。若object被释放,那么raw值对应的item指针也被释放。 |
| cJSON_AddObjectToObject(cJSON * const object, const char * const name); |
object:把要创建的空的object插入到目标object中。 name:空object的名称 这个函数不需要第三个参数(对照cJSON_CreateObject函数就没有参数,这就是本质),因为对于要插入的object,它实际上就是创建了一个名叫name的空的cJSON的object的item然后插入进去 假设{},然后插入一个object就是{'name':{}} |
创建一个空的cJSON的object类型的cJSON节点,然后把这个节点插入到形参中object的cJSON对象中。名字叫做name,函数的返回值就是那个创建的空的object的item指针 |
这个函数等价于: cJSON*objectItem = cJSON_CreateObject(); |
| cJSON_AddArrayToObject(cJSON * const object, const char * const name); |
object:把创建的空的array插入到目标object中 name:创建的空的array的名称 此参数也不需要第三个参数(对照cJSON_CreateArray函数就没有参数),对于这个函数,实际上就是往object这个cJSON节点内部创建了一个名叫name的array类型的cJSON的item。 |
创建一个空的cJSON的array类型的cJSON节点,然后把这个节点插入到形参中object的cJSON对象中。名字叫做name,函数的返回值就是那个创建的空的array的item指针 |
这个函数等价于: cJSON*arrayItem = cJSON_CreateArray(); |
浙公网安备 33010602011771号