Zero-based learning cJSON source code detailed explanation and application (2) create json data

cJSON series:

In the previous article, we have introduced the cjson structure (1) how to learn cJSON , this section introduces the simple creation of json data and analysis of the source code.

One, create a simple json

For example, create a json as follows:

{
    
    
    "years": 22,
    "name": "fool",
    "man": true,
    "adult": false,
    "money": null,
    "season": ["spring", "summer", "fall","winter"],
    "child": {
    
    
        "girlfriend": "june"
    }
}

First analyze this json to determine all its item types. One thing to note is that the child item is a nested child json, so its type should be object . Starting from the item type, create all items first, and then The item is added to the root node. code show as below:

    char *str_arry[3] = 
    {
    
    
        "spring",
        "summer",
        "fall",
        "winter"
    };
    //创建不同类型的item
    cJSON *root = cJSON_CreateObject();
    cJSON *years = cJSON_CreateNumber(22);
    cJSON *name = cJSON_CreateString("fool");
    cJSON *man = cJSON_CreateTrue();
    cJSON *adult = cJSON_CreateFalse();
    cJSON *money = cJSON_CreateNull();
    cJSON *season = cJSON_CreateStringArray(str_arry, 3);
    cJSON *child = cJSON_CreateObject();
    cJSON *girlfriend = cJSON_CreateString("june");

    //将item添加到父节点下
    cJSON_AddItemToObject(root, "years", years);
    cJSON_AddItemToObject(root, "name", name);
    cJSON_AddItemToObject(root, "man", man);
    cJSON_AddItemToObject(root, "adult", adult);
    cJSON_AddItemToObject(root, "money", money);
    cJSON_AddItemToObject(root, "season", season);
    cJSON_AddItemToObject(child, "girlfriend", girlfriend);
    cJSON_AddItemToObject(root, "child", child);

    //将所有json结构体输出成字符串
    char *json=cJSON_Print(root);

    printf("%s\n",json);

    //! 一定要记得用完擦屁股
    cJSON_Delete(root);

It should be noted that due to the use of dynamic memory allocation is cjson when cjson exhausted, 切记!切记!切记!一定用要用cJSON_Delete释放内存.

The print result is as follows:

Insert picture description here

Second, the source code is explained in detail

1, CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);

//创建一个空的json,赋予obj类型
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
{
    
    
    cJSON *item = cJSON_New_Item(&global_hooks);
    if (item)
    {
    
    
        item->type = cJSON_Object;
    }

    return item;
}

This function calls cJSON_New_Item(), and the incoming parameter &global_hooks is a global variable. The variable is pointed to by three function pointers free(),malloc(),realloc()to manipulate memory.
cJSON_New_Item() applies for a piece of memory and initializes the memory in the form of dynamic memory allocation. Return a pointer to the memory.

//动态内存分配一个cjson并设为0
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;
}

2, CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);

//创建字符串值为string的json,string值可被cjson_delete删除
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
{
    
    
    //创建空cjson
    cJSON *item = cJSON_New_Item(&global_hooks);
    if(item)
    {
    
    
        item->type = cJSON_String;
        //将string内容复制给valuestring
        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
        if(!item->valuestring)
        {
    
    
            cJSON_Delete(item);
            return NULL;
        }
    }

    return item;
}

cJSON_strdup() is also a function that will be used frequently in the future, and its role is to copy strings.

//开辟一块新内存,并将string复制到内存中,并返回指向内存的指针
static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
{
    
    
    size_t length = 0;
    unsigned char *copy = NULL;

    if (string == NULL)
    {
    
    
        return NULL;
    }
    //计算所需内存的长度
    length = strlen((const char*)string) + sizeof("");
    //申请内存
    copy = (unsigned char*)hooks->allocate(length);
    if (copy == NULL)
    {
    
    
        return NULL;
    }
    memcpy(copy, string, length);

    return copy;
}

3,CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);

/*
 * 创建字符串型数组的json
 * strings:字符串数组
 * count:数组长度
 * 返回:数组
 */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
{
    
    
    size_t i = 0;
    cJSON *n = NULL;    //next
    cJSON *p = NULL;    //prev
    cJSON *a = NULL;    //arry

    if ((count < 0) || (strings == NULL))
    {
    
    
        return NULL;
    }

    //创建数组
    a = cJSON_CreateArray();

    for (i = 0; a && (i < (size_t)count); i++)
    {
    
    
        //创建string类型cjson
        n = cJSON_CreateString(strings[i]);
        if(!n)
        {
    
    
            cJSON_Delete(a);
            return NULL;
        }
        if(!i)
        {
    
    
            //如果是数组第一个,则将n复制给数组cjson的子节点
            a->child = n;
        }
        else
        {
    
    
            //将n插入p之后(链表操作)
            suffix_object(p,n);
        }
        p = n;
    }

    return a;
}

4,CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);

cJSON_AddItemToObject() is calledadd_item_to_object()

/*
 * 将item以键string添加到obj下
 * note:item可以是任何类型的cjson
 * constant_key:指示string是否是外部定义的常量数据
 * 成功:返回 true
 */
static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
{
    
    
    char *new_key = NULL;
    int new_type = cJSON_Invalid;

    if ((object == NULL) || (string == NULL) || (item == NULL))
    {
    
    
        return false;
    }

    //判断key是否是常量数据,若是则不需要重新复制字符串
    if (constant_key)
    {
    
    
        //直接取指针,cjson_delete不会删除key
        new_key = (char*)cast_away_const(string);
        //cjson类型设置为常量字符串
        new_type = item->type | cJSON_StringIsConst;
    }
    else
    {
    
    
        //复制string
        new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
        if (new_key == NULL)
        {
    
    
            return false;
        }
        //修改cjson类型
        new_type = item->type & ~cJSON_StringIsConst;
    }

    if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
    {
    
    
        //如果string是常量且不为空则释放内存
        hooks->deallocate(item->string);
    }

	//将key赋值给cjson的键
    item->string = new_key;
    item->type = new_type;

    //最后把item添加到obj
    return add_item_to_array(object, item);
}

At the end add_item_to_array() is called;

/*
 * 添加item到数组最后
 * 成功返回 true
 */
static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
{
    
    
    cJSON *child = NULL;

    if ((item == NULL) || (array == NULL))
    {
    
    
        return false;
    }

    //child是数组的第一个成员
    child = array->child;

    //如果数组为空,则item赋予第一个成员child
    if (child == NULL)
    {
    
    
        /* list is empty, start new one */
        array->child = item;
    }
    else
    {
    
    
        /* append to the end */
        //遍历数组,并在数组最后插入item
        while (child->next)
        {
    
    
            child = child->next;
        }
        suffix_object(child, item);
    }

    return true;
}

5,CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);

/*
 * 将item所在链表的及其子节点的所有cjson释放
 */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
{
    
    
    cJSON *next = NULL; //指向当前cjson的下一个
    
    
    while (item != NULL)
    {
    
    
        //由json结构体的定义可知,json结构体自身,string和valuestring是由动态内存分配获得,需要释放这三部分内存
        next = item->next;
        //如果cjson不是参考外部数据且不为空,则递归调用delete,删除cjson的子节点
        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
        {
    
    
            //释放嵌套的json结构体
            cJSON_Delete(item->child);
        }
        //如果cjson不是参考外部数据,则valuestring以及string是由cJSON动态内存分配的,需要释放内存
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
        {
    
    
            global_hooks.deallocate(item->valuestring);
        }
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
        {
    
    
            global_hooks.deallocate(item->string);
        }
        //释放当前的cjson
        global_hooks.deallocate(item);
        //准备释放链表中的下一个cjson
        item = next;
    }
}

deallocate(); can be analogous to free();
What needs to be noted here is that when releasing the memory, it is necessary to judge whether the string and valuesstring of the cjson structure are constants.

When string and valuesstring are dynamically allocated, they can be released using deallocate(), otherwise a memory error may occur. See the next section for specific reasons

Three pay attention to const, reference

The above code you will find that some functions will appear const, reference, which is cjson allows the use of external variables defined as a member of the cjson structure. In this case, the string needs to be modified with const, and the structure is modified with reference.

For cJSON_CreateString()example, when valuestringassigning a value, a piece of memory is used in the form of dynamic memory allocation, and the incoming parameter string is copied to the memory. After that, how the parameter string changes has no effect on the item's valuestring.

For comparison, take cJSON_CreateStringReference()an example:
In this function, the system does not valuestringallocate memory, but just points it tostring

/*
 * 创建一个string类型的item,其valuestring指向传入参数string,外部定义的string发生变化会影响item的valuestring
 */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
{
    
    
    cJSON *item = cJSON_New_Item(&global_hooks);
    if (item != NULL)
    {
    
    
        item->type = cJSON_String | cJSON_IsReference;
        item->valuestring = (char*)cast_away_const(string);
    }

    return item;
}

One aspect of the purpose of this is to save memory, but when using it, you need to pay attention to the value of the reference variable not to be easily modified. The functions of other reference classes are the same, but the reference variable is different.

CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);

CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);

CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);

As a result: when deleting an item, it is necessary to determine whether its pointer is an externally defined variable to determine whether to use the memory release function.

Four simpler creation of cjson

When you are familiar with cjson's idea of ​​creating json, you can create cjson in the following faster way:

    cJSON_AddNullToObject(root, "money");
    cJSON_AddTrueToObject(root, "man");
    cJSON_AddFalseToObject(root, "adult");
    cJSON_AddNumberToObject(root, "years", 22);
    cJSON_AddStringToObject(root, "name", "fool");

    cJSON *season = cJSON_CreateStringArray(str_arry, 3);
    cJSON_AddItemToObject(root, "season", season);
    
    cJSON *child = cJSON_AddObjectToObject(root, "child");
    cJSON_AddStringToObject(child, "girlfriend", "june");

CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);

It can be seen that this function essentially calls the AND mentioned above cJSON_CreateString();in add_item_to_object();two steps and takes one step.

/*
 * 添加string类型cjson到obj
 * name :键
 * string:值
 * 成功返回:string类cjson
 */
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
{
    
    
    cJSON *string_item = cJSON_CreateString(string);
    if (add_item_to_object(object, name, string_item, &global_hooks, false))
    {
    
    
        return string_item;
    }

    cJSON_Delete(string_item);
    return NULL;
}

summary

Familiar with the creation of json, and have a deeper grasp of the corresponding relationship between json and cjson structure, the next chapter will parse cJSON_Print(); output json.
Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_44821644/article/details/110406265