c语言 list 使用数组来实现_如何使用C语言实现JSON解析器(一)

从结构上看,所有数据最终可分解成三种类型:

1.标量(scalar),即一个单独的字符串(string)或数字(numbers),比如“北京”这个单独的词。

2.序列(sequence),即若干个相关数据按照一定顺序并列在一起,又叫数组(array)或列表(list),比如“北京,上海”。

3.映射(mapping),即一个名称/值对(name/value),数据有一个名称,且有一个与之相对应的值,又称散列或字典,比如“首都:北京”。


  • 简单需求分析

了解JSONL:https://www.json.org/json-zh.html

JSON值有6种数据类型:

l 对象

l 数字

l 字符串

l 数组

l 布尔

l NULL

一个对象用一对花括号括起来,如图有3个对象。

1b91374a373123269eab829d45b1b99e.png

1个数组,2个字符串,1个布尔型,1个null,1个数字

8395bd11600e3e3e78e9cfb55ddad7c0.png

JSON结构:

5459a0e7dca979cbf94f38e93e145af6.png

34a1cc4400a38ddcbee1eae02adb251f.png

由上述的分析可发现,只有object类型和array类型才会有子节点。

逻辑上它是一棵树:

98698e45634340435edcd71e944e31a7.png

代码实现上按如下图结构来实现,其中兄弟节点间用双链表来实现

6388e7a4321de0717e5987a25c4e2ec8.png

  • 代码实现

cJSON.h头文件:

//节点类型(type)#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//节点的结构typedef struct cJSON {  struct cJSON *next, *prev;//兄弟节点  struct cJSON *child;//子节点  int type;//节点类型  char *valueString;//当type==cJSON_String时,该节点的值  int valueInt;//当type==cJSON_Number时,该节点的int值  double valueDouble;//当type==cJSON_Number时,该节点的double值  char *nameString; //节点名称,即name-value中的name,若无则为null}cJSON;//创建基本类型cJSON *cJSON_CreateObject(void);//创建一个对象节点cJSON *cJSON_CreateString(const char *string);//创建一个字符串节点cJSON *cJSON_CreateNumber(double num);//创建一个数字型节点cJSON *cJSON_CreateArray(void);//创建一个数组型节点cJSON *cJSON_CreateBool(int b);//创建一个布尔型节点,赋值为bcJSON *cJSON_CreateTrue(void);//创建一个值为true的布尔型cJSON *cJSON_CreateFalse(void);//创建一个值为false的布尔型节点cJSON *cJSON_CreateNull(void);//创建一个null类型节点

先来实现创建基本类型函数:

cJSON.c源文件:

/*1.使用函数指针,为了方便以后替换成其它自定义函数2.使用static:该函数指针只能在本件中源文件中使用,对其它源文件隐藏*/static void *(*cJSON_malloc)(size_t sz) = malloc;static void(*cJSON_free)(void *ptr) = free;/*1.作用:为节点开辟内存空间,并将内存空间初始化为02.使用static:只能在本源文件中使用,对其它源文件隐藏*/static cJSON *cJSON_New_Item(void){  cJSON *node = cJSON_malloc(sizeof(cJSON));  if (node) { memset(node, 0, sizeof(cJSON)); }  return node;}/*1.作用:字符串拷贝1.字符串拷贝函数,此处使用深拷贝,size_t是一个int类型,可在不同系统下分配不同长度*/const char *cJSON_strdup(const char *str){  char *copy;  size_t len = strlen(str);  copy = (char*)cJSON_malloc(len + 1);  memcpy(copy, str, len + 1);  return copy;}cJSON *cJSON_CreateObject(void){  cJSON *item = cJSON_New_Item();//分配内存空间  if (item) { item->type = cJSON_Object; }//设置节点类型  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_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_CreateArray(void){  cJSON *item = cJSON_New_Item();//分配内存空间  if (item) { item->type = cJSON_Array; }//设置节点类型  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_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_Object类型节点添加子节点cJSON *cJSON_CreateNull(void){  cJSON *item = cJSON_New_Item();//分配内存空间  if (item) { item->type = cJSON_NULL; }//设置节点类型  return item;}

创建完节点后,接着需要将节点关联起来:

cJSON.h头文件:

//为cJSON_Array类型节点添加子节点cJSON *cJSON_AddItemToArray(cJSON *array, cJSON *item);//为cJSON_Object类型节点添加子节点cJSON *cJSON_AddItemToObject(cJSON *object, const char *name, cJSON *item);

cJSON.c源文件:

//为cJSON_Array类型节点添加子节点cJSON *cJSON_AddItemToArray(cJSON *array, cJSON *item){  if (!item) { return NULL; }  cJSON *c = array->child;  if (!c)  {array->child = item;}  else  {    while (c && c->next){c = c->next;}    c->next = item;    item->prev = c;  }}//为cJSON_Object类型节点添加子节点cJSON *cJSON_AddItemToObject(cJSON *object, const char *name, cJSON *item){  if (!item) { return NULL; }  if (item->nameString) { cJSON_free(item->nameString); }//节点名称不为空,先释放内存再赋值  item->nameString = cJSON_strdup(name);  cJSON_AddItemToArray(object, item);//该部分代码可复用}

    未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值