JSON WIKI解釋:
JSON(JavaScript Object Notation蛉鹿,JavaScript對象表示法)是一種由道格拉斯·克羅克福特構(gòu)想和設(shè)計、輕量級的數(shù)據(jù)交換語言趾盐,該語言以易于讓人閱讀的文字為基礎(chǔ),用來傳輸由屬性值或者序列性的值組成的數(shù)據(jù)對象衩藤。盡管JSON是JavaScript的一個子集阐枣,但JSON是獨立于語言的文本格式甫贯,并且采用了類似于C語言家族的一些習(xí)慣吼鳞。
JSON 數(shù)據(jù)格式與語言無關(guān),脫胎自JavaScript叫搁,但當(dāng)前很多編程語言都支持 JSON 格式數(shù)據(jù)的生成和解析赔桌。JSON 的官方 MIME 類型是 application/json
,文件擴展名是 .json
渴逻。
JSON 解析器和 JSON 庫支持許多不同的編程語言疾党。 JSON 文本格式在語法上與創(chuàng)建 JavaScript 對象的代碼相同。 由于這種相似性惨奕, 無需解析器雪位, JavaScript 程序能夠使用內(nèi)建的 eval() 函數(shù), 用 JSON 數(shù)據(jù)來生成原生的 JavaScript 對象梨撞。
JSON 是存儲和交換文本信息的語法雹洗。 類似 XML。 JSON 比 XML 更小聋袋、 更快队伟, 更易解析穴吹。
JSON 具有自我描述性幽勒, 語法簡潔, 易于理解港令。
JSON建構(gòu)于兩種結(jié)構(gòu):
“名稱/值”對的集合(A collection of name/value pairs)啥容。不同的語言中锈颗,它被理解為對象(object),紀錄(record)咪惠,結(jié)構(gòu)(struct)击吱,字典(dictionary),哈希表(hash table)遥昧,有鍵列表(keyed list)覆醇,或者關(guān)聯(lián)數(shù)組 (associative array)。
值的有序列表(An ordered list of values)炭臭。在大部分語言中永脓,它被理解為數(shù)組(array)。
JSON的三種語法:
鍵/值對 key:value鞋仍,用半角冒號分割常摧。 比如 "name":"Faye" 文檔對象 JSON對象寫在花括號中,可以包含多個鍵/值對威创。比如{ "name":"Faye" ,"address":"北京" }
落午。 數(shù)組 JSON 數(shù)組在方括號中書寫: 數(shù)組成員可以是對象,值肚豺,也可以是數(shù)組(只要有意義)溃斋。{"love": ["乒乓球","高爾夫","斯諾克","羽毛球","LOL","撩妹"]}
cJSON是C語言中的一個JSON編解碼器,非常輕量級详炬,C文件只有不到一千行盐类,代碼的可讀性也很好,很適合作為C語言項目進行學(xué)習(xí)呛谜。
項目主頁
項目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的數(shù)據(jù)結(jié)構(gòu):
/* 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;
不管是數(shù)值類型隐岛、字符串類型或者對象類型等都使用該結(jié)構(gòu)體猫妙,類型信息通過標識符 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 */
另外聚凹,如果是對象或者數(shù)組割坠,采用的是雙向鏈表來實現(xiàn),鏈表中的每一個節(jié)點表示數(shù)組中的一個元素或者對象中的一個字段妒牙。其中child表示頭結(jié)點彼哼,next、prev分別表示下一個節(jié)點和前一個節(jié)點湘今。valuestring敢朱、valueint、valuedouble分別表示字符串、整數(shù)拴签、浮點數(shù)的字面量孝常。string表示對象中某一字段的名稱,比如有這樣的一個json字符串:
{'age': 20}//'age'則用結(jié)構(gòu)體中的string來表示蚓哩。
一构灸、cjson常用函數(shù)
用到的函數(shù),在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對象岸梨,釋放鏈表占用的內(nèi)存空間
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(cJSON *array);//獲取cjson對象數(shù)組成員的個數(shù)
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);//根據(jù)下標獲取cjosn對象數(shù)組中的對象
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);//根據(jù)鍵獲取對應(yīng)的值(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函數(shù)來完成曹阔,打開cJSON_Parse函數(shù)后洛巢,我們發(fā)現(xiàn)該函數(shù)使用了另外一個輔助函數(shù):
/* Default options for cJSON_Parse */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
{
return cJSON_ParseWithOpts(value, 0, 0);
}
cJSON_ParseWithOpts提供了一些額外的參數(shù)選項:
/* 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);//創(chuàng)建一個節(jié)點,malloc分配一塊內(nèi)存次兆,再將分配的內(nèi)存初始化
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;
}
第一步:先調(diào)用cJSON_New_Item創(chuàng)建一個節(jié)點稿茉,該函數(shù)實現(xiàn)非常簡單,就是使用malloc分配一塊內(nèi)存芥炭,再將分配的內(nèi)存使用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;
}
第二步:調(diào)用parse_value函數(shù)進行真正的解析,該函數(shù)是json解析的核心部分园蝠,后面我們會重點分析渺蒿。而在解析前,先對json字符串調(diào)用了一次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;
}
最后一步:函數(shù)中參數(shù)中提供了require_null_terminated是為了確保json字符串必須以'\0'字符作為結(jié)尾。若參數(shù)提供了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;
}
上述 代碼看上去應(yīng)該清晰易懂。對于json為null易遣、true或者false的情況彼妻,直接將type置為對應(yīng)的類型即可。對于其他情況豆茫,需要分別再做處理侨歉,先來看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)
* 這一步主要是為了確定字符串的長度,以便下一步進行內(nèi)存分配
* 問題在于字符串中可能存在一定的轉(zhuǎn)義字符揩魂,由于json字符串本身
* 是一個字符串幽邓,碰到像雙引號必須進行轉(zhuǎn)義,另外像\t這樣的轉(zhuǎn)義
* 字符火脉,需要再次轉(zhuǎn)義牵舵,用\\t來表示茅特。而在解析的時候,我們不需要
* 這些多余的轉(zhuǎn)義字符棋枕。(說得有點繞,不知道能不能看明白)
*/
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;
}
下面是解析數(shù)值類型的代碼:
解析字符串的困難之處在于可能會碰到轉(zhuǎn)義字符妒峦,需要將類似于\t這樣的再轉(zhuǎn)義字符轉(zhuǎn)化為\t.
下面是解析數(shù)值類型的代碼:
/* 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;
}
/* 將數(shù)字復(fù)制到臨時緩沖區(qū)中重斑,并將“.”替換為當(dāng)前區(qū)域設(shè)置的小數(shù)點(對于strtod)
* 這還需要注意“0”不一定用于標記輸入的結(jié)尾。
*/
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;
}
考慮了小數(shù)和指數(shù)的情況肯骇,會帶來一定的復(fù)雜性窥浪。
接下來是如何解析數(shù)組:
/* 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] != '[')
{
/* 不是一個數(shù)組,直接返回 */
goto fail;
}
input_buffer->offset++;
buffer_skip_whitespace(input_buffer);//跳過前面的空白字符
if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
{
/* 空數(shù)組 */
goto success;
}
/* 檢查是否跳過緩沖區(qū)結(jié)尾 */
if (cannot_access_at_index(input_buffer, 0))
{
input_buffer->offset--;
goto fail;
}
/* 返回到第一個元素前面的字符 */
input_buffer->offset--;
/* 循環(huán)遍歷逗號分隔的數(shù)組元素 */
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節(jié)點的尾部笛丙,形成一個鏈表 */
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; /* 達到數(shù)組的尾部 */
}
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;
}
解析數(shù)組時漾脂,其基本思想是對數(shù)組中每一個元素遞歸調(diào)用parse_value,再將這些元素連接形成一個鏈表胚鸯。
如果能看懂?dāng)?shù)組的解析過程骨稿,對象的解析直接來看代碼:
/* 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 */
}
/* 檢查是否跳過緩沖區(qū)結(jié)尾 */
if (cannot_access_at_index(input_buffer, 0))
{
input_buffer->offset--;
goto fail;
}
/* 返回到第一個元素前面的字符 */
input_buffer->offset--;
/* 循環(huán)遍歷逗號分隔的數(shù)組元素 */
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;
}
客戶端代碼在使用完成后坦冠,需要將分配的內(nèi)存釋放掉:
void cJSON_Delete(cJSON *c) {
cJSON *next;
while (c) { //循環(huán)刪除鏈表中所有節(jié)點
next = c->next;
if (c->child) cJSON_Delete(c->child); //存在子節(jié)點,遞歸刪除
if (c->valuestring) cJSON_free(c->valuestring);
if (c->string) cJSON_free(c->string);
cJSON_free(c); //刪除結(jié)構(gòu)體本身
c = next;
}
}
cJSON對于json字符串的解析基本就結(jié)束了哥桥。下篇文章我會進行簡單的代碼示例辙浑,進行展示cJSON的用法與封裝。