• CJSON库的学习


    目录

    一、JSON简介

    二、 JSON语法

    ​​​​​​三、 CJSON简介:

    四、 CJSON数据结构

    五、使用CJSON构造JSON

    1. cJSON常用库函数介绍

    2. CJSON构造JSON实例代码

    (1)!!!编译过程中有两个注意的点:

    3. 使用cJSON解析JSON实例代码


    一、JSON简介

    1.  JSON(JavaScript object Notation),即JavaScript 对象符号,是一种轻量级的数据格式;【其本质就是字符串
    2.  它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁,层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传送效率。
    3.  因为它完全独立于编程语言所以支持跨平台开发;
    4.  JSON 的名称中虽然带有JavaScript,但这是指其语法规则是参考JavaScript对象的,而不是指只能用于JavaScript 语言。
    5.  因为JSON本身就是参考JavaScript 对象的规则定义的,其语法与JavaScript定义对象的语法几乎完全相同。

    二、 JSON语法

    1.  JSON可以将数据转换为字符串,接着在网络中或者程序里面传递这个字符串,最后可以还原成各个编程语言所支持的数据格式;
    2.  JSON是一个无序的键值对(key / value)集合;
      • JSON以"{“开始,以”}"结束,允许嵌套使用
      • 每个key(关键字)和value(值)成对出现,关键字和值之间使用":"分隔
      • 键/值对之间用","分隔
      • 在这些字符前后允许存在无意义的空白符
      • 数组(Array)用方括号(“[]”)表示。
      • 对象(0bject)用大括号(“{}”)表示。
      • 名称/值对(name/value)组合成数组和对象。
      • 名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组。
      • 并列的数据之间用逗号(“,”)分隔
    • 在线的JSON解析网站如下:JSON解析

    • 如下是一个实际的例子,来体会一下JSON:

    1. {
    2. "name": "JK",
    3. "age": 18,
    4. "height": 175,
    5. "sex": false,
    6. "address": {
    7. "country": "China",
    8. "tel": 123456
    9. },
    10. "subject": ["语文", "数学", "英语"],
    11. "grade": [1, 2, 3],
    12. "student": [{
    13. "name": "wsf",
    14. "age": 23,
    15. "sex": true
    16. },
    17. {
    18. "name": "rs",
    19. "age": 25,
    20. "sex": true
    21. }
    22. ]
    23. }
    • JSON树可视化

    ​​​​​​三、 CJSON简介:

    1. CJSON对象的实现采用了树形结构,每一个对象就是树的一个节点,每个节点由cJSON这个结构体组成,对象中的元素也由cJSON这个结构体组成。同一层的对象和元素是双向链表结构,由next和prev指针链接。不同层的对象或元素由child指针链接起来。type表示对象或元素类型,string表示对象或节点的名称。元素的值存储在valuestring, valueint和valuedouble中;

    2. cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。

    3. 要使用CJSON,直接把项目从Github上clone下来,接着把CJSON.h,CJSON.c这两个源文件加入到工程中就行,使用时include CJSON.h头文件就行;

    四、 CJSON数据结构

    • cJSON使用cJSON结构体来表示一个JSON数据,定义在cJSON.h中,源码如下:

    1. //逻辑值的宏定义
    2. #define cJSON_Invalid (0)
    3. #define cJSON_False (1 << 0)
    4. #define cJSON_True (1 << 1)
    5. #define cJSON_NULL (1 << 2)
    6. #define cJSON_Number (1 << 3)
    7. #define cJSON_String (1 << 4)
    8. #define cJSON_Array (1 << 5)
    9. #define cJSON_Object (1 << 6)
    10. #define cJSON_Raw (1 << 7) /* raw json */
    11. #define cJSON_IsReference 256
    12. #define cJSON_StringIsConst 512
    13. /* The cJSON structure: */
    14. typedef struct cJSON
    15. {
    16. /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    17. struct cJSON *next;
    18. struct cJSON *prev;
    19. /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    20. struct cJSON *child;
    21. /* The type of the item, as above. */
    22. int type;
    23. /* The item's string, if type==cJSON_String and type == cJSON_Raw */
    24. char *valuestring;
    25. /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    26. int valueint;
    27. /* The item's number, if type==cJSON_Number */
    28. double valuedouble;
    29. /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    30. char *string;
    31. } cJSON;

     
      
    1.  首先,CJSON不是将一整段JSON数据全抽象出来,而是将其中的一条JSON数据抽象出来,也就是一个键值对,用上面的结构体 strcut cJSON 来表示,其中用来存放值的成员列表如下:
      1. String:用于表示该键值对的名称;
      2. type:用于表示该键值对中值的类型;
      3. valuestring:如果键值类型(type)是字符串,则将该指针指向键值;
      4. valueint:如果键值类型(type)是整数,则将该指针指向键值;
      5. valuedouble:如果键值类型(type)是浮点数,则将该指针指向键值;
    2.  一段完整的JSON数据中由很多键值对组成,并且涉及到键值对的查找、删除、添加,所以使用链表来存储整段JSON数据,如上面的代码所示:
      1. next指针:指向下一个键值对
      2. prev指针指向上一个键值对
    3.  因为JSON数据支持嵌套,所以一个键值对的值会是一个新的JSON数据对象(一条新的链表),也有可能是一个数组,方便起见,在cJSON中,数组也表示为一个数组对象,用链表存储,所以:在键值对结构体中,当该键值对的值是一个嵌套的JSON数据或者一个数组时,由child指针指向该条新链表;
    4.  链表中的一些概念:
      1. 头指针:指向链表头结点的指针;
      2. 头结点:不存放有效数据,方便链表操作;
      3. 首节点:第一个存放有效数据的节点;
      4. 尾节点:最后一个存放有效数据的节点;

    五、使用CJSON构造JSON

    1. cJSON常用库函数介绍

    1. extern cJSON * cJSON_CreateObject(void); //创建对象
    2. extern cJSON * cJSON_CreateArray(void); //创建数组
    3. extern cJSON * cJSON_CreateIntArray(const int *numbers, int count);//创建整型数组
    4. extern cJSON * cJSON_CreateDoubleArray(const double *numbers, int count);//创建双浮点型数组
    5. extern cJSON* cJSON_AddNullToObject(cJSON * const object, const char * const name);//在对象中添加null
    6. extern cJSON* cJSON_AddTrueToObject(cJSON * const object, const char * const name);//在对象中添加true
    7. extern cJSON* cJSON_AddFalseToObject(cJSON * const object, const char * const name);//在对象中添加false
    8. extern cJSON* cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);//在对象中添加数字
    9. extern cJSON* cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);//在对象中添加字符串
    10. extern cJSON_bool cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); //在对象中添加项目
    11. extern cJSON_bool cJSON_AddItemToArray(cJSON *array, cJSON *item);//在数组中添加项目
    12. extern char * cJSON_Print(const cJSON *item);//JSON数据结构转换为JSON字符串---有格式
    13. extern char * cJSON_PrintUnformatted(const cJSON *item); //JSON数据结构转换为JSON字符串---无格式
    14. extern void cJSON_Delete(cJSON *item); //清除结构体

    2. CJSON构造JSON实例代码

    1. #include "string.h"
    2. #include "cJSON.h"
    3. #include "stdio.h"
    4. int main()
    5. {
    6. // 创建头指针
    7. cJSON *JSON_Root = NULL;
    8. // 创建头结点,并将头指针指向头结点(可以看做是一个树的根root)
    9. JSON_Root = cJSON_CreateObject();
    10. // 添加一条字符串类型的JSON数据
    11. cJSON_AddStringToObject(JSON_Root, "name", "zhuhua");
    12. // 添加一条浮点类型的JSON数据(添加一个链表结点)到root下
    13. cJSON_AddNumberToObject(JSON_Root, "height", 66.6666);
    14. // 添加一条整数型的JSON数据(链表结点)
    15. cJSON_AddNumberToObject(JSON_Root, "grade", 100);
    16. // 添加一个嵌套的JSON数据(添加一个链表节点, 又一个《对象》)
    17. cJSON *timeCode = cJSON_CreateObject();
    18. // true
    19. cJSON_AddTrueToObject(timeCode, "Sex");
    20. cJSON_AddStringToObject(timeCode, "datatime", "20220811");
    21. cJSON_AddFalseToObject(timeCode, "Judge");
    22. // 最后把这个对象加入到root下
    23. cJSON_AddItemToObject(JSON_Root, "TIMECODE", timeCode);
    24. // 再次嵌套,加入一个数组类型的JSON数据,在timecode结点之下(添加一个链表结点)
    25. cJSON *dataCode = cJSON_CreateArray();
    26. // 两种方式添加
    27. cJSON_AddStringToObject(dataCode, "", "English");
    28. cJSON_AddItemToArray(dataCode, cJSON_CreateString("zhuzhuzhu"));
    29. cJSON_AddStringToObject(dataCode, "", "huahuahua");
    30. cJSON_AddNumberToObject(dataCode, "number", 300);
    31. // 将datacode (array)结点添加到timecode 对象结点下(同样数组也可以有对象数据, 甚至数组中数据类型也可以不一样,但这样理解上不太好)
    32. cJSON_AddItemToObject(timeCode, "DATACODE", dataCode);
    33. // 最后将JSON数据结构转换为字符串, 并且输出
    34. char *strForJson = cJSON_Print(JSON_Root);
    35. printf("json字符串:%s\n", strForJson);
    36. // 将字符串存入到文件中
    37. FILE *FCJ = NULL;
    38. FILE *FCJ1 = NULL;
    39. FCJ = fopen("data.txt", "w");
    40. FCJ1 = fopen("data1.txt", "w");
    41. int i = 0;
    42. for (i = 0; i < strlen(strForJson); ++i)
    43. {
    44. fprintf(FCJ, "%c", strForJson[i]);
    45. fputc(strForJson[i], FCJ1);
    46. }
    47. fclose(FCJ);
    48. fclose(FCJ1);
    49. // 清除结构体
    50. cJSON_Delete(JSON_Root);
    51. return 0;
    52. }

    • 输出结果如下:

    (1)!!!编译过程中有两个注意的点:

    1. 提示头文件中报unknown type name ‘size_t’错误:

      1. 原因及解决方案:

        1. 原因在测试c文件中加入了string.h的头文件,并且放在了cJSON.h的后面;

        2. 解决:一定要把string.h放在cJSON头文件的前面;

    2. 提示找不到pow和floor函数:

      1. 解决方案:需要链接math库libm(可以查一下libc相关)

    3. 编译语句

    1. gcc cJson.c CJSONTest.c -o uim -lm
    2. 最后./uim执行即可;

    3. 使用cJSON解析JSON实例代码

    1. #include <stdio.h>
    2. #include "cJSON.h"
    3. int main()
    4. {
    5. // 定义JSON字符串
    6. char json_string[]="{\"name\":\"zhuhua\",\
    7. \"height\":66.666600,\"grade\":100,\"TIMECODE\":{\"Sex\":true,\"datatime\":\"20220811\",\"Judge\":false,\"DATACODE\":[\"English\",\"zhuzhuzhu\",\"huahuahua\",300]}}";//定义JSON字符串
    8. // 将JSON字符串转换成JSON结构体
    9. cJSON *JSON_ROOT = cJSON_Parse(json_string);
    10. // 判断转换是否成功
    11. if (JSON_ROOT == NULL)
    12. {
    13. printf("cjson error.......\n");
    14. }
    15. else
    16. {
    17. printf("%s\n", cJSON_Print(JSON_ROOT));
    18. }
    19. printf("提取数据\n");
    20. // 解析字符串 找key 得value
    21. char *name = cJSON_GetObjectItem(JSON_ROOT, "name")->valuestring;
    22. // 打印看一下效果
    23. printf("%s\n", name);
    24. double height = cJSON_GetObjectItem(JSON_ROOT, "height")->valuedouble;
    25. printf("%lf\n", height);
    26. int grade = cJSON_GetObjectItem(JSON_ROOT, "grade")->valueint;
    27. printf("%d\n", grade);
    28. // 对象和数组的接收
    29. cJSON *obj_timeCode = cJSON_GetObjectItem(JSON_ROOT, "TIMECODE"); // 解析对象
    30. cJSON *arr_dataCode = cJSON_GetObjectItem(obj_timeCode, "DATACODE"); // 解析数组 一层一层来
    31. int sex = cJSON_GetObjectItem(obj_timeCode, "Sex")->type; // 解析逻辑值————输出逻辑值对应的宏定义数值
    32. printf("%d\n", sex);
    33. char *datatime = cJSON_GetObjectItem(obj_timeCode, "datatime")->valuestring;
    34. printf("%s\n", datatime);
    35. int judge = cJSON_GetObjectItem(obj_timeCode, "Judge")->type; // 解析逻辑值————输出逻辑值对应的宏定义数值
    36. printf("%d\n", judge);
    37. // 数组的处理 先获取数组的成员个数
    38. int arr_size = cJSON_GetArraySize(arr_dataCode);
    39. printf("arrsize: %d\n", arr_size);
    40. int i = 0;
    41. for (i = 0; i < arr_size - 1; ++i)
    42. {
    43. printf("%s\n", cJSON_GetArrayItem(arr_dataCode, i)->valuestring);
    44. }
    45. printf("%d\n", cJSON_GetArrayItem(arr_dataCode, arr_size - 1)->valueint);
    46. // 清除结构体
    47. cJSON_Delete(JSON_ROOT);
    48. return 0;
    49. }

    • 运行结果如下

  • 相关阅读:
    剑指 Offer 19. 正则表达式匹配
    VLAN互通
    浏览器输入URL后到服务器返回数据大体过程
    OG-488 SE|198139-51-4|Oregon Green 488 Succinimidyl Ester
    【Linux】文件重定向以及一切皆文件
    Java Spring-AOP动态代理-JDK和CGlib实现
    shiro550复现环境搭建
    python解析.hhr文件
    JAVA计算机毕业设计幼儿影视节目智能推荐系统Mybatis+源码+数据库+lw文档+系统+调试部署
    实人认证API的出现,让电子化身份验证更加可靠
  • 原文地址:https://blog.csdn.net/weixin_43306271/article/details/126282917