Skip to content

Commit

Permalink
Update All: Rplace http urls with https urls
Browse files Browse the repository at this point in the history
  • Loading branch information
imba-tjd committed Sep 3, 2018
1 parent c80b095 commit 858db91
Show file tree
Hide file tree
Showing 7 changed files with 15 additions and 15 deletions.
8 changes: 4 additions & 4 deletions tutorial01/tutorial01.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

## JSON 是什么

JSON(JavaScript Object Notation)是一个用于数据交换的文本格式,现时的标准为[ECMA-404](http:https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf)
JSON(JavaScript Object Notation)是一个用于数据交换的文本格式,现时的标准为[ECMA-404](https:https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf)

虽然 JSON 源至于 JavaScript 语言,但它只是一种数据格式,可用于任何编程语言。现时具类似功能的格式有 XML、YAML,当中以 JSON 的语法最为简单。

Expand Down Expand Up @@ -90,7 +90,7 @@ JSON(JavaScript Object Notation)是一个用于数据交换的文本格式

按 Configure,选择编译器,然后按 Generate 便会生成 Visual Studio 的 .sln 和 .vcproj 等文件。注意这个 build 目录都是生成的文件,可以随时删除,也不用上传至仓库。

在 OS X 下,建议安装 [Homebrew](http:https://brew.sh/),然后在命令行键入:
在 OS X 下,建议安装 [Homebrew](https:https://brew.sh/),然后在命令行键入:

~~~
$ brew install cmake
Expand Down Expand Up @@ -226,7 +226,7 @@ true = "true"
许多同学在做练习题时,都是以 `printf`/`cout` 打印结果,再用肉眼对比结果是否乎合预期。但当软件项目越来越复杂,这个做法会越来越低效。一般我们会采用自动的测试方式,例如单元测试(unit testing)。单元测试也能确保其他人修改代码后,原来的功能维持正确(这称为回归测试/regression testing)。
常用的单元测试框架有 xUnit 系列,如 C++ 的 [Google Test](https://github.com/google/googletest)、C# 的 [NUnit](http:https://www.nunit.org/)。我们为了简单起见,会编写一个极简单的单元测试方式。
常用的单元测试框架有 xUnit 系列,如 C++ 的 [Google Test](https://github.com/google/googletest)、C# 的 [NUnit](https:https://www.nunit.org/)。我们为了简单起见,会编写一个极简单的单元测试方式。
一般来说,软件开发是以周期进行的。例如,加入一个功能,再写关于该功能的单元测试。但也有另一种软件开发方法论,称为测试驱动开发(test-driven development, TDD),它的主要循环步骤是:
Expand Down Expand Up @@ -423,7 +423,7 @@ static int lept_parse_value(lept_context* c, lept_value* v) {

断言(assertion)是 C 语言中常用的防御式编程方式,减少编程错误。最常用的是在函数开始的地方,检测所有参数。有时候也可以在调用函数后,检查上下文是否正确。

C 语言的标准库含有 [`assert()`](http:https://en.cppreference.com/w/c/error/assert) 这个宏(需 `#include <assert.h>`),提供断言功能。当程序以 release 配置编译时(定义了 `NDEBUG` 宏),`assert()` 不会做检测;而当在 debug 配置时(没定义 `NDEBUG` 宏),则会在运行时检测 `assert(cond)` 中的条件是否为真(非 0),断言失败会直接令程序崩溃。
C 语言的标准库含有 [`assert()`](https:https://en.cppreference.com/w/c/error/assert) 这个宏(需 `#include <assert.h>`),提供断言功能。当程序以 release 配置编译时(定义了 `NDEBUG` 宏),`assert()` 不会做检测;而当在 debug 配置时(没定义 `NDEBUG` 宏),则会在运行时检测 `assert(cond)` 中的条件是否为真(非 0),断言失败会直接令程序崩溃。

例如上面的 `lept_parse_null()` 开始时,当前字符应该是 `'n'`,所以我们使用一个宏 `EXPECT(c, ch)` 进行断言,并跳到下一字符。

Expand Down
8 changes: 4 additions & 4 deletions tutorial02/tutorial02.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ number 是以十进制表示,它主要由 4 部分顺序组成:负号、整

JSON 可使用科学记数法,指数部分由大写 E 或小写 e 开始,然后可有正负号,之后是一或多个数字(0-9)。

JSON 标准 [ECMA-404](http:https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf) 采用图的形式表示语法,也可以更直观地看到解析时可能经过的路径:
JSON 标准 [ECMA-404](https:https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf) 采用图的形式表示语法,也可以更直观地看到解析时可能经过的路径:

![number](images/number.png)

Expand Down Expand Up @@ -151,7 +151,7 @@ static void test_parse_invalid_value() {

# 5. 十进制转换至二进制

我们需要把十进制的数字转换成二进制的 `double`。这并不是容易的事情 [2]。为了简单起见,leptjson 将使用标准库的 [`strtod()`](http:https://en.cppreference.com/w/c/string/byte/strtof) 来进行转换。`strtod()` 可转换 JSON 所要求的格式,但问题是,一些 JSON 不容许的格式,`strtod()` 也可转换,所以我们需要自行做格式校验。
我们需要把十进制的数字转换成二进制的 `double`。这并不是容易的事情 [2]。为了简单起见,leptjson 将使用标准库的 [`strtod()`](https:https://en.cppreference.com/w/c/string/byte/strtof) 来进行转换。`strtod()` 可转换 JSON 所要求的格式,但问题是,一些 JSON 不容许的格式,`strtod()` 也可转换,所以我们需要自行做格式校验。

~~~c
#include <stdlib.h> /* NULL, strtod() */
Expand Down Expand Up @@ -201,7 +201,7 @@ static int lept_parse_value(lept_context* c, lept_value* v) {
1. 重构合并 `lept_parse_null()``lept_parse_false()``lept_parse_true``lept_parse_literal()`
2. 加入 [维基百科双精度浮点数](https://en.wikipedia.org/wiki/Double-precision_floating-point_format#Double-precision_examples) 的一些边界值至单元测试,如 min subnormal positive double、max double 等。
3. 去掉 `test_parse_invalid_value()``test_parse_root_not_singular` 中的 `#if 0 ... #endif`,执行测试,证实测试失败。按 JSON number 的语法在 lept_parse_number() 校验,不符合标准的程况返回 `LEPT_PARSE_INVALID_VALUE` 错误码。
4. 去掉 `test_parse_number_too_big` 中的 `#if 0 ... #endif`,执行测试,证实测试失败。仔细阅读 [`strtod()`](http:https://en.cppreference.com/w/c/string/byte/strtof),看看怎样从返回值得知数值是否过大,以返回 `LEPT_PARSE_NUMBER_TOO_BIG` 错误码。(提示:这里需要 `#include` 额外两个标准库头文件。)
4. 去掉 `test_parse_number_too_big` 中的 `#if 0 ... #endif`,执行测试,证实测试失败。仔细阅读 [`strtod()`](https:https://en.cppreference.com/w/c/string/byte/strtof),看看怎样从返回值得知数值是否过大,以返回 `LEPT_PARSE_NUMBER_TOO_BIG` 错误码。(提示:这里需要 `#include` 额外两个标准库头文件。)

以上最重要的是第 3 条题目,就是要校验 JSON 的数字语法。建议可使用以下两个宏去简化一下代码:

Expand All @@ -228,6 +228,6 @@ static int lept_parse_value(lept_context* c, lept_value* v) {

2. 科学计数法的指数部分没有对前导零作限制吗?`1E012` 也是合法的吗?

是的,这是合法的。JSON 源自于 JavaScript([ECMA-262, 3rd edition](http:https://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf)),数字语法取自 JavaScript 的十进位数字的语法(§7.8.3 Numeric Literals)。整数不容许前导零(leading zero),是因为更久的 JavaScript 版本容许以前导零来表示八进位数字,如 `052 == 42`,这种八进位常数表示方式来自于 [C 语言](http:https://en.cppreference.com/w/c/language/integer_constant)。禁止前导零避免了可能出现的歧义。但是在指数里就不会出现这个问题。多谢 @Smallay 提出及协助解答这个问题。
是的,这是合法的。JSON 源自于 JavaScript([ECMA-262, 3rd edition](https:https://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf)),数字语法取自 JavaScript 的十进位数字的语法(§7.8.3 Numeric Literals)。整数不容许前导零(leading zero),是因为更久的 JavaScript 版本容许以前导零来表示八进位数字,如 `052 == 42`,这种八进位常数表示方式来自于 [C 语言](https:https://en.cppreference.com/w/c/language/integer_constant)。禁止前导零避免了可能出现的歧义。但是在指数里就不会出现这个问题。多谢 @Smallay 提出及协助解答这个问题。

其他常见问答将会从评论中整理。
2 changes: 1 addition & 1 deletion tutorial02_answer/tutorial02_answer.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ static int lept_parse_number(lept_context* c, lept_value* v) {
}
~~~
许多时候课本/书籍也不会把每个标准库功能说得很仔细,我想藉此提醒同学要好好看参考文档,学会读文档编程就简单得多![cppreference.com](http:https://cppreference.com) 是 C/C++ 程序员的宝库。
许多时候课本/书籍也不会把每个标准库功能说得很仔细,我想藉此提醒同学要好好看参考文档,学会读文档编程就简单得多![cppreference.com](https:https://cppreference.com) 是 C/C++ 程序员的宝库。
## 5. 总结
Expand Down
2 changes: 1 addition & 1 deletion tutorial03/tutorial03.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ static void* lept_context_pop(lept_context* c, size_t size) {

压入时若空间不足,便回以 1.5 倍大小扩展。为什么是 1.5 倍而不是两倍?可参考我在 [STL 的 vector 有哪些封装上的技巧?](https://www.zhihu.com/question/25079705/answer/30030883) 的答案。

注意到这里使用了 [`realloc()`](http:https://en.cppreference.com/w/c/memory/realloc) 来重新分配内存,`c->stack` 在初始化时为 `NULL``realloc(NULL, size)` 的行为是等价于 `malloc(size)` 的,所以我们不需要为第一次分配内存作特别处理。
注意到这里使用了 [`realloc()`](https:https://en.cppreference.com/w/c/memory/realloc) 来重新分配内存,`c->stack` 在初始化时为 `NULL``realloc(NULL, size)` 的行为是等价于 `malloc(size)` 的,所以我们不需要为第一次分配内存作特别处理。

另外,我们把初始大小以宏 `LEPT_PARSE_STACK_INIT_SIZE` 的形式定义,使用 `#ifndef X #define X ... #endif` 方式的好处是,使用者可在编译选项中自行设置宏,没设置的话就用缺省值。

Expand Down
2 changes: 1 addition & 1 deletion tutorial03_answer/tutorial03_answer.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Object dump complete.

## 1B. Linux/OSX 下的内存泄漏检测方法

在 Linux、OS X 下,我们可以使用 [valgrind](http:https://valgrind.org/) 工具(用 `apt-get install valgrind``brew install valgrind`)。我们完全不用修改代码,只要在命令行执行:
在 Linux、OS X 下,我们可以使用 [valgrind](https:https://valgrind.org/) 工具(用 `apt-get install valgrind``brew install valgrind`)。我们完全不用修改代码,只要在命令行执行:

~~~
$ valgrind --leak-check=full ./leptjson_test
Expand Down
2 changes: 1 addition & 1 deletion tutorial04_answer/tutorial04_answer.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static const char* lept_parse_hex4(const char* p, unsigned* u) {
}
~~~
可能有同学想到用标准库的 [`strtol()`](http:https://en.cppreference.com/w/c/string/byte/strtol),因为它也能解析 16 进制数字,那么可以简短的写成:
可能有同学想到用标准库的 [`strtol()`](https:https://en.cppreference.com/w/c/string/byte/strtol),因为它也能解析 16 进制数字,那么可以简短的写成:
~~~c
static const char* lept_parse_hex4(const char* p, unsigned* u) {
Expand Down
6 changes: 3 additions & 3 deletions tutorial06/tutorial06.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ object = %x7B ws [ member *( ws %x2C ws member ) ] ws %x7D

要表示键值对的集合,有很多数据结构可供选择,例如:

* 动态数组(dynamic array):可扩展容量的数组,如 C++ 的 [`std::vector`](http:https://en.cppreference.com/w/cpp/container/vector)
* 动态数组(dynamic array):可扩展容量的数组,如 C++ 的 [`std::vector`](https:https://en.cppreference.com/w/cpp/container/vector)
* 有序动态数组(sorted dynamic array):和动态数组相同,但保证元素已排序,可用二分搜寻查询成员。
* 平衡树(balanced tree):平衡二叉树可有序地遍历成员,如红黑树和 C++ 的 [`std::map`](http:https://en.cppreference.com/w/cpp/container/map)[`std::multi_map`](http:https://en.cppreference.com/w/cpp/container/multimap) 支持重复键)。
* 哈希表(hash table):通过哈希函数能实现平均 O(1) 查询,如 C++11 的 [`std::unordered_map`](http:https://en.cppreference.com/w/cpp/container/unordered_map)[`unordered_multimap`](http:https://en.cppreference.com/w/cpp/container/unordered_multimap) 支持重复键)。
* 平衡树(balanced tree):平衡二叉树可有序地遍历成员,如红黑树和 C++ 的 [`std::map`](https:https://en.cppreference.com/w/cpp/container/map)[`std::multi_map`](https:https://en.cppreference.com/w/cpp/container/multimap) 支持重复键)。
* 哈希表(hash table):通过哈希函数能实现平均 O(1) 查询,如 C++11 的 [`std::unordered_map`](https:https://en.cppreference.com/w/cpp/container/unordered_map)[`unordered_multimap`](https:https://en.cppreference.com/w/cpp/container/unordered_multimap) 支持重复键)。

设一个对象有 n 个成员,数据结构的容量是 m,n ⩽ m,那么一些常用操作的时间/空间复杂度如下:

Expand Down

0 comments on commit 858db91

Please sign in to comment.