> 脚本语言 > >
从零开始的JSON库教程(五):解析数组解答篇 2016-10-14 11:25 出处:清屏网 人气:
本文是 《从零开始的 JSON 库教程》 的第五个单元解答篇。解答代码位于 json-tutorial/tutorial05_answer 。
1. 编写 test_parse_array() 单元测试这个练习纯粹为了熟习数组的访问 API。新增的第一个 JSON 只需平凡的检测。第二个 JSON 有特定模式,第 i 个子数组的长度为 i,每个子数组的第 j 个元素是数字值 j,所以可用两层 for 循环测试。
static void test_parse_array() { size_t i, j; lept_value v; /* ... */ lept_init(&v); EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ null , false , true , 123 , \"abc\" ]")); EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(&v)); EXPECT_EQ_SIZE_T(5, lept_get_array_size(&v)); EXPECT_EQ_INT(LEPT_NULL, lept_get_type(lept_get_array_element(&v, 0))); EXPECT_EQ_INT(LEPT_FALSE, lept_get_type(lept_get_array_element(&v, 1))); EXPECT_EQ_INT(LEPT_TRUE, lept_get_type(lept_get_array_element(&v, 2))); EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(lept_get_array_element(&v, 3))); EXPECT_EQ_INT(LEPT_STRING, lept_get_type(lept_get_array_element(&v, 4))); EXPECT_EQ_DOUBLE(123.0, lept_get_number(lept_get_array_element(&v, 3))); EXPECT_EQ_STRING("abc", lept_get_string(lept_get_array_element(&v, 4)), lept_get_string_length(lept_get_array_element(&v, 4))); lept_free(&v); lept_init(&v); EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "[ [ ] , [ 0 ] , [ 0 , 1 ] , [ 0 , 1 , 2 ] ]")); EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(&v)); EXPECT_EQ_SIZE_T(4, lept_get_array_size(&v)); for (i = 0; i < 4; i++) { lept_value* a = lept_get_array_element(&v, i); EXPECT_EQ_INT(LEPT_ARRAY, lept_get_type(a)); EXPECT_EQ_SIZE_T(i, lept_get_array_size(a)); for (j = 0; j < i; j++) { lept_value* e = lept_get_array_element(a, j); EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(e)); EXPECT_EQ_DOUBLE((double)j, lept_get_number(e)); } } lept_free(&v); } 2. 解析空白字符按现时的 lept_parse_array() 的编写方式,需要加入 3 个 lept_parse_whitespace() 调用,分别是解析 [ 之后,元素之后,以及 , 之后:
static int lept_parse_array(lept_context* c, lept_value* v) { /* ... */ EXPECT(c, '['); lept_parse_whitespace(c); /* ... */ for (;;) { /* ... */ if ((ret = lept_parse_value(c, &e)) != LEPT_PARSE_OK) return ret; /* ... */ lept_parse_whitespace(c); if (*c->json == ',') { c->json++; lept_parse_whitespace(c); } /* ... */ } } 3. 内存泄漏成功测试那 3 个 JSON 后,使用内存泄漏检测工具会发现 lept_parse_array() 用 malloc()分配的内存没有被释放:
==154== 124 (120 direct, 4 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 4 ==154== at 0x4C28C20: malloc (vg_replace_malloc.c:296) ==154== by 0x409D82: lept_parse_array (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x409E91: lept_parse_value (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x409F14: lept_parse (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x405261: test_parse_array (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x408C72: test_parse (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x40916A: main (in /json-tutorial/tutorial05/build/leptjson_test) ==154== ==154== 240 (96 direct, 144 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4 ==154== at 0x4C28C20: malloc (vg_replace_malloc.c:296) ==154== by 0x409D82: lept_parse_array (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x409E91: lept_parse_value (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x409F14: lept_parse (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x40582C: test_parse_array (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x408C72: test_parse (in /json-tutorial/tutorial05/build/leptjson_test) ==154== by 0x40916A: main (in /json-tutorial/tutorial05/build/leptjson_test)很明显,有 malloc() 就要有对应的 free()。正确的释放位置应该放置在 lept_free(),当值被释放时,该值拥有的内存也在那里释放。之前字符串的释放也是放在这里:
void lept_free(lept_value* v) { assert(v != NULL); if (v->type == LEPT_STRING) free(v->u.s.s); v->type = LEPT_NULL; }