美文网首页js
JSON的简单介绍&cJSON库使用(一)

JSON的简单介绍&cJSON库使用(一)

作者: 苏州韭菜明 | 来源:发表于2019-03-18 18:41 被阅读0次

    JSON WIKI解释

    JSONJavaScript Object Notation,JavaScript对象表示法)是一种由道格拉斯·克罗克福特构想和设计、轻量级数据交换语言该语言以易于让人阅读的文字为基础,用来传输由属性值或者序列性的值组成的数据对象。尽管JSON是JavaScript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。

    JSON 数据格式与语言无关,脱胎自JavaScript,但当前很多编程语言都支持 JSON 格式数据的生成和解析。JSON 的官方 MIME 类型application/json,文件扩展名是 .json

    JSON 解析器和 JSON 库支持许多不同的编程语言。 JSON 文本格式在语法上与创建 JavaScript 对象的代码相同。 由于这种相似性, 无需解析器, JavaScript 程序能够使用内建的 eval() 函数, 用 JSON 数据来生成原生的 JavaScript 对象。

    • JSON 是存储和交换文本信息的语法。 类似 XML。 JSON 比 XML 更小、 更快, 更易解析。

    • JSON 具有自我描述性, 语法简洁, 易于理解。

    JSON建构于两种结构:

    • “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。

    • 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

    JSON的三种语法:

    键/值对 key:value,用半角冒号分割。 比如 "name":"Faye" 文档对象 JSON对象写在花括号中,可以包含多个键/值对。比如{ "name":"Faye" ,"address":"北京" }。   数组 JSON 数组在方括号中书写: 数组成员可以是对象,值,也可以是数组(只要有意义)。{"love": ["乒乓球","高尔夫","斯诺克","羽毛球","LOL","撩妹"]}

    json.jpg

    cJSON是C语言中的一个JSON编解码器,非常轻量级,C文件只有不到一千行,代码的可读性也很好,很适合作为C语言项目进行学习。
    项目主页
    项目github主页

    cJSON源码解析、下载与安装:

    git clone https://github.com/DaveGamble/cJSON 
    #下载完成后,切换至下载目录
    mkdir build
    cd build
    cmake .. -DENABLE_CJSON_UTILS=Off -DENABLE_CJSON_TEST=On -DCMAKE_INSTALL_PREFIX=/usr (生成bin+lib)
    cmake .. -DENABLE_CJSON_UTILS=Off -DENABLE_CJSON_TEST=On -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=Off (生成bin)
    make
    sudo make install (安装libcjson.so)
    
    

    先来看一下cJSON的数据结构:

    /* The cJSON structure: */
    typedef struct cJSON {
        struct cJSON *next,*prev;   /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
        struct cJSON *child;        /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    
       int type;                   /* The type of the item, as above. */
    
        char *valuestring;          /* The item's string, if type==cJSON_String */
        int valueint;               /* The item's number, if type==cJSON_Number */
        double valuedouble;         /* The item's number, if type==cJSON_Number */
    
        char *string;               /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    } cJSON;
    

    不管是数值类型、字符串类型或者对象类型等都使用该结构体,类型信息通过标识符 type来进行判断,cJSON总共定义了7种类型:

    /* cJSON Types: */
    #define cJSON_Invalid (0)
    #define cJSON_False  (1 << 0)
    #define cJSON_True   (1 << 1)
    #define cJSON_NULL   (1 << 2)
    #define cJSON_Number (1 << 3)
    #define cJSON_String (1 << 4)
    #define cJSON_Array  (1 << 5)
    #define cJSON_Object (1 << 6)
    #define cJSON_Raw    (1 << 7) /* raw json */
    

    另外,如果是对象或者数组,采用的是双向链表来实现,链表中的每一个节点表示数组中的一个元素或者对象中的一个字段。其中child表示头结点,next、prev分别表示下一个节点和前一个节点。valuestring、valueint、valuedouble分别表示字符串、整数、浮点数的字面量。string表示对象中某一字段的名称,比如有这样的一个json字符串:

    {'age': 20}//'age'则用结构体中的string来表示。
    

    一、cjson常用函数

    用到的函数,在cJSON.h中都能找到:

    /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
    extern cJSON *cJSON_Parse(const char *value);//从 给定的json字符串中得到cjson对象
    /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
    extern char  *cJSON_Print(cJSON *item);//从cjson对象中获取有格式的json对象
    /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
    extern char  *cJSON_PrintUnformatted(cJSON *item);//从cjson对象中获取无格式的json对象
    
    /* Delete a cJSON entity and all subentities. */
    extern void   cJSON_Delete(cJSON *c);//删除cjson对象,释放链表占用的内存空间
    
    /* Returns the number of items in an array (or object). */
    extern int    cJSON_GetArraySize(cJSON *array);//获取cjson对象数组成员的个数
    /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
    extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);//根据下标获取cjosn对象数组中的对象
    /* Get item "string" from object. Case insensitive. */
    extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);//根据键获取对应的值(cjson对象)
    
    /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
    extern const char *cJSON_GetErrorPtr(void);//获取错误字符串
    

    二、cjson源码解析

    简单示例代码如下:

    char *out;cJSON *json;
        
    json=cJSON_Parse(text);
    if (!json) {
        printf("Error before: [%s]\n",cJSON_GetErrorPtr());
    } else {
        out=cJSON_Print(json);
        cJSON_Delete(json);
        printf("%s\n",out);
        free(out);
    }
    

    下面我们先来看一下json字符串的解析,json的字符串的解析主要是通过cJSON_Parse函数来完成,打开cJSON_Parse函数后,我们发现该函数使用了另外一个辅助函数:

    /* Default options for cJSON_Parse */
    CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
    {
        return cJSON_ParseWithOpts(value, 0, 0);
    }
    

    cJSON_ParseWithOpts提供了一些额外的参数选项:

    /* Parse an object - create a new root, and populate. */
    CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
    {
        parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
        cJSON *item = NULL;
    
        /* reset error position */
        global_error.json = NULL;
        global_error.position = 0;
    
        if (value == NULL)
        {
            goto fail;
        }
    
        buffer.content = (const unsigned char*)value;
        buffer.length = strlen((const char*)value) + sizeof("");
        buffer.offset = 0;
        buffer.hooks = global_hooks;
    
        item = cJSON_New_Item(&global_hooks);//创建一个节点,malloc分配一块内存,再将分配的内存初始化
        if (item == NULL) /* memory fail */
        {
            goto fail;
        }
    
        if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
        {
            /* parse failure. ep is set. */
            goto fail;
        }
    
        /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
        if (require_null_terminated)
        {
            buffer_skip_whitespace(&buffer);
            if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
            {
                goto fail;
            }
        }
        if (return_parse_end)
        {
            *return_parse_end = (const char*)buffer_at_offset(&buffer);
        }
    
        return item;
    
    fail:
        if (item != NULL)
        {
            cJSON_Delete(item);
        }
    
        if (value != NULL)
        {
            error local_error;
            local_error.json = (const unsigned char*)value;
            local_error.position = 0;
    
            if (buffer.offset < buffer.length)
            {
                local_error.position = buffer.offset;
            }
            else if (buffer.length > 0)
            {
                local_error.position = buffer.length - 1;
            }
    
            if (return_parse_end != NULL)
            {
                *return_parse_end = (const char*)local_error.json + local_error.position;
            }
    
            global_error = local_error;
        }
    
        return NULL;
    }
    

    第一步:先调用cJSON_New_Item创建一个节点,该函数实现非常简单,就是使用malloc分配一块内存,再将分配的内存使用0来进行初始化。

    /* Internal constructor. */
    
    #define internal_malloc malloc
    #define internal_free free
    #define internal_realloc realloc
    #endif
    
    static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
    //上方可从cJSON.c中查找到引用
    static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
    {
        cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
        if (node)
        {
            memset(node, '\0', sizeof(cJSON));
        }
    
        return node;
    }
    

    第二步:调用parse_value函数进行真正的解析,该函数是json解析的核心部分,后面我们会重点分析。而在解析前,先对json字符串调用了一次buffer_skip_whitespace,其实就是将字符串前面的的一些空字符去除,代码如下:

    /* Utility to jump whitespace and cr/lf */
    static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
    {
        if ((buffer == NULL) || (buffer->content == NULL))
        {
            return NULL;
        }
    
        while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
        {
           buffer->offset++;
        }
    
        if (buffer->offset == buffer->length)
        {
            buffer->offset--;
        }
    
        return buffer;
    }
    

    最后一步:函数中参数中提供了require_null_terminated是为了确保json字符串必须以'\0'字符作为结尾。若参数提供了return_parse_end,将返回json字符串解析完成后剩余的部分。

    下面来看json解析算法的核心部分:

    
    /* Parser core - when encountering text, process appropriately. */
    static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
    {
        if ((input_buffer == NULL) || (input_buffer->content == NULL))
        {
            return false; /* no input */
        }
    
        /*分析不同类型的值 */
        /* null */
        if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
        {
            item->type = cJSON_NULL;
            input_buffer->offset += 4;
            return true;
        }
        /* false */
        if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
        {
            item->type = cJSON_False;
            input_buffer->offset += 5;
            return true;
        }
        /* true */
        if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
        {
            item->type = cJSON_True;
            item->valueint = 1;
            input_buffer->offset += 4;
            return true;
        }
        /* string */
        if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
        {
            return parse_string(item, input_buffer);
        }
        /* number */
        if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
        {
            return parse_number(item, input_buffer);
        }
        /* array */
        if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
        {
            return parse_array(item, input_buffer);
        }
        /* object */
        if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
        {
            return parse_object(item, input_buffer);
        }
    
        return false;
    }
    
    

    上述 代码看上去应该清晰易懂。对于json为null、true或者false的情况,直接将type置为对应的类型即可。对于其他情况,需要分别再做处理,先来看json为字符串的情况:

        /* string */
        if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
        {
            return parse_string(item, input_buffer);
        }
    
    /* Parse the input text into an unescaped cinput, and populate item. */
    static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
    {
        const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
        const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
        unsigned char *output_pointer = NULL;
        unsigned char *output = NULL;
    
        /* not a string */
        if (buffer_at_offset(input_buffer)[0] != '\"')
        {
            goto fail;
        }
    
        {
        /* calculate approximate size of the output (overestimate) 
         * 这一步主要是为了确定字符串的长度,以便下一步进行内存分配
         * 问题在于字符串中可能存在一定的转义字符,由于json字符串本身
         * 是一个字符串,碰到像双引号必须进行转义,另外像\t这样的转义
         * 字符,需要再次转义,用\\t来表示。而在解析的时候,我们不需要
         * 这些多余的转义字符。(说得有点绕,不知道能不能看明白)
         */
            size_t allocation_length = 0;
            size_t skipped_bytes = 0;
            while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
            {
                /* is escape sequence */
                if (input_end[0] == '\\')
                {
                    if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
                    {
                        /* prevent buffer overflow when last input character is a backslash */
                        goto fail;
                    }
                    skipped_bytes++;
                    input_end++;
                }
                input_end++;
            }
            if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
            {
                goto fail; /* string ended unexpectedly */
            }
    
            /* This is at most how much we need for the output */
            allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
            output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
            if (output == NULL)
            {
                goto fail; /* allocation failure */
            }
        }
    
        output_pointer = output;
        /* loop through the string literal */
        while (input_pointer < input_end)
        {
            if (*input_pointer != '\\')
            {
                *output_pointer++ = *input_pointer++;
            }
            /* escape sequence */
            else
            {
                unsigned char sequence_length = 2;
                if ((input_end - input_pointer) < 1)
                {
                    goto fail;
                }
    
                switch (input_pointer[1])
                {
                    case 'b':
                        *output_pointer++ = '\b';
                        break;
                    case 'f':
                        *output_pointer++ = '\f';
                        break;
                    case 'n':
                        *output_pointer++ = '\n';
                        break;
                    case 'r':
                        *output_pointer++ = '\r';
                        break;
                    case 't':
                        *output_pointer++ = '\t';
                        break;
                    case '\"':
                    case '\\':
                    case '/':
                        *output_pointer++ = input_pointer[1];
                        break;
    
                    /* UTF-16 literal */
                    case 'u':
                        sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
                        if (sequence_length == 0)
                        {
                            /* failed to convert UTF16-literal to UTF-8 */
                            goto fail;
                        }
                        break;
    
                    default:
                        goto fail;
                }
                input_pointer += sequence_length;
            }
        }
    
        /* zero terminate the output */
        *output_pointer = '\0';
    
        item->type = cJSON_String;
        item->valuestring = (char*)output;
    
        input_buffer->offset = (size_t) (input_end - input_buffer->content);
        input_buffer->offset++;
    
        return true;
    
    fail:
        if (output != NULL)
        {
            input_buffer->hooks.deallocate(output);
        }
    
        if (input_pointer != NULL)
        {
            input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
        }
    
        return false;
    }
    

    下面是解析数值类型的代码:

    解析字符串的困难之处在于可能会碰到转义字符,需要将类似于\t这样的再转义字符转化为\t.

    下面是解析数值类型的代码:

    
    /* Parse the input text to generate a number, and populate the result into item. */
    static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
    {
        double number = 0;
        unsigned char *after_end = NULL;
        unsigned char number_c_string[64];
        unsigned char decimal_point = get_decimal_point();
        size_t i = 0;
    
        if ((input_buffer == NULL) || (input_buffer->content == NULL))
        {
            return false;
        }
    
        /* 将数字复制到临时缓冲区中,并将“.”替换为当前区域设置的小数点(对于strtod)
         * 这还需要注意“0”不一定用于标记输入的结尾。  
         */
        for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
        {
            switch (buffer_at_offset(input_buffer)[i])
            {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                case '+':
                case '-':
                case 'e':
                case 'E':
                    number_c_string[i] = buffer_at_offset(input_buffer)[i];
                    break;
    
                case '.':
                    number_c_string[i] = decimal_point;
                    break;
    
                default:
                    goto loop_end;
            }
        }
    loop_end:
        number_c_string[i] = '\0';
    
        number = strtod((const char*)number_c_string, (char**)&after_end);
        if (number_c_string == after_end)
        {
            return false; /* parse_error */
        }
    
        item->valuedouble = number;
    
        /* use saturation in case of overflow */
        if (number >= INT_MAX)
        {
            item->valueint = INT_MAX;
        }
        else if (number <= (double)INT_MIN)
        {
            item->valueint = INT_MIN;
        }
        else
        {
            item->valueint = (int)number;
        }
    
        item->type = cJSON_Number;
    
        input_buffer->offset += (size_t)(after_end - number_c_string);
        return true;
    }
    

    考虑了小数和指数的情况,会带来一定的复杂性。

    接下来是如何解析数组:

    /* Build an array from input text. */
    static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
    {
        cJSON *head = NULL; /* head of the linked list */
        cJSON *current_item = NULL;
    
        if (input_buffer->depth >= CJSON_NESTING_LIMIT)
        {
            return false; /* to deeply nested */
        }
        input_buffer->depth++;
    
        if (buffer_at_offset(input_buffer)[0] != '[')
        {
            /* 不是一个数组,直接返回 */
            goto fail;
        }
    
        input_buffer->offset++;
        buffer_skip_whitespace(input_buffer);//跳过前面的空白字符
        if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
        {
           /* 空数组 */
            goto success;
        }
    
        /* 检查是否跳过缓冲区结尾 */
        if (cannot_access_at_index(input_buffer, 0))
        {
            input_buffer->offset--;
            goto fail;
        }
    
        /* 返回到第一个元素前面的字符 */
        input_buffer->offset--;
        /* 循环遍历逗号分隔的数组元素  */
        do
        {
            /* allocate next item */
            cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
            if (new_item == NULL)
            {
                goto fail; /* allocation failure */
            }
    
            /* attach next item to list */
            if (head == NULL)
            {
                /* start the linked list */
                current_item = head = new_item;
            }
            else
            {
                /*放在child节点的尾部,形成一个链表 */
                current_item->next = new_item;
                new_item->prev = current_item;
                current_item = new_item;
            }
    
            /* parse next value */
            input_buffer->offset++;
            buffer_skip_whitespace(input_buffer);
            if (!parse_value(current_item, input_buffer))
            {
                goto fail; /* failed to parse value */
            }
            buffer_skip_whitespace(input_buffer);
        }
        while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
    
        if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
        {
            goto fail; /* 达到数组的尾部  */
        }
    
    success:
        input_buffer->depth--;
    
        item->type = cJSON_Array;
        item->child = head;
    
        input_buffer->offset++;
    
        return true;
    
    fail:
        if (head != NULL)
        {
            cJSON_Delete(head);
        }
    
        return false;
    }
    

    解析数组时,其基本思想是对数组中每一个元素递归调用parse_value,再将这些元素连接形成一个链表。

    如果能看懂数组的解析过程,对象的解析直接来看代码:

    /* Build an object from the text. */
    static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
    {
        cJSON *head = NULL; /* linked list head */
        cJSON *current_item = NULL;
    
        if (input_buffer->depth >= CJSON_NESTING_LIMIT)
        {
            return false; /* to deeply nested */
        }
        input_buffer->depth++;
    
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
        {
            goto fail; /*  不是一个对象,直接返回 */
        }
    
        input_buffer->offset++;
        buffer_skip_whitespace(input_buffer);
        if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
        {
            goto success; /* empty object */
        }
    
        /* 检查是否跳过缓冲区结尾 */
        if (cannot_access_at_index(input_buffer, 0))
        {
            input_buffer->offset--;
            goto fail;
        }
    
        /* 返回到第一个元素前面的字符 */
        input_buffer->offset--;
        /* 循环遍历逗号分隔的数组元素  */
        do
        {
            /* allocate next item */
            cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
            if (new_item == NULL)
            {
                goto fail; /* allocation failure */
            }
    
            /* attach next item to list */
            if (head == NULL)
            {
                /* start the linked list */
                current_item = head = new_item;
            }
            else
            {
                /* add to the end and advance */
                current_item->next = new_item;
                new_item->prev = current_item;
                current_item = new_item;
            }
    
            /* parse the name of the child */
            input_buffer->offset++;
            buffer_skip_whitespace(input_buffer);
            if (!parse_string(current_item, input_buffer))
            {
                goto fail; /* faile to parse name */
            }
            buffer_skip_whitespace(input_buffer);
    
            /* 交换valuestring和string,因为我们分析了名称 */
            current_item->string = current_item->valuestring;
            current_item->valuestring = NULL;
    
            if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
            {
                goto fail; /* invalid object */
            }
    
            /* parse the value */
            input_buffer->offset++;
            buffer_skip_whitespace(input_buffer);
            if (!parse_value(current_item, input_buffer))
            {
                goto fail; /* failed to parse value */
            }
            buffer_skip_whitespace(input_buffer);
        }
        while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
    
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
        {
            goto fail; /* expected end of object */
        }
    
    success:
        input_buffer->depth--;
    
        item->type = cJSON_Object;
        item->child = head;
    
        input_buffer->offset++;
        return true;
    
    fail:
        if (head != NULL)
        {
            cJSON_Delete(head);
        }
    
        return false;
    }
    

    客户端代码在使用完成后,需要将分配的内存释放掉:

    void cJSON_Delete(cJSON *c) {
        cJSON *next;
        while (c) { //循环删除链表中所有节点
            next = c->next;
            if (c->child) cJSON_Delete(c->child); //存在子节点,递归删除
            if (c->valuestring) cJSON_free(c->valuestring); 
            if (c->string) cJSON_free(c->string);
            cJSON_free(c); //删除结构体本身
            c = next;
        }
    }
    

    cJSON对于json字符串的解析基本就结束了。下篇文章我会进行简单的代码示例,进行展示cJSON的用法与封装。

    相关文章

      网友评论

        本文标题:JSON的简单介绍&cJSON库使用(一)

        本文链接:https://www.haomeiwen.com/subject/kmibmqtx.html