cJSON源码解释(一)--节点管理
来源:互联网 发布:淘宝订单险是什么意思 编辑:程序博客网 时间:2024/05/19 00:13
前言
楼主是CS的毕业生,虽然不是编程新手,但是在校期间都没有做过大规模的项目,于是想从网上学习一些开源项目来弥补自己的经验,这是第一次解释开源的源代码,出于柿子还是挑软捏这个原则,盯上了只有一千行代码的cJSON。从test.c文件开始,逐步调试程序的执行过程,通过画出数据结构来解读源代码,过程如下
JSON是什么
通过阅读下面的页面来了解JSON的信息:http://www.json.org/json-zh.html
我从这里下载了cJSON的源代码http://sourceforge.net/projects/cjson/
可以了解到JSON具有两种形式,一种是由键值对(key/value)集合组成的对象(object),另一种是由值(value)的集合组成的数组。其中,key的类型是字符串类型,因为JSON允许结构嵌套,所以value的类型则有很多种,包括:字符串,数字,对象,数组,true,false,null
cJSON的解释原理:
1. cJSON分为三步来处理:解释,渲染和输出
2. 解释阶段:对输入的字符串进行特征识别,例如提取字符串中的单词,数字等,并把这些提取出来的特征分别组合成一个节点,然后用树(树的某些节点是双向链表)把这些节点连接起来。
3. 渲染阶段:提取树中每个节点里的信息,放在一个字符串缓冲区中,最后输出缓冲区里的内容
4.输出阶段:把缓冲区里的内容输出即可
用代码描述JSON的一个节点结构如下:
typedef struct cJSON { struct cJSON *next,*prev; /*该节点指向前后节点的指针*/ struct cJSON *child; /*一个数组节点或者对象节点会拥有一个指向由子节点组成的链表的指针 int type; /*节点的类型 */ char *valuestring; /* 如果这个节点的type等于cJSON_String,就会具有这个字段的信息 */ int valueint; /* 如果这个节点的type等于cJSON_Number,就会具有这个字段的信息*/ double valuedouble; /* 如果这个节点的type等于cJSON_Number,就会具有这个字段的信息*/char *string; /* 如果这个节点是一个儿子节点或者某个object的子节点的集合,这个字段表明了这个节点的名字 */} cJSON;
那么每个节点的type究竟有哪些呢?
/* cJSON Types: */#define cJSON_False 0#define cJSON_True 1#define cJSON_NULL 2#define cJSON_Number 3#define cJSON_String 4#define cJSON_Array 5#define cJSON_Object 6 #define cJSON_IsReference 256#define cJSON_StringIsConst 512
cJSON节点管理
创建节点
/* 分配一个JSON节点的内存,并且用0填充该节点的内容*/static cJSON *cJSON_New_Item(void){ cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); if (node) memset(node,0,sizeof(cJSON)); return node;}
注意这里使用到的函数cJSON_malloc(),cJSON使用了hook技术,使得用户可以自己定制内存的分配和释放函数,在默认的情况下,cJSON使用的是C语言中的malloc和free函数。代码如下:
static void *(*cJSON_malloc)(size_t sz) = malloc; //cJSON_malloc是一个函数指针的指针static void (*cJSON_free)(void *ptr) = free; //cJSON_free是一个函数指针/*用户可以选择是否使用自定义的内存管理函数*/void cJSON_InitHooks(cJSON_Hooks* hooks) { if (!hooks) { /* Reset hooks */ cJSON_malloc = malloc; cJSON_free = free; return; } cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; cJSON_free = (hooks->free_fn)?hooks->free_fn:free;}
可以封装cJSON_New_Item()函数来创建更具体的JSON节点
/* Create basic types: */cJSON *cJSON_CreateNull(void){ cJSON *item=cJSON_New_Item(); if(item)item->type=cJSON_NULL; return item;}cJSON *cJSON_CreateTrue(void){ cJSON *item=cJSON_New_Item(); if(item)item->type=cJSON_True; return item;}cJSON *cJSON_CreateFalse(void){ cJSON *item=cJSON_New_Item(); if(item)item->type=cJSON_False; return item;}cJSON *cJSON_CreateBool(int b){ cJSON *item=cJSON_New_Item(); if(item)item->type=b?cJSON_True:cJSON_False; return item;}cJSON *cJSON_CreateNumber(double num){ cJSON *item=cJSON_New_Item(); if(item){ item->type=cJSON_Number; item->valuedouble=num; item->valueint=(int)num; } return item;}cJSON *cJSON_CreateString(const char *string){ cJSON *item=cJSON_New_Item(); if(item){ item->type=cJSON_String; item->valuestring=cJSON_strdup(string); } return item;}cJSON *cJSON_CreateArray(void){ cJSON *item=cJSON_New_Item(); if(item)item->type=cJSON_Array; return item;}cJSON *cJSON_CreateObject(void){ cJSON *item=cJSON_New_Item(); if(item) item->type=cJSON_Object; return item;}/* Create Arrays: */cJSON *cJSON_CreateIntArray(const int *numbers,int count){ int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray(); for(i=0;a && i<count;i++){ n=cJSON_CreateNumber(numbers[i]); if(!i) a->child=n; else suffix_object(p,n); p=n; } return a;}cJSON *cJSON_CreateFloatArray(const float *numbers,int count){ int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray(); for(i=0;a && i<count;i++){ n=cJSON_CreateNumber(numbers[i]); if(!i) a->child=n; else suffix_object(p,n); p=n; } return a; } cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) { int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray(); for(i=0;a && i<count;i++){ n=cJSON_CreateNumber(numbers[i]); if(!i) a->child=n; else suffix_object(p,n); p=n; } return a;}cJSON *cJSON_CreateStringArray(const char **strings,int count){ int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray(); for(i=0;a && i<count;i++){ n=cJSON_CreateString(strings[i]); if(!i) a->child=n; else suffix_object(p,n); p=n; } return a;}
添加节点
只能够往object或者array中添加子节点
/* Add item to array/object. */void cJSON_AddItemToArray(cJSON *array, cJSON *item){ cJSON *c=array->child; if (!item) return; if (!c) { array->child=item; } else { while (c && c->next) c=c->next; suffix_object(c,item); }}void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item){ if (!item) return; if (item->string) cJSON_free(item->string); item->string=cJSON_strdup(string); cJSON_AddItemToArray(object,item);}void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item){ if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string); item->string=(char*)string; item->type|=cJSON_StringIsConst; cJSON_AddItemToArray(object,item);}
在object中添加子节点的时候,只要把object节点的string字段设置好就可以直接调用给array添加子节点的函数,其中suffix_object函数如下,它的功能是设置好节点的前后指针
static void suffix_object(cJSON *prev,cJSON *item) { prev->next=item; item->prev=prev;}
删除节点
删除节点分为两种:detach和delete。detach是把要删除的节点从双向链表中分离出来(并没有释放该节点的内存),然后返回该分离的节点,而delete是直接把该节点的内存释放掉
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which){ cJSON *c=array->child; while (c && which>0) c=c->next,which--; if (!c) return 0; if (c->prev) c->prev->next=c->next; if (c->next) c->next->prev=c->prev; if (c==array->child) array->child=c->next; c->prev=c->next=0; return c;}void cJSON_DeleteItemFromArray(cJSON *array,int which){ cJSON_Delete(cJSON_DetachItemFromArray(array,which));}cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) { int i=0; cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next; if (c) return cJSON_DetachItemFromArray(object,i); return 0;}void cJSON_DeleteItemFromObject(cJSON *object,const char *string) { cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
cJSON_strcasecmp函数忽略大小写,然后比较字符串,s1比s2大则返回大于0的整数,相等则返回0,小于则返回符整数
static int cJSON_strcasecmp(const char *s1,const char *s2){ if (!s1) return (s1==s2)?0:1; if (!s2) return 1; for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);}
释放节点的内存时,如果节点有儿子节点,则对儿子节点进行递归删除;如果节点有字符串信息,就先释放字符串的内存,其他类型的节点就直接释放节点的内存
/* Delete a cJSON structure. */void cJSON_Delete(cJSON *c){ cJSON *next; while (c) { next=c->next; if (!(c->type&cJSON_IsReference) && c->child) //检查节点是否被引用了 cJSON_Delete(c->child); if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); cJSON_free(c); c=next; }}
修改节点
一个链表的节点替换工作。
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) { cJSON *c=array->child; while (c && which>0) c=c->next,which--; if (!c) return; newitem->next=c->next; newitem->prev=c->prev; if (newitem->next) newitem->next->prev=newitem; if (c==array->child) array->child=newitem; else newitem->prev->next=newitem; c->next=c->prev=0; cJSON_Delete(c);}void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){ int i=0; cJSON *c=object->child; while(c && cJSON_strcasecmp(c->string,string)) i++,c=c->next; if(c){ newitem->string=cJSON_strdup(string); cJSON_ReplaceItemInArray(object,i,newitem); }}
查找节点
通过暴力搜索双向链表来查找节点
cJSON *cJSON_GetArrayItem(cJSON *array,int item){ cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}cJSON *cJSON_GetObjectItem(cJSON *object,const char *string){ cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
- cJSON源码解释(一)--节点管理
- cJSON源码解释(二)--解释输入
- cJSON源码解释(三)--渲染输出
- 【cJSon】cJSON学习笔记(一)
- cjson源码剖析(1)
- cJSON学习笔记(一)
- cJSON学习笔记(一)
- cJSON库源码分析
- cJSON源码的使用说明
- cJSON源码学习总结
- cjson源码阅读有感
- cJSON库源码分析
- CJSON源码研究笔记
- cJSON源码分析
- cjson源码学习
- cjson 源码阅读笔记
- CJSON源码研究笔记
- cJSON剖析一
- 利用并查集求最小生成树
- 每个程序员需掌握的20个代码命名小贴士
- [LinkedIn] Smallest/greatest/largest k element in stream of data (integer array) priority Q / heap
- P52第21题
- JS实现页面跳转 浏览器地址栏保持不变
- cJSON源码解释(一)--节点管理
- Sqrt double
- linux 查看用户所在组(groups指令的使用) 含实例
- 8.3 时间戳(Time Stamp)选项
- Linux下chkconfig命令详解
- 黑马程序员——Foundation框架学习——OC结构体、字符串、OC集合、NSNumber,NSValue、OC时间对象
- 复习——几种排序实现
- declare-styleable中format详解
- iOS开发 GPS定位 指定语言 返回中文地点