diff --git a/3.编程思维体系构建/3.4.6.10.增添属性.md b/3.编程思维体系构建/3.4.6.10.增添属性.md index 7b7cce2..05e01da 100644 --- a/3.编程思维体系构建/3.4.6.10.增添属性.md +++ b/3.编程思维体系构建/3.4.6.10.增添属性.md @@ -442,7 +442,7 @@ int listObjectsAtLocation(OBJECT *location) 为了使整个画面完整,最好扩展前面生成的地图,我们可以用虚线表示“明显”的通道。 -```c +```awk BEGIN { print "digraph map {"; } /^- / { outputEdges(); delete a; } /^[ \t]/ { a[$1] = $2; } diff --git a/3.编程思维体系构建/3.4.6.11.设置条件.md b/3.编程思维体系构建/3.4.6.11.设置条件.md index ce88931..a1659e4 100644 --- a/3.编程思维体系构建/3.4.6.11.设置条件.md +++ b/3.编程思维体系构建/3.4.6.11.设置条件.md @@ -7,12 +7,12 @@ 让我们举一个简单的例子。为了越过守卫进入山洞,玩家必须杀死或贿赂守卫(或两者兼而有之,这很有价值)。换句话说: - 当警卫死亡时(HP=0),入口开放 -- 当警卫拿着银币(贿赂警卫)时,入口开放 +- 当警卫拿着银币 (贿赂警卫) 时,入口开放 - 两者都不是,入口关闭 打开一个封闭的通道(在这里是进入洞穴)涉及到改变一些属性值: -- 目的地从 NULL(空地点)变为洞穴 +- 目的地从 NULL(空地点) 变为洞穴 - textGo从 "警卫阻止你...... "改为 "你走进山洞" - 在一些特殊情况下,描述和细节不需要改变。但对于一个门洞或栅栏,其中之一(或两者)通常会包含一些从 "开放 "到 "关闭 "的文字。 @@ -36,7 +36,8 @@ bool intoCaveIsClosed(void) } ``` -思考题:你能仿照上面例子自己写一些条件函数吗? +::: warning 🤔 思考题:你能仿照上面例子自己写一些条件函数吗? +::: 新的属性条件是一个指向这样一个函数的指针。 @@ -46,9 +47,9 @@ bool (*condition)(void); 接下来,我们可以立即开始为 object.txt 中的新属性分配函数。 -# object.txt +## object.txt -``` +```txt - intoCave condition intoCaveIsOpen description "a cave entrance to the east" @@ -68,11 +69,12 @@ bool (*condition)(void); textGo "The guard stops you from walking into the cave.\n" ``` -思考题:尝试自己实现上面的伪代码 +::: warning 🤔 思考题:尝试自己实现上面的伪代码 +::: 这两个 "条件 "函数是如此具体,每一个条件函数都只用这一次。现在,我们可以在我们需要的地方定义这些函数。许多编程语言都支持匿名函数,像这样: -``` +```txt - intoCave condition { return guard->health == 0 || silver->location == guard; } ... @@ -84,9 +86,9 @@ bool (*condition)(void); 所以现在我们可以把额外的段落和条件添加到 object.txt 中,就像前面解释的那样。 -# object.txt +## new object.txt -``` +```txt #include #include #include "object.h" @@ -193,11 +195,12 @@ extern OBJECT objs[]; textGo "Solid rock is blocking the way." ``` -思考题:尝试自己实现这些功能,并看看与你之前设计的有何不同 +::: warning 🤔 思考题:尝试自己实现这些功能,并看看与你之前设计的有何不同 +::: 为了使这些条件发挥作用,我们需要调整函数 isHolding 和 getDistance。 -# misc.c +## misc.c ```c #include @@ -273,7 +276,8 @@ int listObjectsAtLocation(OBJECT *location) } ``` -思考题:想想我们调整了什么 +::: warning 🤔 思考题:想想我们调整了什么 +::: 注意: @@ -282,7 +286,8 @@ int listObjectsAtLocation(OBJECT *location) 3. 为了简单起见,条件函数没有参数。实际上,传递一个参数 OBJECT *obj 可能更好;这使得编写更多的通用条件函数成为可能,可以在多个对象中重复使用。 4. 在理论上,任何对象都可以成为 "条件"。在下一章,你可以看到一个类似的技术被应用于此。 -思考题:想一想上面第二点要怎么用 C 来实现? +::: warning 🤔 思考题:想一想上面第二点要怎么用 C 来实现? +::: 输出样例 diff --git a/3.编程思维体系构建/3.4.6.12.开启关闭.md b/3.编程思维体系构建/3.4.6.12.开启关闭.md index ee6985d..d352de3 100644 --- a/3.编程思维体系构建/3.4.6.12.开启关闭.md +++ b/3.编程思维体系构建/3.4.6.12.开启关闭.md @@ -1,12 +1,12 @@ # 12.开启关闭 -在上一章中,我们使用 "条件 "函数来使对象消失。当然,还有一个更简单的方法来实现同样的目的:只要清除对象的位置属性就可以了! +在上一章中,我们使用 "条件 "函数来使对象消失。当然,还有一个更简单的方法来实现同样的目的:只要清除对象的位置属性就可以了! 洞口是一个典型的例子,条件函数在那里工作得特别好。这是因为入口受到其他对象(守卫和银币)中的属性的影响;我们可以使用函数使得所有的逻辑都能保持一致。 让我们举一个更直接的例子。假设山洞有一扇门通向一个密室。只是一个简单的门洞,玩家可以打开和关闭。就像前一章一样,我们将使用两个对象来表示这个通道;一个表示打开的门,另一个表示门关闭时。 -``` +```txt - backroom description "a backroom" tags "backroom" @@ -28,11 +28,12 @@ textGo "The door is closed.\n" ``` -思考题:尝试自己用 C 语言实现 +::: warning 🤔 思考题:尝试自己用 C 语言实现 +::: 自然,门也应该能从另一侧进入。 -``` +```txt - openDoorToCave description "an open door to the north" tags "north", "door", "doorway" @@ -111,7 +112,8 @@ else } ``` -思考题:你能不能仿照上面的代码实现 close 功能? +::: warning 🤔 思考题:你能不能仿照上面的代码实现 close 功能? +::: 为了使事情稍微复杂一些,我们可以在门上或盒子上加一把锁。这需要(至少)三个相互排斥的对象;每个可能的状态都有一个:打开、关闭和锁定。但是我们仍然可以使用同一个函数来交换对象的位置。例如,这里是如何解锁一个上锁的盒子;反之亦然。 @@ -132,15 +134,17 @@ else if (obj == lockedBox) 显然,代码的行数与游戏中的门(以及盒子和其他可以打开的物体)的数量成正比。因此,如果你的游戏有不止几扇门,那么选择一个更通用的解决方案是个好主意。顺便说一下,这对每一个命令都是适用的:当它涉及到许多物体时,尽量写通用代码;但当你处理一两个特殊情况时,就坚持使用直接的、专门的代码。 -思考题:我们可以使用什么方法来解决这个问题? +::: warning 🤔 思考题: +我们可以使用什么方法来解决这个问题? 提示:C++ 中的模板功能(这只是一种选择) 下面我们将揭晓答案 +::: 通用代码通常带有数据驱动的方法。换句话说,我们需要向我们的对象结构添加一个或多个属性。在这种特殊情况下,我们将为我们希望支持的每个命令添加一个函数指针:打开、关闭、锁定和解锁。 -# object.txt +## object.txt ```c #include @@ -354,7 +358,7 @@ extern OBJECT objs[]; 为了避免重复的代码,我们这次特意没有使用匿名函数。相反,我们将在一个单独的模块中实现必要的逻辑。函数 swapLocations 也在其中,这不过是一个稍微扩展的版本,它也会向用户输出反馈。 -# toggle.h +## toggle.h ```c extern void cannotBeOpened(void); @@ -376,7 +380,7 @@ extern void toggleBox(void); extern void toggleBoxLock(void); ``` -# toggle.c +## toggle.c ```c #include @@ -439,7 +443,7 @@ void toggleBoxLock(void) 正如前面所宣布的,打开、关闭、锁定和解锁这四个命令的实现是完全通用的。 -# openclose.h +## openclose.h ```c extern void executeOpen(const char *noun); @@ -448,7 +452,7 @@ extern void executeLock(const char *noun); extern void executeUnlock(const char *noun); ``` -# openclose.c +## openclose.c ```c #include @@ -478,17 +482,18 @@ void executeUnlock(const char *noun) { OBJECT *obj = reachableObject("what you want to unlock", noun); if (obj != NULL) (*obj->unlock)(); +} ``` 上面,我们使用了一个通用函数 reachableObject 来处理不在这里的对象;其实现见下文。这样,我们就不必把同样的代码写四遍(每个执行函数写一遍)。更多的命令将在第 15 章中加入;这些命令将受益于同样的函数。 -# reach.h +## reach.h ```c extern OBJECT *reachableObject(const char *intention, const char *noun); ``` -# reach.c +## reach.c ```c #include @@ -526,7 +531,7 @@ OBJECT *reachableObject(const char *intention, const char *noun) 同样,我们也要对 parsexec.c 进行补充 -# parsexec.c +## parsexec.c ```c #include diff --git a/3.编程思维体系构建/3.4.6.13.编写解析器.md b/3.编程思维体系构建/3.4.6.13.编写解析器.md index 7a73c4b..03284bc 100644 --- a/3.编程思维体系构建/3.4.6.13.编写解析器.md +++ b/3.编程思维体系构建/3.4.6.13.编写解析器.md @@ -1,6 +1,6 @@ # 13.编写解析器 -每个文本冒险都有一个解析器,但是解析器也有高下之分。一个简单的 "动词-名词 "解析器(就像我们从第二章开始一直使用的那个)对于一个精心设计的冒险游戏来说可能已经足够了。 +每个文本冒险都有一个解析器,但是解析器也有高下之分。一个简单的 "动词 - 名词 "解析器(就像我们从第二章开始一直使用的那个)对于一个精心设计的冒险游戏来说可能已经足够了。 然而,Infocom 已经证明,一个更高级的解析器确实有助于制作一个令人愉快的游戏。它不一定要通过图灵测试。 @@ -19,7 +19,8 @@ char *noun = strtok(NULL, "\n"); - 它确实接受多字对象(如银币),但字与字之间的空格必须准确无误。我们的游戏拒绝银币和硬币之间的双空格。 - 它是区分大小写的;"向北走 "的命令因为大写的 "G "而不被识别。 -思考题:你能想到有什么办法解决这些问题吗? +::: warning 🤔 思考题:你能想到有什么办法解决这些问题吗? +::: 编写一个好的分析器并不是一件小事,但在这里我将给你一个相对简单的方法,我们将定义一个由模式列表组成的语法,类似于(但比)正则表达式要简单得多。 @@ -30,7 +31,8 @@ char *noun = strtok(NULL, "\n"); 为了解析用户的输入,我们将从上到下遍历模式列表,依次尝试将用户的输入与每个模式匹配。我们将在发现第一个匹配时停止。为了简单起见,我们将不使用回溯,尽管这可以在以后添加。 -思考题:如果我们使用回溯,那该怎么编写代码? +::: warning 🤔 思考题:如果我们使用回溯,那该怎么编写代码? +::: 大写字母是我们语法中的非终端符号,它们可以匹配任何标签(任何对象)。当解析器在两个不同的标签(例如 "银币 "和 "银")之间进行选择时,较长的标签将被优先考虑。 @@ -40,7 +42,7 @@ char *noun = strtok(NULL, "\n"); const char *params[26]; ``` -该数组有 26 个元素;字母表中的每个(大写)字母都有一个,这足以满足一个模式中多达 26 个不同的非终端。对于一个(匹配的)模式中的每个非终端,将通过在非终端的数组元素中填充一个指向该特定标签的指针来 "捕获 "一个匹配的标签。 params[0](第一个数组元素)捕获非终端 "A",params[1]捕获 "B",以此类推。一个简单的宏定义可以用来找到属于某个非终端的数组元素。 +该数组有 26 个元素;字母表中的每个(大写)字母都有一个,这足以满足一个模式中多达 26 个不同的非终端。对于一个(匹配的)模式中的每个非终端,将通过在非终端的数组元素中填充一个指向该特定标签的指针来 "捕获 "一个匹配的标签。params[0](第一个数组元素)捕获非终端 "A",params[1]捕获 "B",以此类推。一个简单的宏定义可以用来找到属于某个非终端的数组元素。 ```c #define paramByLetter(letter) (params + (letter) - 'A') @@ -52,7 +54,8 @@ const char *params[26]; 假设用户打错了字,输入了 "go kave"。问题是,这个命令到底应不应该匹配 "go A "这个命令?如果我们不想出解决办法,那么这个命令将无法匹配任何其他命令,并最终进入一个通用的错误处理程序,它可能会回答 "我不知道如何去 kave "这样的话。这就失去了改进这些 "消极反应 "的所有机会;回答 "我不知道你要去哪里 "已经感觉更自然了。最好的办法是将所有关于命令去向的答复保持在函数 executeGo 内。 -停下来想一想,可以怎么解决这个问题? +::: warning 🤔 停下来想一想,可以怎么解决这个问题? +::: 有几种方法可以实现这一点,但最简单的方法是允许非终止符匹配任何东西。所以不仅仅是一个有效的标签,也包括完全的胡言乱语、空白或什么都没有这种语句。这种 "无效 "的输入将被捕获为一个空字符串("")。 @@ -73,17 +76,18 @@ const char *params[26]; 前两个命令形式可以为任何顺序,但第三个必须在最后。 -思考题:你是否有办法解决这个问题? +::: warning 🤔 思考题:你是否有办法解决这个问题? +::: 是时候将其付诸行动了。我们将抛弃模块 parsexec.c 的现有内容,用一个新的函数 parseAndExecute 的实现来取代它,该函数使用一个模式列表,应该能够匹配我们到目前为止实现的每一条命令。每个模式都与一个执行相应命令的函数相联系。 -# parsexec.c +## parsexec.c ```c extern bool parseAndExecute(const char *input); ``` -# parsexec.h +## parsexec.h ```c #include @@ -149,7 +153,7 @@ bool parseAndExecute(const char *input) 最难的部分是函数 matchCommand 的实现。但正如你在下面看到的,这也可以在不到 100 行的代码中完成。 -# match.h +## match.h ```c #define MAX_PARAMS 26 @@ -161,7 +165,7 @@ extern const char *params[]; extern bool matchCommand(const char *src, const char *pattern); ``` -# match.c +## match.c ```c #include @@ -242,7 +246,7 @@ bool matchCommand(const char *src, const char *pattern) 我们调整各种命令的实现,以利用新的数组参数。 -# inventory.h +## inventory.h ```c extern bool executeGet(void); @@ -252,7 +256,7 @@ extern bool executeGive(void); extern bool executeInventory(void); ``` -# inventory.c +## inventory.c ```c #include @@ -323,7 +327,7 @@ bool executeInventory(void) 我们在上一章中添加的模块也是如此。 -# opemclose.h +## opemclose.h ```c extern bool executeOpen(void); @@ -332,7 +336,7 @@ extern bool executeLock(void); extern bool executeUnlock(void); ``` -# openclose.c +## openclose.c ```c #include @@ -372,7 +376,7 @@ bool executeUnlock(void) 在 location.c 中,look around 命令被赋予了自己的功能,与检查特定对象的 look 命令分开(见第 7-12 行)。 -# location.h +## location.h ```c extern bool executeLookAround(void); @@ -380,7 +384,7 @@ extern bool executeLook(void); extern bool executeGo(void); ``` -# location.c +## location.c ```c #include @@ -453,7 +457,7 @@ bool executeGo(void) } ``` -我们的游戏仍然只接受简单的动词-名词命令,但新的解析器确实有可能接受有多个名词的命令,如 "put coin in box",这将在下一章中演示。 +我们的游戏仍然只接受简单的动词 - 名词命令,但新的解析器确实有可能接受有多个名词的命令,如 "put coin in box",这将在下一章中演示。 新的解析器比原来的解析器有了很大的改进,但以今天的标准来看,它仍然远远不够完美。例如,没有结构性的方法可以用一个命令操纵多个对象("获得硬币、钥匙和灯")或连续执行两个或多个命令("获得钥匙然后向东走")。这对于一个 RPG 游戏来说限制实在太大了! diff --git a/3.编程思维体系构建/3.4.6.14.丰富命令.md b/3.编程思维体系构建/3.4.6.14.丰富命令.md index 80f86f0..9ced0d2 100644 --- a/3.编程思维体系构建/3.4.6.14.丰富命令.md +++ b/3.编程思维体系构建/3.4.6.14.丰富命令.md @@ -2,7 +2,7 @@ 是时候证明新的解析器确实有能力解释更复杂的命令了。 -到目前为止,我们的解析器只接受简单的动词-名词命令。让我们试着解析一些更复杂的命令,比如: +到目前为止,我们的解析器只接受简单的动词 - 名词命令。让我们试着解析一些更复杂的命令,比如: - get coin from box - put coin in box @@ -16,7 +16,8 @@ - ask A from B - give A to B -思考题:你能否自行实现这些命令 +::: warning 🤔 思考题:你能否自行实现这些命令 +::: 但是正如前一章所解释的,类似的命令(比如 "从 B 中获取 A "和已经存在的 "获取 A")必须以正确的顺序排列。如果'get A'首先出现,那么它将消耗任何以'get'开头的命令,包括所有应该被新模式匹配的命令。简而言之,"从 B 获取 A "必须出现在 "获取 A "之前。 @@ -32,13 +33,13 @@ 目前,我们不需要有两个以上非终结点的模式。 -# parsexec.h +## parsexec.h ```c extern bool parseAndExecute(const char *input); ``` -# parsexec.c +## parsexec.c ```c #include @@ -106,9 +107,9 @@ bool parseAndExecute(const char *input) } ``` -在一个新的模块 inventory2.c 中,我们实现了新的多名词命令 get、drop/put、ask 和 give。现在我们终于可以把金币放回盒子里了(可喜可贺,可喜可贺)。 +在一个新的模块 inventory2.c 中,我们实现了新的多名词命令 get、drop/put、ask 和 give。现在我们终于可以把金币放回盒子里了 (可喜可贺,可喜可贺)。 -# inventory2.h +## inventory2.h ```c extern bool executeGetFrom(void); @@ -117,7 +118,7 @@ extern bool executeAskFrom(void); extern bool executeGiveTo(void); ``` -# inventory2.c +## inventory2.c ```c #include @@ -210,11 +211,12 @@ bool executeGiveTo(void) 仔细观察上面的代码,你可能会注意到,像 "把硬币放进森林 "和 "把硬币放进盒子 "这样的命令(当盒子被关闭时)会得到以下奇怪的回答:"这太重了。" 这是因为大多数物体(包括封闭的盒子,以及像森林这样的场景)容纳其他物体的能力为零。这是正确的,但这个信息是很不恰当的。为了避免这种情况,我们将为那些容量为零的物体引入一个单独的信息:"这样做似乎不太适合。" -先想想有没有什么办法解决? +::: warning 🤔 先想想有没有什么办法解决? +::: 然而,当它作为对 "把钥匙放进盒子里 "的回应时,这个特殊的信息是完全误导的。所以我们将为这种特殊的对象组合做一个特殊的例外。 -# move.c +## move.c ```c #include diff --git a/3.编程思维体系构建/3.4.6.15.赋予明暗.md b/3.编程思维体系构建/3.4.6.15.赋予明暗.md index af0e4e0..d061695 100644 --- a/3.编程思维体系构建/3.4.6.15.赋予明暗.md +++ b/3.编程思维体系构建/3.4.6.15.赋予明暗.md @@ -4,11 +4,11 @@ 在黑暗中的效果因游戏而异。通常情况下,它使命令 "look "没有效果。在一些游戏中(如 Zork),黑暗是致命的。在其他游戏中,只要你画出了黑暗区域的详细地图,在没有光源的情况下,你仍然可以取得进展。 -我们的游戏将保持在这两者之间;在黑暗中不会让你被杀,但你也不能进入任何通道(具有光亮的通道将是一个例外)。对我们来说,让玩家跑进一个黑暗的区域,而没有不让他机会回到他来的地方,似乎是不公平的。 +我们的游戏将保持在这两者之间;在黑暗中不会让你被杀,但你也不能进入任何通道 (具有光亮的通道将是一个例外)。对我们来说,让玩家跑进一个黑暗的区域,而没有不让他机会回到他来的地方,似乎是不公平的。 好吧,所以首先,我们来设计在黑暗中玩家无法看到周围环境。 -# location.c +## location.c ```c #include @@ -90,7 +90,7 @@ bool executeGo(void) 其次,在黑暗中玩家无法看到或使用附近的物体。 -# noun.c +## noun.c ```c #include @@ -193,7 +193,7 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) 在这两种情况下,我们都使用了一个函数 isLit。它在 misc.c 中被定义(并且使用量增多了)。 -# misc.h +## misc.h ```c typedef enum { @@ -216,7 +216,7 @@ extern OBJECT *actorHere(void); extern int listObjectsAtLocation(OBJECT *location); ``` -# misc.c +## misc.c ```c #include @@ -318,6 +318,7 @@ int listObjectsAtLocation(OBJECT *location) } } return count; +} ``` 注意: @@ -326,13 +327,14 @@ int listObjectsAtLocation(OBJECT *location) - isNoticeable 函数相比 isLit 更进一步。它对每个物体都有效,而不仅仅是地点和灯。它还考虑到玩家库存中的物体总是可以被使用,即使是在黑暗中。 - 第 60 行:附近的物体仍然隐藏在黑暗中,被视为'不在这里'。这自然可以防止游戏泄露玩家不应该知道的物体的信息。 -思考题:你还能想到那哪些可以改进的地方吗? +::: warning 🤔 思考题:你还能想到那哪些可以改进的地方吗? +::: 我们为实现 isLit 函数的功能从而使用了一个新的属性 light。 -# object.awk +## object.awk -``` +```awk BEGIN { count = 0; obj = ""; @@ -428,11 +430,11 @@ function outputRecord(separator) } ``` -默认情况下,亮度为零意味着一个物体不发光。在大白天的每一个地点(通常是除了地下的所有地点)都会被赋予一个正(大于 0)的光线值。其实是什么值并不重要,只要它不是零就可以了。我们还将添加一盏灯,玩家可以携带它来穿越黑暗区域。 +默认情况下,亮度为零意味着一个物体不发光。在大白天的每一个地点(通常是除了地下的所有地点)都会被赋予一个正 (大于 0) 的光线值。其实是什么值并不重要,只要它不是零就可以了。我们还将添加一盏灯,玩家可以携带它来穿越黑暗区域。 -# object.txt +## object.txt -``` +```txt #include #include #include "object.h" @@ -658,7 +660,7 @@ extern OBJECT objs[]; 我们将添加一些命令,我们可以用来打开和关闭灯。 -# parsexec.c +## parsexec.c ```c #include @@ -733,14 +735,14 @@ bool parseAndExecute(const char *input) 下面是这些命令的实现。 -# onoff.h +## onoff.h ```c extern bool executeTurnOn(void); extern bool executeTurnOff(void); ``` -# onoff.c +## onoff.c ```c #include @@ -789,7 +791,7 @@ bool executeTurnOff(void) 为了打开和关闭灯,我们将使用我们用来打开和关闭门和盒子的相同技巧(见第 13 章)。 -# toggle.h +## toggle.h ```c extern void cannotBeOpened(void); @@ -813,7 +815,7 @@ extern void toggleBoxLock(void); extern void toggleLamp(void); ``` -# toggle.c +## toggle.c ```c #include @@ -895,9 +897,9 @@ void toggleLamp(void) 最后,我们将在我们生成的地图上标记出黑暗的位置。 -# map.awk +## map.awk -```c +```awk BEGIN { print "digraph map {\n\tnode [style=filled]"; } /^- / { outputEdges(); obj = $2; delete a; } /^[ \t]/ { a[$1] = $2; } @@ -929,9 +931,10 @@ function outputNodes() } ``` -思考题:尝试将上面的伪代码用 C 语言实现其功能 +::: warning 🤔 思考题:尝试将上面的伪代码用 C 语言实现其功能 +::: -玩家们,请注意不要把灯关掉,也不要把它丢掉。如果这样做,那么在黑暗中你将永远无法找回它。换言之,你会被困在黑暗之中! 幸运的是,下一章将提供一个撤销笨拙行动的方法。 +玩家们,请注意不要把灯关掉,也不要把它丢掉。如果这样做,那么在黑暗中你将永远无法找回它。换言之,你会被困在黑暗之中!幸运的是,下一章将提供一个撤销笨拙行动的方法。 输出样例:Welcome to Little Cave Adventure. You are in an open field. diff --git a/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md b/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md index 9194fcd..f492b80 100644 --- a/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md +++ b/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md @@ -1,6 +1,6 @@ # 阶段二:文字冒险(cool) -# 前言 +## 前言 本来打算让各位做下面的任务来进行进一步的学习的,但是想了想,实在是,太无聊啦! @@ -24,20 +24,20 @@ 在 1980 年代, [文字冒险](http://en.wikipedia.org/wiki/Text_adventure) 是一种受人尊敬的电脑游戏类型。但是时代已经变了,在 21 世纪,它们与 带有 3D 引擎的现代 [MMORPG 相比显得苍白无力。](http://en.wikipedia.org/wiki/Mmorpg)书籍在电影的兴起中幸存下来,而基于文本的游戏很快就输掉了与图形游戏的战斗。“互动小说”由一个活跃的社区保持活力,但它的商业价值早已不复存在。 -# 系统调试的黄金法则:KISS 原则 +## 系统调试的黄金法则:KISS 原则 -这里的 `KISS` 是 `Keep It Simple, Stupid` 的缩写, 它的中文翻译是: 不要在一开始追求绝对的完美. +这里的 `KISS` 是 `Keep It Simple, Stupid` 的缩写,它的中文翻译是:不要在一开始追求绝对的完美。 -随着以后代码量会越来越多, 各个模块之间的交互也越来越复杂, 工程的维护变得越来越困难, 一个很弱智的 bug 可能需要调好几天. +随着以后代码量会越来越多,各个模块之间的交互也越来越复杂,工程的维护变得越来越困难,一个很弱智的 bug 可能需要调好几天。 -在这种情况下, 系统能跑起来才是王道, 跑不起来什么都是浮云, 追求面面俱到只会增加代码维护的难度. +在这种情况下,系统能跑起来才是王道,跑不起来什么都是浮云,追求面面俱到只会增加代码维护的难度。 -唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则, 它的宗旨是从易到难, 逐步推进, 一次只做一件事, 少做无关的事. +唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则,它的宗旨是从易到难,逐步推进, 一次只做一件事,少做无关的事。 -如果你不知道这是什么意思, 我们以可能发生的 `str` 成员缓冲区溢出问题来作为例子. KISS 法则告诉你, 你应该使用 `assert(0)`, 就算不"得体"地处理上述问题, 仍然不会影响表达式求值的核心功能的正确性. +如果你不知道这是什么意思,我们以可能发生的 `str` 成员缓冲区溢出问题来作为例子。KISS 法则告诉你,你应该使用 `assert(0)`, 就算不"得体"地处理上述问题,仍然不会影响表达式求值的核心功能的正确性。 -如果你还记得调试公理, 你会发现两者之间是有联系的: 调试公理第二点告诉你, 未测试代码永远是错的. 与其一下子写那么多"错误"的代码, 倒不如使用 `assert(0)` 来有效帮助你减少这些"错误". +如果你还记得调试公理,你会发现两者之间是有联系的:调试公理第二点告诉你,未测试代码永远是错的。与其一下子写那么多"错误"的代码,倒不如使用 `assert(0)` 来有效帮助你减少这些"错误". -如果把 KISS 法则放在软件工程领域来解释, 它强调的就是多做[单元测试](http://en.wikipedia.org/wiki/Unit_testing): 写一个函数, 对它进行测试, 正确之后再写下一个函数, 再对它进行测试... 一种好的测试方式是使用 assertion 进行验证, +如果把 KISS 法则放在软件工程领域来解释,它强调的就是多做[单元测试](http://en.wikipedia.org/wiki/Unit_testing): 写一个函数,对它进行测试,正确之后再写下一个函数,再对它进行测试... 一种好的测试方式是使用 assertion 进行验证, -KISS 法则不但广泛用在计算机领域, 就连其它很多领域也视其为黄金法则, [这里](http://blog.sciencenet.cn/blog-414166-562616.html)有一篇文章举出了很多的例子, 我们强烈建议你阅读它, 体会 KISS 法则的重要性. +KISS 法则不但广泛用在计算机领域,就连其它很多领域也视其为黄金法则,[这里](http://blog.sciencenet.cn/blog-414166-562616.html)有一篇文章举出了很多的例子,我们强烈建议你阅读它,体会 KISS 法则的重要性。 diff --git a/3.编程思维体系构建/3.4.7.1.1调试理论.md b/3.编程思维体系构建/3.4.7.1.1调试理论.md index c0e9daf..560add4 100644 --- a/3.编程思维体系构建/3.4.7.1.1调试理论.md +++ b/3.编程思维体系构建/3.4.7.1.1调试理论.md @@ -1,6 +1,6 @@ # 调试理论 -# 调试公理 +::: warning 🌲 调试公理 - The machine is always right. (机器永远是对的) @@ -9,32 +9,34 @@ - Corollary: Mistakes are likely to appear in the "must-be-correct" code. -这两条公理的意思是: 抱怨是没有用的, 接受代码有 bug 的现实, 耐心调试. +这两条公理的意思是:抱怨是没有用的,接受代码有 bug 的现实,耐心调试. +::: -# 如何调试 +::: warning 😋 如何调试 - 不要使用"目光调试法", 要思考如何用正确的工具和方法帮助调试 - - 程序设计课上盯着几十行的程序, 你或许还能在大脑中像 NEMU 那样模拟程序的执行过程; 但程序规模大了之后, 很快你就会放弃的: 你的大脑不可能模拟得了一个巨大的状态机 - - 我们学习计算机是为了学习计算机的工作原理, 而不是学习如何像计算机那样机械地工作 -- 使用 `assert()` 设置检查点, 拦截非预期情况 + - 程序设计课上盯着几十行的程序,你或许还能在大脑中像 NEMU 那样模拟程序的执行过程; 但程序规模大了之后,很快你就会放弃的:你的大脑不可能模拟得了一个巨大的状态机 + - 我们学习计算机是为了学习计算机的工作原理,而不是学习如何像计算机那样机械地工作 +- 使用 `assert()` 设置检查点,拦截非预期情况 - 例如 `assert(p != NULL)` 就可以拦截由空指针解引用引起的段错误 -- 结合对程序执行行为的理解, 使用 `printf()` 查看程序执行的情况(注意字符串要换行) +- 结合对程序执行行为的理解,使用 `printf()` 查看程序执行的情况 (注意字符串要换行) - - `printf()` 输出任意信息可以检查代码可达性: 输出了相应信息, 当且仅当相应的代码块被执行 - - `printf()` 输出变量的值, 可以检查其变化过程与原因 + - `printf()` 输出任意信息可以检查代码可达性:输出了相应信息,当且仅当相应的代码块被执行 + - `printf()` 输出变量的值,可以检查其变化过程与原因 - 使用 GDB 观察程序的任意状态和行为 - - 打印变量, 断点, 监视点, 函数调用栈... + - 打印变量,断点,监视点,函数调用栈... +::: ![](https://cdn.xyxsw.site/boxcnaqLMfwqNMTcYEPuF3vFjqg.png) -# 调试理论 +## 什么是调试理论 如果我们能判定任意程序状态的正确性,那么给定一个 failure,我们可以通过二分查找定位到第一个 error 的状态,此时的代码就是 fault (bug)。 -# 正确的方法:理解程序的执行过程,弄清楚到底为何导致了 bug +## 正确的方法:理解程序的执行过程,弄清楚到底为何导致了 bug - `ssh`:使用 `-v` 选项检查日志 - `gcc`:使用 `-v` 选项打印各种过程 @@ -44,22 +46,22 @@ 各个工具普遍提供调试功能,帮助用户/开发者了解程序的行为 -# 错误概念 +## 错误概念 -我们来简单梳理一下段错误发生的原因. 首先, 机器永远是对的. 如果程序出了错, 先怀疑自己的代码有 bug . 比如由于你的疏忽, 你编写了 `if (p = NULL)` 这样的代码. 但执行到这行代码的时候, 也只是 `p` 被赋值成 `NULL`, 程序还会往下执行. 然而等到将来对 `p` 进行了解引用的时候, 才会触发段错误, 程序彻底崩溃. +我们来简单梳理一下段错误发生的原因。首先,机器永远是对的。如果程序出了错,先怀疑自己的代码有 bug . 比如由于你的疏忽,你编写了 `if (p = NULL)` 这样的代码。但执行到这行代码的时候,也只是 `p` 被赋值成 `NULL`, 程序还会往下执行。然而等到将来对 `p` 进行了解引用的时候,才会触发段错误,程序彻底崩溃。 -我们可以从上面的这个例子中抽象出一些软件工程相关的概念: +我们可以从上面的这个例子中抽象出一些软件工程相关的概念: -- Fault: 实现错误的代码, 例如 `if (p = NULL)` -- Error: 程序执行时不符合预期的状态, 例如 `p` 被错误地赋值成 `NULL` -- Failure: 能直接观测到的错误, 例如程序触发了段错误 +- Fault: 实现错误的代码,例如 `if (p = NULL)` +- Error: 程序执行时不符合预期的状态,例如 `p` 被错误地赋值成 `NULL` +- Failure: 能直接观测到的错误,例如程序触发了段错误 -调试其实就是从观测到的 failure 一步一步回溯寻找 fault 的过程, 找到了 fault 之后, 我们就很快知道应该如何修改错误的代码了. 但从上面的例子也可以看出, 调试之所以不容易, 恰恰是因为: +调试其实就是从观测到的 failure 一步一步回溯寻找 fault 的过程,找到了 fault 之后,我们就很快知道应该如何修改错误的代码了。但从上面的例子也可以看出,调试之所以不容易,恰恰是因为: - fault 不一定马上触发 error - 触发了 error 也不一定马上转变成可观测的 failure -- error 会像滚雪球一般越积越多, 当我们观测到 failure 的时候, 其实已经距离 fault 非常遥远了 +- error 会像滚雪球一般越积越多,当我们观测到 failure 的时候,其实已经距离 fault 非常遥远了 -理解了这些原因之后, 我们就可以制定相应的策略了: +理解了这些原因之后,我们就可以制定相应的策略了: -- 尽可能把 fault 转变成 error. 这其实就是测试做的事情, 所以我们在上一节中加入了表达式生成器的内容, 来帮助大家进行测试, 后面的实验内容也会提供丰富的测试用例. 但并不是有了测试用例就能把所有 fault 都转变成 error 了, 因为这取决于测试的覆盖度. 要设计出一套全覆盖的测试并不是一件简单的事情, 越是复杂的系统, 全覆盖的测试就越难设计. 但是, 如何提高测试的覆盖度, 是学术界一直以来都在关注的问题. +- 尽可能把 fault 转变成 error. 这其实就是测试做的事情,所以我们在上一节中加入了表达式生成器的内容,来帮助大家进行测试,后面的实验内容也会提供丰富的测试用例。但并不是有了测试用例就能把所有 fault 都转变成 error 了,因为这取决于测试的覆盖度。要设计出一套全覆盖的测试并不是一件简单的事情,越是复杂的系统,全覆盖的测试就越难设计。但是,如何提高测试的覆盖度,是学术界一直以来都在关注的问题。 diff --git a/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md b/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md index 1b251cf..855b24b 100644 --- a/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md +++ b/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md @@ -4,57 +4,61 @@ ![](https://cdn.xyxsw.site/boxcnHXggg6eLy86vFmb4shOksh.png) -# GDB 是什么? +## GDB 是什么? 调试器,简单来说就是当你代码跑不通时候修正错误用的 +[GDB's Mascot?](https://sourceware.org/gdb/mascot/) + 可搭配插件 gef pwndbg pwngdb peda -# 基本操作 +## 基本操作 + +[GDB 快速入门教程](https://www.bilibili.com/video/BV1EK411g7Li/) ### GDB 使用表 -run (r)运行程序 +`run (r)`运行程序 -b打断点,可以在函数和位置打断点 +`b`打断点,可以在函数和位置打断点 -info b查看打断点的位置 +`info b`查看打断点的位置 -n下一步,跳过函数的 +`n`下一步,跳过函数的 -list查看源代码 +`list`查看源代码 --p走 PID 路线 +`-p`走 PID 路线 -edit [file:]function 看现在停下的函数位置 +`edit [file:]function` 看现在停下的函数位置 -step 进入任何函数 +`step` 进入任何函数 -p打印变量 +`p`打印变量 -shell输入命令 +`shell`输入命令 -set logging on记录日志 +`set logging on`记录日志 -watchpoint观察变量是否变化的观察点 +`watchpoint`观察变量是否变化的观察点 -watch设置观察点位置,watch*(地址) +`watch`设置观察点位置,watch*(地址) -layout split开启 TUI 模式 +`layout split`开启 TUI 模式 -whatis查看变量类型 +`whatis`查看变量类型 -ptype查看详细信息 +`ptype`查看详细信息 #### TUI -ctrl +x +a开启 +`ctrl + x + a`开启 -ctrl+p+n往前 +`ctrl + p + n`往前 -ctrl +l重新整理页面 +`ctrl + l`重新整理页面 -# 官方手册 +## 官方手册 [GDB User Manual](https://sourceware.org/gdb/current/onlinedocs/gdb) diff --git a/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md b/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md index f8e4052..ec8a473 100644 --- a/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md +++ b/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md @@ -22,7 +22,7 @@ int main(int argc, char **argv) { } ``` -讓我們看看不同編譯器的 Debug 模式下執行的結果 +让我们看看不同编译器的 Debug 模式下执行的结果 Visual C++ 6.0 @@ -36,7 +36,7 @@ MinGW(GCC) > The answer : 25 -我們試試看在 Release 下執行的結果 +我们试试看在 Release 下执行的结果 Visual C++ 6.0 @@ -50,9 +50,9 @@ MinGW(GCC) > The answer : 25 -C 語言最初為了開發 UNIX 和系統軟體而生,本質是低階的程式語言, +C 语言最初为了开发 UNIX 和系统软体而生,本质是低阶的程式语言 -在語言規範層級存在 UB,可允許編譯器引入更多最佳化。比方說 `X * 2 / 2` 在沒有 overflow 發生的時候,可最佳化為 `X`。 +在语言规范层级存在 UB,可允许编译器引入更多最佳化。比方说 `X * 2 / 2` 在沒有 overflow 发生的時候,可最佳化为 `X`。 而且值得注意的是,在你的程序初始化之前,栈里面塞的一堆东西也是 UB。 @@ -64,4 +64,4 @@ C 語言最初為了開發 UNIX 和系統軟體而生,本質是低階的程式 [万恶的未定义行为 | 程式设计 遇上 小提琴](https://blog.ez2learn.com/2008/09/27/evil-undefined-behavior/) -关键是,老师喜欢出题刁难你啊!真烦啊! +关键是,老师喜欢出题刁难你啊!真烦啊! diff --git a/3.编程思维体系构建/3.4.7.3C编译器干了什么.md b/3.编程思维体系构建/3.4.7.3C编译器干了什么.md index 1d7db6a..20267a2 100644 --- a/3.编程思维体系构建/3.4.7.3C编译器干了什么.md +++ b/3.编程思维体系构建/3.4.7.3C编译器干了什么.md @@ -1,16 +1,16 @@ # C 编译器干了什么 -# 以 gcc 为例 +## 以 gcc 为例 -1、预处理,生成 .i 的文件[预处理器 cpp] +1、预处理,生成 .i 的文件[预处理器 cpp] -2、将预处理后的文件转换成汇编语言, 生成文件 .s [编译器 egcs] +2、将预处理后的文件转换成汇编语言,生成文件 .s [编译器 egcs] -3、有汇编变为目标代码(机器代码)生成 .o 的文件[汇编器 as] +3、有汇编变为目标代码 (机器代码) 生成 .o 的文件[汇编器 as] -4、连接目标代码, 生成可执行程序 [链接器 ld] +4、连接目标代码,生成可执行程序 [链接器 ld] -# 有啥用 +## 有啥用 有一天你发现,某一段 C 语言只有几行,但是用了大量的魔法宏定义以及魔法操作以及神奇的元编程。 @@ -18,10 +18,10 @@ 如果有一天你要学习汇编语言,或者说出现了在代码中看不出的 bug,你可能需要翻译成.s 文件 -# 了解更多 +## 了解更多 当然不止如此,编译器还承担了优化的过程,有时候同一份代码,经过 O1 和 O2 不同优化可能最后代码都不一样。 推荐阅读 -[http://www.ruanyifeng.com/blog/2014/11/compiler.html](http://www.ruanyifeng.com/blog/2014/11/compiler.html) +[编译器的工作过程](http://www.ruanyifeng.com/blog/2014/11/compiler.html) diff --git a/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md b/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md index cd8424d..7613471 100644 --- a/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md +++ b/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md @@ -1,6 +1,6 @@ # Inline Assembly 与链接加载 -# Inline Assembly +## Inline Assembly 可以在 C 代码里嵌入汇编语言的骚操作。毕竟编译器本身也就是个复制,翻译,,粘贴的过程。 @@ -14,7 +14,7 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 当然这里可以参考 c inline Asm 的教程 但是已经脱离了本文的主题了 -这里给指条路 [https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/how-to-use-inline-assembly-language-in-c-code.html](https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/how-to-use-inline-assembly-language-in-c-code.html) +这里给指条路 [How to Use Inline Assembly Language in C Code](https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/how-to-use-inline-assembly-language-in-c-code.html) > 诸如 Go 的高级语言 也可以通过 inline C 来 内链汇编 @@ -24,17 +24,17 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 当然,你可以通过 RTFM 来将 C 语言的变量塞到汇编中处理。 -在 Windows 平台下 VS 没有 Code 可以以 `__asm {}` 代码块来进行实验 但是注意 只能在 x86 模式下使用 x64 不支持 可以参考 [https://docs.microsoft.com/zh-tw/cpp/assembler/inline/asm?view=msvc-170](https://docs.microsoft.com/zh-tw/cpp/assembler/inline/asm?view=msvc-170) +在 Windows 平台下 VS 没有 Code 可以以 `__asm {}` 代码块来进行实验 但是注意 只能在 x86 模式下使用 x64 不支持 可以参考 [__asm](https://docs.microsoft.com/zh-tw/cpp/assembler/inline/asm?view=msvc-170) 以上两种平台的方案都其实本质是编译器特殊宏 并不包括在 C 的标准内 所以要针对不同的编译器 寻找对应的文档 -# 静态链接 +## 静态链接 当你使用 GCC 生成可执行文件./a.out 时,到底发生了什么? 为什么就可以直接执行呢?当你问及这个问题时,那么就大有一番探索的空间了 -# 链接器 +## 链接器 链接器的功能:将一个可执行程序所需的目标文件和库最终整合在一起。 @@ -42,15 +42,13 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 这个就是帮你和外部库连接起来的重要部分。 -一个程序包含三个段:.text 、.data 和 .bss 段。 +一个程序包含三个段:.text、.data 和 .bss 段。 -``` 而各目标文件和库都包含这三段,所以,ld 链接器的功能就是将各个目标文件和库的三段合并在一起。 -当然,链接器所完成的链接工作并非只是简单地将各个目标文件和库的三段内存堆砌在一起,而是还要完成 “重定位” 的工作。 -``` +当然,链接器所完成的链接工作并非只是简单地将各个目标文件和库的三段内存堆砌在一起,而是还要完成“重定位”的工作。 -## 查看二进制文件的工具 +### 查看二进制文件的工具 使用 objdump 查看 data 节的 x,y @@ -60,7 +58,7 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 使用 IDA BinaryNInja 一类反汇编工具 -# 动态链接 +## 动态链接 静态链接一次用那么多,实在是太大太大了 @@ -74,7 +72,7 @@ Linux 下一般是 .so 如果你看到了 .a 那个一般是 archive 的缩写 使用动态链接的好处在于 可以热加载和热更新 -# 共享连接的加载 +## 共享连接的加载 使用 ldd 来查看 a.out 就可以查看动态链接库 diff --git a/3.编程思维体系构建/3.5git与github.md b/3.编程思维体系构建/3.5git与github.md index 3c09933..4a151f0 100644 --- a/3.编程思维体系构建/3.5git与github.md +++ b/3.编程思维体系构建/3.5git与github.md @@ -4,7 +4,9 @@ ## 光玉 -想象一下你正在玩 Flappy Bird ,你今晚的目标是拿到 100 分,不然就不睡觉。 经过千辛万苦,你拿到了 99 分,就要看到成功的曙光的时候,你竟然失手了!你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?为什么不让我存档?” +想象一下你正在玩 Flappy Bird,你今晚的目标是拿到 100 分,不然就不睡觉。经过千辛万苦,你拿到了 99 分,就要看到成功的曙光的时候,你竟然失手了!你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?为什么不让我存档?” + +[**Play Happy Bird**](https://flappybird.io/) 想象一下你正在写代码,你今晚的目标是实现某一个新功能,不然就不睡觉。经过千辛万苦,你终于把代码写好了,保存并编译运行,你看到调试信息一行一行地在终端上输出。就要看到成功的曙光的时候,竟然发生了错误!你仔细思考,发现你之前的构思有着致命的错误,但之前正确运行的代码已经永远离你而去了。你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?”你绝望地倒在屏幕前 ... ... 这时,你发现身边渐渐出现无数的光玉,把你包围起来,耀眼的光芒令你无法睁开眼睛 ... ... 等到你回过神来,你发现屏幕上正是那份之前正确运行的代码!但在你的记忆中,你确实经历过那悲痛欲绝的时刻 ... ... 这一切真是不可思议啊 ... ... @@ -40,7 +42,7 @@ git config --global user.name "Zhang San" # your name git config --global user.email "zhangsan@foo.com" # your email ``` -经过这些配置, 你就可以开始使用 `git` 了。 +经过这些配置,你就可以开始使用 `git` 了。 你会通过 `git clone` 命令来拉取远程仓库的代码,里面已经包含一些 `git` 记录,因此不需要额外进行初始化。如果你想在别的实验、项目中使用 `git` ,你首先需要切换到实验、项目的目录中,然后输入 @@ -68,11 +70,11 @@ git log git status ``` -可以得知,与当前存档相比,哪些文件发生了变化. +可以得知,与当前存档相比,哪些文件发生了变化。 ### 提交 -你可以像以前一样编写代码。等到你的开发取得了一些阶段性成果,你应该马上进行 “ 提交( commit )”。 +你可以像以前一样编写代码。等到你的开发取得了一些阶段性成果,你应该马上进行“提交(commit)”。 首先你需要使用 `git status` 查看是否有新的文件或已修改的文件未被跟踪;若有,则使用 `git add` 将文件加入跟踪列表,例如 @@ -88,7 +90,7 @@ git add -A git add . ``` -但这样可能会跟踪了一些不必要的文件(二进制文件),例如编译产生的 `.o` 文件,和最后产生的可执行文件。事实上,我们只需要跟踪代码源文件即可。为了让 `git` 在添加跟踪文件之前作筛选,你可以编辑 `.gitignore` 文件( 没有的话手动创建 文件名就叫这个 ),在里面给出需要被 `git` 忽略的文件和文件类型。 +但这样可能会跟踪了一些不必要的文件(二进制文件),例如编译产生的 `.o` 文件,和最后产生的可执行文件。事实上,我们只需要跟踪代码源文件即可。为了让 `git` 在添加跟踪文件之前作筛选,你可以编辑 `.gitignore` 文件(没有的话手动创建 文件名就叫这个),在里面给出需要被 `git` 忽略的文件和文件类型。 [这个网页](https://www.toptal.com/developers/gitignore) 可以根据你搜索的语言来给你创建必要的 `.gitignore` 文件 @@ -105,13 +107,13 @@ file.o # 一个编译后的文件 建议把编译后的文件都加入 `.gitignore` 并在 `README.md` 文件中留下编译的详细操作流程,节省 `.git` 空间、符合提交规范。 -把新文件加入跟踪列表后, 使用 `git status` 再次确认. 确认无误后就可以存档了, 使用 +把新文件加入跟踪列表后,使用 `git status` 再次确认。确认无误后就可以存档了,使用 ```bash git commit -m "...comment..." ``` -提交工程当前的状态(注释)。其中 `...comment...` 是你本次提交的注释( 一般在注释中简略写出本次提交干了什么)以下为注释规范,养成良好习惯请遵守: +提交工程当前的状态(注释)。其中 `...comment...` 是你本次提交的注释(一般在注释中简略写出本次提交干了什么)以下为注释规范,养成良好习惯请遵守: ```bash 模板: @@ -145,7 +147,7 @@ subject为commit概述 你可以使用 `git log` 查看存档记录,你应该能看到刚才编辑的注释。 -### 读档( 回溯到某一个 commit ) +### 读档(回溯到某一个 commit) 如果你遇到了上文提到的让你悲痛欲绝的情况,现在你可以使用光玉来救你一命了。首先使用 `git log` 来查看已有的存档,并决定你需要回到哪个过去。每一份存档都有一个 `hash code`,例如 `b87c512d10348fd8f1e32ddea8ec95f87215aaa5` , 你需要通过 `hash code` 来告诉 `git` 你希望读哪一个档。使用以下命令进行读档: @@ -155,7 +157,7 @@ git reset --hard b87c 其中 `b87c` 是上文 `hash code` 的前缀:你不需要输入整个 hash code. 这时你再看看你的代码,你已经成功地回到了过去! -但事实上, 在使用 `git reset` 的 `hard` 模式之前, 你需要再三确认选择的存档是不是你的真正目标。 如果你读入了一个较早的存档,那么比这个存档新的所有记录都将被删除!这意味着你不能随便回到“将来”了。 +但事实上,在使用 `git reset` 的 `hard` 模式之前,你需要再三确认选择的存档是不是你的真正目标。如果你读入了一个较早的存档,那么比这个存档新的所有记录都将被删除!这意味着你不能随便回到“将来”了。 ### 分支 @@ -165,7 +167,7 @@ git reset --hard b87c git branch ``` -查看所有分支. 其中 `master` 是主分支,使用 `git init` 初始化之后会自动建立主分支。 +查看所有分支。其中 `master` 是主分支,使用 `git init` 初始化之后会自动建立主分支。 读档的时候使用以下命令: @@ -190,13 +192,13 @@ git checkout -B 分支名 - 把修改结果保存到一个新的分支中,如果分支已存在,其内容将会被覆盖 -不同的分支之间不会相互干扰,这也给项目的分布式开发带来了便利。有了分支功能,你就可以像第三视点那样在一个世界的不同时间 ( 一个分支的多个存档 ),或者是多个平行世界 ( 多个分支 ) 之间来回穿梭了。 +不同的分支之间不会相互干扰,这也给项目的分布式开发带来了便利。有了分支功能,你就可以像第三视点那样在一个世界的不同时间 ( 一个分支的多个存档 ),或者是多个平行世界(多个分支)之间来回穿梭了。 ### 更多功能 以上介绍的是 `git` 的一些基本功能,`git` 还提供很多强大的功能,例如使用 `git diff` 比较同一个文件在不同版本中的区别,使用 `git bisect` 进行二分搜索来寻找一个 bug 在哪次提交中被引入... -其它功能的使用请参考 `git help` , `man git` , 或者在网上搜索相关资料。 +其它功能的使用请参考 `git help` , `man git` ,或者在网上搜索相关资料。 ## 全球最大男性交友网站 —— Github @@ -205,17 +207,16 @@ git checkout -B 分支名 你把任务分配好让组员去写代码中的某一个模块。组员写好之后发给你。 -你一看,通过QQ发过来的是一个文件啊文件 比如说 `学生管理模块.c` 你打开一看,我去是**乱码**。 +你一看,通过 QQ 发过来的是一个文件啊文件 比如说 `学生管理模块.c` 你打开一看,我去是**乱码**。 你废了九牛二虎之力把他的 GBK 编码改成 UTF8 之后,细细地品鉴这段代码,发现我去有严重逻辑错误,而且代码很不规范。 -你通过QQ告诉他,这一行有问题,能不能改一下。他说,好的我改一下。 +你通过 QQ 告诉他,这一行有问题,能不能改一下。他说,好的我改一下。 然后又发了文件啊文件给你,如此反复循环,你俩已经互相传了好几百个源代码文件,很没效率! ::: - -> 通过Git版本控制管理自己的代码 ,再通过Github来发布、同步互联,是一个很好的解决方案! +> 通过 Git 版本控制管理自己的代码,再通过 Github 来发布、同步互联,是一个很好的解决方案! 简介 @@ -241,7 +242,7 @@ git checkout -B 分支名 他会用一个像是命令行交互的方式引导注册,你需要依次填写 `邮箱` 、`密码` 、 `用户名(此为 ID 非昵称)` 、`是否同意邮箱广告推送` 、`机器验证码` 之后创建账户,随后会给你填写的邮箱发送验证码,填写注册。 -随后是一个欢迎问卷😋随便填写、如果他问你什么PRO Plan 选择 free 不付费就好。 +随后是一个欢迎问卷😋随便填写、如果他问你什么 PRO Plan 选择 free 不付费就好。 最后你访问[GitHub 官网](https://github.com)应该会显示你的 dashboard 管理台界面 @@ -251,7 +252,7 @@ git checkout -B 分支名 如果有就直接跳过这一步 -如果没有,打开 Shell( Windows 下打开 Git Bash 前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项 ),创建 SSH Key: +如果没有,打开 Shell(Windows 下打开 Git Bash 前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项 ),创建 SSH Key: ```bash ssh-keygen -t rsa -C "youremail@example.com" # youremail为你注册用的电子邮件地址 @@ -302,12 +303,10 @@ git clone git@github.com:yourname/gitexample.git > 以上方法是基于 ssh 方式的,下面方法是基于 HTTPS 方式的 -或者你可以跟随新创建之后的指引,`…or create a new repository on the command line` 内他描述了如何创建一个文件夹、创建一个README.md的文件,然后和github仓库绑定。 +或者你可以跟随新创建之后的指引,`…or create a new repository on the command line` 内他描述了如何创建一个文件夹、创建一个 README.md 的文件,然后和 github 仓库绑定。 ![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-19-18.png) - - ### 下载代码——clone 拷贝他人存档也未尝不可,而我们如果用他人存档时,次次都需要一样一样的拷贝文件和代码未免太过折磨,下面简单介绍如何使用 @@ -334,7 +333,7 @@ git clone https://github.com/camera-2018/git-example.git > > 如果你使用我的仓库的话,你 clone 过后在你自己电脑更改的文件等东西,是没法直接提交回来的(因为你没有我仓库管理权限) > -> 如果你非要给我的仓库添加东西呢 也是可以,参照下面的 PR (Pull Request)教程 +> 如果你非要给我的仓库添加东西呢 也是可以,参照下面的 PR(Pull Request)教程 一阵抽搐过后就下载好了 @@ -380,11 +379,11 @@ git commit -m "feat(helloworld): add helloworld file" ![](https://cdn.xyxsw.site/boxcni2dupDzNO8qTWPAxS5c67b.png) -1. 如果这是你自己的仓库有权限(本人仓库或 Collaborators 有权限的情况下)你就可以直接使用 +1. 如果这是你自己的仓库有权限(本人仓库或 Collaborators 有权限的情况下)你就可以直接使用 ```bash - git push origin main # origin是第四步里remote add起的远程名字 - # main是分支名 + git push origin main # origin 是第四步里 remote add 起的远程名字 + # main 是分支名 ``` 上传本次提交 @@ -405,7 +404,7 @@ git commit -m "feat(helloworld): add helloworld file" git switch camera-2018-dev ``` - 然后提交一个文件,这里直接使用 vscode 自带的 git 工具试试 (很方便、不用敲命令行) + 然后提交一个文件,这里直接使用 vscode 自带的 git 工具试试(很方便、不用敲命令行) ![](https://cdn.xyxsw.site/boxcnmwlYWOzwPbNqTAuSZK9dW3.png) @@ -437,7 +436,7 @@ git commit -m "feat(helloworld): add helloworld file" **第二种情况:我不是协作者、我什么权限也没有,我看了这个 public 项目后觉得很好但是有一些问题,我要给他贡献一些代码** - 可以点击仓库右上角的 fork + 可以点击仓库右上角的 fork ![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-34-21.png) @@ -445,35 +444,34 @@ git commit -m "feat(helloworld): add helloworld file" 回到源仓库点击 Pull Request 然后创建 PR `New pull request` - 最上面会提示你说 + 最上面会提示你说 Comparing changes Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also **compare across forks** . - 点击小蓝字 `compare across forks` 这会让你对比你fork仓库和源代码仓库的提交记录,之后就可以创建 PR 了,原作者看到了会合并。 - + 点击小蓝字 `compare across forks` 这会让你对比你 fork 仓库和源代码仓库的提交记录,之后就可以创建 PR 了,原作者看到了会合并。 ### 其他功能 -问题跟踪:GitHub的问题跟踪功能可用于报告软件中的问题、错误和功能请求,并进行讨论、分配和解决。 +问题跟踪:GitHub 的问题跟踪功能可用于报告软件中的问题、错误和功能请求,并进行讨论、分配和解决。 -Wiki页面:用户可以创建和编辑与存储库相关的Wiki页面,用于提供项目的文档、指南、示例代码等。 +Wiki 页面:用户可以创建和编辑与存储库相关的 Wiki 页面,用于提供项目的文档、指南、示例代码等。 -Pull请求(Pull Requests):使用者可以将自己的代码变更提交给其他项目的所有者,并请求合并到主干代码中。 +Pull 请求(Pull Requests):使用者可以将自己的代码变更提交给其他项目的所有者,并请求合并到主干代码中。 -项目管理:GitHub提供项目管理功能,包括任务管理、里程碑(milestones)、项目板(project boards)等工具,可用于组织和跟踪项目的进展。 +项目管理:GitHub 提供项目管理功能,包括任务管理、里程碑(milestones)、项目板(project boards)等工具,可用于组织和跟踪项目的进展。 -部署功能:GitHub可以与各种持续集成和部署(CI/CD)工具集成,帮助开发人员自动化构建、测试和部署他们的应用程序。 +部署功能:GitHub 可以与各种持续集成和部署(CI/CD)工具集成,帮助开发人员自动化构建、测试和部署他们的应用程序。 -统计信息:GitHub提供有关存储库活动和贡献者的统计信息,例如提交图表、活动日历等,有助于跟踪和分析项目的发展。 +统计信息:GitHub 提供有关存储库活动和贡献者的统计信息,例如提交图表、活动日历等,有助于跟踪和分析项目的发展。 社交功能:用户可以关注其他用户、存储库和组织,接收他们的更新和活动通知,并与他们进行交流和讨论。 -代码审核(Code Review):GitHub的Pull请求功能允许团队成员对代码进行审查和讨论,以确保代码质量和最佳实践。 +代码审核(Code Review):GitHub 的 Pull 请求功能允许团队成员对代码进行审查和讨论,以确保代码质量和最佳实践。 -集成和扩展:GitHub支持与其他工具和服务的集成,例如持续集成(CI)工具、代码质量检查工具、项目管理工具等。 +集成和扩展:GitHub 支持与其他工具和服务的集成,例如持续集成(CI)工具、代码质量检查工具、项目管理工具等。 -页面托管:GitHub Pages功能使您可以托管静态网站和文档,这在展示和共享项目文档、演示和博客等方面非常有用。 +页面托管:GitHub Pages 功能使您可以托管静态网站和文档,这在展示和共享项目文档、演示和博客等方面非常有用。 然后还有一些比如说 Copilot 之类的有用的功能。 @@ -485,19 +483,20 @@ Copilot 可以根据上下文和输入的提示,为开发人员生成代码建 你需要学生认证你的 Github 账号。 -地址在 https://education.github.com/students 点击 `Sign up for Global Campus` 来开始认证,下面会让你输入学校,绑定学校邮箱(杭电为 @hdu.edu.cn 结尾的邮箱)(如果你是杭电新生的话,可能要等到智慧杭电账号发放时才能注册杭电邮箱)并上传**学生证明**(从21年开始这个验证越来越严,如果不过的话你可以尝试 `学生证第一页`、`学生证第一页英文翻译(像有道翻译那样 P 图上去)`、`学信网学籍证明英文翻译(英文也是 P 上去)`) +地址在 [https://education.github.com/students](https://education.github.com/students) 点击 `Sign up for Global Campus` 来开始认证,下面会让你输入学校,绑定学校邮箱(杭电为 @hdu.edu.cn 结尾的邮箱)(如果你是杭电新生的话,可能要等到智慧杭电账号发放时才能注册杭电邮箱)并上传**学生证明**(从 21 年开始这个验证越来越严,如果不过的话你可以尝试 `学生证第一页`、`学生证第一页英文翻译(像有道翻译那样 P 图上去)`、`学信网学籍证明英文翻译(英文也是 P 上去)`) 通过了的话你的账户会有 Pro 标识 然后你可以享受的 Github 学生包里包含[这些东西](https://education.github.com/pack) -里面比较有用的有 -- JETBRAINS 全家桶的免费用(我没用,我用的是jb自己家的验证方式,不是github) +里面比较有用的有 + +- JETBRAINS 全家桶的免费用(我没用,我用的是 jb 自己家的验证方式,不是 github) - name.com 家的一个一年期的免费域名(大概价值吧 六七十块钱?) - github 的容量扩容和 actions 时间扩容、Codespaces 时间延长、Pages 扩容(没啥用倒是) -- Termius 学生包,这是我很喜欢用的终端软件,有学生包可以多端同步ssh的账号密码啥的,很方便。 +- Termius 学生包,这是我很喜欢用的终端软件,有学生包可以多端同步 ssh 的账号密码啥的,很方便。 - Sentry 容量扩容 - Copilot 免费用 -你可以在 `settings` 里看到你的copilot ,配置如下 +你可以在 `settings` 里看到你的 copilot,配置如下 ![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-59-49.png) diff --git a/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md b/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md index 38a92fb..886f0ce 100644 --- a/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md +++ b/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md @@ -1,18 +1,16 @@ # 从 CS61A 看编程语言学习 - - -# 什么是 CS61A +## 什么是 CS61A 首先声明,本教程的 python 部分很多内容摘自 CS61A 如果你看过 CS 自学指南,想必你在第一页就看过这样的描述 -> 大一入学时我是一个对计算机一无所知的小白,装了几十个 G 的 Visual Studio 天天和 OJ 你死我活。凭着高中的数学底子我数学课学得还不错,但在专业课上对竞赛大佬只有仰望。提到编程我只会打开那笨重的 IDE,新建一个我也不知道具体是干啥的命令行项目,然后就是 `cin`, `cout`, `for` 循环,然后 CE, RE, WA 循环。当时的我就处在一种拼命想学好但不知道怎么学,课上认真听讲但题还不会做,课后做作业完全是用时间和它硬耗的痛苦状态。我至今电脑里还存着自己大一上学期计算概论大作业的源代码 —— 一个 1200 行的 C++ 文件,没有头文件、没有类、没有封装、没有 unit test、没有 Makefile、没有 Git,唯一的优点是它确实能跑,缺点是“能跑”的补集。我一度怀疑我是不是不适合学计算机,因为童年对于极客的所有想象,已经被我第一个学期的体验彻底粉碎了。
这一切的转机发生在我大一的寒假,我心血来潮想学习 Python。无意间看到知乎有人推荐了 CS61A 这门课,说是 UC Berkeley 的大一入门课程,讲的就是 Python。我永远不会忘记那一天,打开 [CS61A](https://cs61a.org/) 课程网站的那个瞬间,就像哥伦布发现了新大陆一样,我开启了新世界的大门。
我一口气 3 个星期上完了这门课,它让我第一次感觉到原来 CS 可以学得如此充实而有趣,原来这世上竟有如此精华的课程。
为避免有崇洋媚外之嫌,我单纯从一个学生的视角来讲讲自学 CS61A 的体验:
- 独立搭建的课程网站: 一个网站将所有课程资源整合一体,条理分明的课程 schedule、所有 slides, hw, discussion 的文件链接、详细明确的课程给分说明、历年的考试题与答案。这样一个网站抛开美观程度不谈,既方便学生,也让资源公正透明。
- 课程教授亲自编写的教材:CS61A 这门课的开课老师将 MIT 的经典教材 Structure and Interpretation of Computer Programs (SICP) 用 Python 这门语言进行改编(原教材基于 Scheme 语言),保证了课堂内容与教材内容的一致性,同时补充了更多细节,可以说诚意满满。而且全书开源,可以直接线上阅读。
- 丰富到让人眼花缭乱的课程作业:14 个 lab 巩固随堂知识点,10 个 homework,还有 4 个代码量均上千行的 project。与大家熟悉的 OJ 和 Word 文档式的作业不同,所有作业均有完善的代码框架,保姆级的作业说明。每个 Project 都有详尽的 handout 文档、全自动的评分脚本。CS61A 甚至专门开发了一个[自动化的作业提交评分系统](https://okpy.org/)(据说还发了论文)。当然,有人会说“一个 project 几千行代码大部分都是助教帮你写好的,你还能学到啥?”。此言差矣,作为一个刚刚接触计算机,连安装 Python 都磕磕绊绊的小白来说,这样完善的代码框架既可以让你专注于巩固课堂上学习到的核心知识点,又能有“我才学了一个月就能做一个小游戏了!”的成就感,还能有机会阅读学习别人高质量的代码,从而为自己所用。我觉得在低年级,这种代码框架可以说百利而无一害。唯一的害也许是苦了老师和助教,因为开发这样的作业可想而知需要相当的时间投入。
- 每周 Discussion 讨论课,助教会讲解知识难点和考试例题:类似于北京大学 ICS 的小班研讨,但习题全部用 LaTeX 撰写,相当规范且会明确给出 solution。
这样的课程,你完全不需要任何计算机的基础,你只需要努力、认真、花时间就够了。此前那种有劲没处使的感觉,那种付出再多时间却得不到回报的感觉,从此烟消云散。这太适合我了,我从此爱上了自学。
试想如果有人能把艰深的知识点嚼碎嚼烂,用生动直白的方式呈现给你,还有那么多听起来就很 fancy,种类繁多的 project 来巩固你的理论知识,你会觉得他们真的是在倾尽全力想方设法地让你完全掌握这门课,你会觉得不学好它简直是对这些课程建设者的侮辱。
如果你觉得我在夸大其词,那么不妨从 [CS61A](https://cs61a.org/) 开始,因为它是我的梦开始的地方。 +> 大一入学时我是一个对计算机一无所知的小白,装了几十个 G 的 Visual Studio 天天和 OJ 你死我活。凭着高中的数学底子我数学课学得还不错,但在专业课上对竞赛大佬只有仰望。提到编程我只会打开那笨重的 IDE,新建一个我也不知道具体是干啥的命令行项目,然后就是 `cin`, `cout`, `for` 循环,然后 CE, RE, WA 循环。当时的我就处在一种拼命想学好但不知道怎么学,课上认真听讲但题还不会做,课后做作业完全是用时间和它硬耗的痛苦状态。我至今电脑里还存着自己大一上学期计算概论大作业的源代码 —— 一个 1200 行的 C++ 文件,没有头文件、没有类、没有封装、没有 unit test、没有 Makefile、没有 Git,唯一的优点是它确实能跑,缺点是“能跑”的补集。我一度怀疑我是不是不适合学计算机,因为童年对于极客的所有想象,已经被我第一个学期的体验彻底粉碎了。
这一切的转机发生在我大一的寒假,我心血来潮想学习 Python。无意间看到知乎有人推荐了 CS61A 这门课,说是 UC Berkeley 的大一入门课程,讲的就是 Python。我永远不会忘记那一天,打开 [CS61A](https://cs61a.org/) 课程网站的那个瞬间,就像哥伦布发现了新大陆一样,我开启了新世界的大门。
我一口气 3 个星期上完了这门课,它让我第一次感觉到原来 CS 可以学得如此充实而有趣,原来这世上竟有如此精华的课程。
为避免有崇洋媚外之嫌,我单纯从一个学生的视角来讲讲自学 CS61A 的体验:
- 独立搭建的课程网站:一个网站将所有课程资源整合一体,条理分明的课程 schedule、所有 slides, hw, discussion 的文件链接、详细明确的课程给分说明、历年的考试题与答案。这样一个网站抛开美观程度不谈,既方便学生,也让资源公正透明。
- 课程教授亲自编写的教材:CS61A 这门课的开课老师将 MIT 的经典教材 Structure and Interpretation of Computer Programs (SICP) 用 Python 这门语言进行改编(原教材基于 Scheme 语言),保证了课堂内容与教材内容的一致性,同时补充了更多细节,可以说诚意满满。而且全书开源,可以直接线上阅读。
- 丰富到让人眼花缭乱的课程作业:14 个 lab 巩固随堂知识点,10 个 homework,还有 4 个代码量均上千行的 project。与大家熟悉的 OJ 和 Word 文档式的作业不同,所有作业均有完善的代码框架,保姆级的作业说明。每个 Project 都有详尽的 handout 文档、全自动的评分脚本。CS61A 甚至专门开发了一个[自动化的作业提交评分系统](https://okpy.org/)(据说还发了论文)。当然,有人会说“一个 project 几千行代码大部分都是助教帮你写好的,你还能学到啥?”。此言差矣,作为一个刚刚接触计算机,连安装 Python 都磕磕绊绊的小白来说,这样完善的代码框架既可以让你专注于巩固课堂上学习到的核心知识点,又能有“我才学了一个月就能做一个小游戏了!”的成就感,还能有机会阅读学习别人高质量的代码,从而为自己所用。我觉得在低年级,这种代码框架可以说百利而无一害。唯一的害也许是苦了老师和助教,因为开发这样的作业可想而知需要相当的时间投入。
- 每周 Discussion 讨论课,助教会讲解知识难点和考试例题:类似于北京大学 ICS 的小班研讨,但习题全部用 LaTeX 撰写,相当规范且会明确给出 solution。
这样的课程,你完全不需要任何计算机的基础,你只需要努力、认真、花时间就够了。此前那种有劲没处使的感觉,那种付出再多时间却得不到回报的感觉,从此烟消云散。这太适合我了,我从此爱上了自学。
试想如果有人能把艰深的知识点嚼碎嚼烂,用生动直白的方式呈现给你,还有那么多听起来就很 fancy,种类繁多的 project 来巩固你的理论知识,你会觉得他们真的是在倾尽全力想方设法地让你完全掌握这门课,你会觉得不学好它简直是对这些课程建设者的侮辱。
如果你觉得我在夸大其词,那么不妨从 [CS61A](https://cs61a.org/) 开始,因为它是我的梦开始的地方。 -如果看完了这些,你可能会震惊,会怀疑并且试着打开它并且去尝试这门课程,但是也有可能你会被纯英文的视频或者油管劝退,也有可能你会怀疑我在使用别人的课程体系的前提下仍然要把它放到自己的内容里面的目的,That's all right,我会在下面对她讲的东西进行一定的补充,并且附着上自己的学习建议以及学习思考。 +如果看完了这些,你可能会震惊,会怀疑并且试着打开它并且去尝试这门课程,但是也有可能你会被纯英文的视频或者油管劝退,也有可能你会怀疑我在使用别人的课程体系的前提下仍然要把它放到自己的内容里面的目的,That's all right,我会在下面对她讲的东西进行一定的补充,并且附着上自己的学习建议以及学习思考。 -# 错误的学习方式 +## 错误的学习方式 很多人看到要自学 python 之后,第一时间想到的是,我要去 B 站/百度搜一搜,然后一般搜出来就是菜鸟教程,然后就是一连串枯燥乏味的知识堆叠,或者说是培训班的网课,给我们一种知识好像就是这么枯燥乏味以及自己好像学到了很多但是真的用起来却一无所知痛苦万分的感觉。 @@ -24,17 +22,17 @@ 是很好。 -但是为什么坚持不下来呢? +但是为什么坚持不下来呢? 根据我的统计,原因无外乎是以下几点:英语太难太劝退了!课程设置太难,好像听懂了但是写起东西来却还是推行不下去!我不知道学了这个能干什么,所以没有动力!学了一两章虽然好像学到了东西,但是感觉有很多东西学了却记不住,导致难度曲线陡增了!游戏太好玩了! 舒适区看起来很难打破! -# 正确的思考方式 +## 正确的思考方式 面对英语,我们前文有过一而再再而三的提醒过使用正确的工具,但是不得不说的是,在翻译的过程中可能难免丢失了一定的信息,使得我们在困惑中可能变得没有了前进的动力,或者从另一个角度来说我们没有动力是因为没有足够的原因来告诉我们的意识,我们到底应该在做这个超过看菜鸟教程所需精力好多倍的工作,到底能得到除了一点新奇感以外的什么东西,以此来给我们更为充分的理由支撑自己学习完成。 -# 建立正确的认知论 +## 建立正确的认知论 编程思想本身远比学习某一门编程语言的具体内容更为重要,我们很多的同学在进行这方面内容的时候总是只想着记忆某一门语言的某些内容,然后学的非常的痛苦。 @@ -42,12 +40,10 @@ 但是编程语言的设计思想一般不会出现太大的波动,并且就算是发展也有其适配的场景和知识脉络的,如果你乐于去发掘这个知识脉络和思想,那么你就可以优雅的掌握一种思维方式而不是简单的拧螺丝一样的机械化工作。而好的思考方式往往是可以应用在同类的所有语言甚至是在所有的更多的 -# 更有趣的练习方式 +## 更有趣的练习方式 我不得不承认的一点是,越痛苦的练习往往可以让你获得更大的提升模拟的成长往往与你面对苦难以及解决他的时间是成正比的。 不过遗憾的是,我们大多数的同学是在面对跳起来都够不到的反馈的时候,会选择放弃。(除非你有 M 的倾向) 因此,有时候我们说大道至简。好的东西往往是能让人们快速理解的东西,我觉得 61A 的难度梯度设计,就是兼具了趣味性和间接性的,并且全面优于互联网上的非常多的教程,比硬啃要给我们更多的正反馈(当然,改变思维和学习方式是很重要的。 - -# diff --git a/3.编程思维体系构建/3.6.2环境配置.md b/3.编程思维体系构建/3.6.2环境配置.md index 3b81c9a..db7792d 100644 --- a/3.编程思维体系构建/3.6.2环境配置.md +++ b/3.编程思维体系构建/3.6.2环境配置.md @@ -2,7 +2,7 @@ 当你开始制作大型项目或者复现论文时,环境配置就开始变得至关重要。 -# 什么是环境? +## 什么是环境? 环境是包的集合,我们一般用 Anaconda 来配置虚拟环境。 @@ -28,24 +28,18 @@ 然后一个新的环境就创建好辣~ -# 如何配置环境 +## 如何配置环境 -## 1.配置你自己的环境 +### 1.配置你自己的环境 你可以尝试命令 `pip install <包的名字>` 或者 `conda install <包的名字>` -``` - 在下载某个包失败的时候可以查一查有没有人写相关攻略~ -``` +> 在下载某个包失败的时候可以查一查有没有人写相关攻略~ 你可以用 `conda list` 查看你这个环境已有的包。你也可以在包的名字后面加上 `==版本号` 来指定版本。 -``` - 请注意各个包之间的依赖关系,否则容易导致无法运行或效果变差! -``` +> 请注意各个包之间的依赖关系,否则容易导致无法运行或效果变差! -## 2.复现论文代码时配置环境 +### 2.复现论文代码时配置环境 -``` - 一般我们可以在Github的README中找到环境的配置方法,遇到难以下载的特殊版本包时可以考虑下载它的源码手动编译,具体流程不展开了,可以自行搜索 -``` +> 一般我们可以在 Github 的 README 中找到环境的配置方法,遇到难以下载的特殊版本包时可以考虑下载它的源码手动编译,具体流程不展开了,可以自行搜索 diff --git a/3.编程思维体系构建/3.6.3安装python.md b/3.编程思维体系构建/3.6.3安装python.md index bb423ea..371ff94 100644 --- a/3.编程思维体系构建/3.6.3安装python.md +++ b/3.编程思维体系构建/3.6.3安装python.md @@ -1,6 +1,6 @@ # 安装 python -教程 +::: warning 😍 教程 [Python 小白必看,非常生动的 Pycharm 与 Anaconda 安装教学,干货!_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Bp4y117UW) @@ -9,8 +9,9 @@ [Win10 下 Conda-Pycharm-Pytorch 的安装_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV15U4y1J7Ss) +::: -# 巧妇难为无米之炊 +## 巧妇难为无米之炊 你可以在终端上用 Python 解释器 @@ -20,9 +21,9 @@ 我们推荐你都进行一波尝试,同样这也会作为一个任务 -# 解释器 +::: warning 😐 解释器 -# Windows 用户 +Windows 用户 打开 [Python 官方网站](https://www.python.org/),找到“Download”里的“Latest: Python 3.x.y”。 @@ -30,17 +31,17 @@ 注意:windows11 安装好后 命令行输入 python 可能会跳到 Microsoft 应用商店 可在 customize installation(自定义安装)next 勾选 install for all users -## GNU/Linux 系统 +GNU/Linux 系统 在终端输入 `sudo apt install python3` 即可完成 Python3 的全部安装流程 可以输入 `python3 --version` 检验是否成功。 - +::: ![](https://cdn.xyxsw.site/boxcn95LbcwuMC2dIViOxWk8BFb.png) -# Jupyter Notebook +::: warning 🤔 Jupyter Notebook -[官方网站](https://jupyter.org/) Jupyter Notebook 是基于网页的用于交互计算的应用程序。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。——[Jupyter ](https://link.zhihu.com/?target=https%3A//jupyter-notebook.readthedocs.io/en/stable/notebook.html) +[官方网站](https://jupyter.org/) Jupyter Notebook 是基于网页的用于交互计算的应用程序。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。——[Jupyter](https://link.zhihu.com/?target=https%3A//jupyter-notebook.readthedocs.io/en/stable/notebook.html) 你在一个框框中直接输入代码,运行,它立马就在下面给你输出。怎么样,是不是很酷? @@ -53,6 +54,7 @@ jupyter notebook 进行使用 +::: ![](https://cdn.xyxsw.site/boxcnfwk8gnFAHu5JzVUiugJjQe.png) diff --git a/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md b/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md index 53c6e11..117ef0b 100644 --- a/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md +++ b/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md @@ -1,10 +1,11 @@ # 阶段零:Python 解释器 -可参考资料 +::: warning 😍 可参考资料 [官方文档](https://wiki.python.org/moin/BeginnersGuide) [菜鸟教程](https://www.runoob.com/python3/python3-interpreter.html) +::: 你可以在终端与解释器进行交互 @@ -14,65 +15,44 @@ 你可以自己把玩一下 -``` +```python >>> 1 + 2 -``` - -``` 3 ``` -``` +```python >>> 3 - 2 -``` - -``` 1 ``` -``` +```python >>> 5 * 6 -``` - -``` 30 ``` -``` +```python >>> 7 / 4 -``` - -``` 1.75 ``` -``` +```python >>> 7 // 4 -``` - -``` 1 ``` -``` +```python >>> 7 % 4 -``` - -``` 3 ``` -``` ->>> 4**3 -``` - -``` +```python +>>> 4 ** 3 64 ``` 同时可以输入 `exit``()` 或按 Ctrl+D 退出交互 -同学们可能已经发现 python 这门编程语言的神奇之处了 +:::: warning 🤔 同学们可能已经发现 python 这门编程语言的神奇之处了 在这里留一个思考题 diff --git a/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md b/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md index 6040d5c..b30ce7c 100644 --- a/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md +++ b/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md @@ -1,10 +1,11 @@ # 阶段一:熟悉语句 -在进行本章之前,请你谨记一个原则:基本所有的功能都被人提前实现好了 +::: warning 🐱 在进行本章之前,请你谨记一个原则:基本所有的功能都被人提前实现好了 你需要关心的仅仅是逻辑该如何设立 在做本章任务前,请熟悉 python 的函数,循环和判断语句即可 +::: P1:请仅使用一行语句求出三个数的最小平方和 @@ -30,7 +31,7 @@ def two_of_three(x, y, z): return _____ ``` -提示:可以使用 max()函数哦 +提示:可以使用 `min()` 函数哦 P2:下降阶乘 diff --git a/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md b/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md index 634dd2b..59f856e 100644 --- a/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md +++ b/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md @@ -4,15 +4,13 @@ ![](https://cdn.xyxsw.site/boxcnCNpeAE9Hy61cyvtxfioIHg.png) -# - -# 释义 +## 释义 递归是在函数主体中重复调用函数的基本方案 让我们来看一个经典的例子 -> 阶乘,即 n!=n*(n-1)*......*2*1
例如: `5! = 5 * 4 * 3 * 2 * 1 = 120`. +> 阶乘,即 n! =n \* (n - 1) \*...... \* 2 \* 1
例如:5! = 5 \* 4 \* 3 \* 2 \* 1 = 120. 而阶乘的代码如下编辑 @@ -29,9 +27,9 @@ def factorial(n): - 想想在最简单的情况下函数将如何跳转 - 考虑使用问题的更简单版本来进行解决问题 -# 任务 +## 任务 -P4:编写一个递归函数 `skip_add`,它接受一个参数 n 并返回 `n + n-2 + n-4 + n-6 + ... + 0`。假设 n 是非负数。 +P4:编写一个递归函数 `skip_add`,它接受一个参数 n 并返回 `n + n-2 + n-4 + n-6 +...+ 0`。假设 n 是非负数。 ```python def skip_add(n): diff --git a/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md b/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md index badcb5b..27b8096 100644 --- a/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md +++ b/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md @@ -1,12 +1,13 @@ # 阶段三:数据抽象 -数据抽象(Data Abstraction) +数据抽象 (Data Abstraction) -[可参考教程](https://zhuanlan.zhihu.com/p/343133774) +::: warning 🐱 [可参考教程](https://zhuanlan.zhihu.com/p/343133774) 各位需要认真了解以下内容,他们是构建任何大厦的基石 +::: -# Data Abstraction +## Data Abstraction 数据抽象是一个伟大的概念,它允许程序员将代码以对象的形式进行看待,并且从更高的层面去审视问题。 @@ -14,14 +15,14 @@ 举个例子:你在开车时,如果要控制发动机的活塞怎么动,对你来说是否有些太过于困难了。因此将其抽象成了离合器,油门,刹车这些较为简单的操作。 -# 组成 +## 组成 一个抽象的数据类型(ADT)由两个主要部分组成 - Constructors:架构抽象数据类型的主要函数 - Selectors:操作数据类型的各式方法 -# 列表与元组 +## 列表与元组 列表是可以存储多个元素的 Python 数据结构。每个元素可以是任何类型,甚至可以是另一个列表! @@ -37,12 +38,12 @@ ```python tup = (1, 2, 3, 4) -new_tup = tup + (5, ) # 创建新的元组new_tup,并依次填充原元组的值 +new_tup = tup + (5, ) # 创建新的元组 new_tup,并依次填充原元组的值 new _tup (1, 2, 3, 4, 5) l = [1, 2, 3, 4] -l.append(5) # 添加元素5到原列表的末尾 +l.append(5) # 添加元素 5 到原列表的末尾 l [1, 2, 3, 4, 5] ``` @@ -69,13 +70,14 @@ l 3 ``` -思考题: +::: warning 🤔 思考题: 列表和元组在性能上有什么差异呢? 他们对应的使用场景有哪些呢? +::: -# 字典与集合 +## ;ltyi 字典与集合 字典是一系列由键(key)和值(value)配对组成的元素的集合,在 Python3.7+,字典被确定为有序 @@ -112,21 +114,22 @@ d {'name': 'jason', 'age': 20, 'gender': 'male'} s = {1, 2, 3} -s.add(4) # 增加元素4到集合 +s.add(4) # 增加元素 4 到集合 s {1, 2, 3, 4} -s.remove(4) # 从集合中删除元素4 +s.remove(4) # 从集合中删除元素 4 s {1, 2, 3} ``` -思考题: +::: warning 🤔 思考题: 字典和集合分别是什么原理呢? 字典可以是一个列表吗?为什么? +::: -# 可变性 +## 可变性 我们说如果一个对象可以由代码进行操作而改变那么我们称其具有可变性。 @@ -176,13 +179,14 @@ False True ``` -思考题,你能否从指针的角度去理解可变性呢? +::: warning 🤔 思考题,你能否从指针的角度去理解可变性呢? +::: -# 任务 +## 任务 -P7:9*9 乘法表 +P7:9*9 乘法表 -可能现在对你来说,构建像下图这样的 99 乘法表已经是非常容易的一件事了,可是如果我要求你使用 python 的列表推导式(list comprehension),在两行以内完成呢? +可能现在对你来说,构建像下图这样的 99 乘法表已经是非常容易的一件事了,可是如果我要求你使用 python 的列表推导式 (list comprehension),在两行以内完成呢? ![](https://cdn.xyxsw.site/boxcnccDSRQj5W3lZWEUkCOHz2b.png) @@ -235,40 +239,40 @@ make_city(name, lat, lon) ```python def make_city(name, lat, lon): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_name(city) - 'Berkeley' - >>> get_lat(city) - 0 - >>> get_lon(city) - 1 - """ - return [name, lat, lon] + """ + >>> city = make_city('Berkeley', 0, 1 + >>> get_name(city) + 'Berkeley + >>> get_lat(city) + 0 + >>> get_lon(city) + 1 + """ + return [name, lat, lon] def get_name(city): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_name(city) - 'Berkeley' - """ - return city[0] + """ + >>> city = make_city('Berkeley', 0, 1) + >>> get_name(city) + 'Berkeley' + """ + return city[0] def get_lat(city): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_lat(city) - 0 - """ - return city[1] + """ + >>> city = make_city('Berkeley', 0, 1) + >>> get_lat(city) + 0 + """ + return city[1] def get_lon(city): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_lon(city) - 1 - """ - return city[2] + """ + >>> city = make_city('Berkeley', 0, 1) + >>> get_lon(city) + 1 + """ + return city[2] ``` 首先你试试求出两个地方的距离。 diff --git a/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md b/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md index d603583..e4ca206 100644 --- a/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md +++ b/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md @@ -1,24 +1,25 @@ # 阶段四:高阶函数 -阅读以及完成本部分内容可以帮助你有效减少代码冗余。 +::: warning 🐱 阅读以及完成本部分内容可以帮助你有效减少代码冗余。 让你完成更为优雅的代码 各位要记住的是 -# 代码首先是给人看的 +代码首先是给人看的 机器看的永远只是你的机器码。 可参考教程 [Lambda](https://zhuanlan.zhihu.com/p/80960485) +::: -# Lambda 介绍 +## Lambda 介绍 Lambda 表达式是通过指定两件事来评估函数的表达式:参数和返回表达式。 请尝试阅读以下英文表格,对比函数与 lambda 表达式的不同 -# Lambda 实验 +## Lambda 实验 以下代码 python 会显示什么?通过对这些代码的实验,加深你对代码的学习 @@ -74,7 +75,7 @@ ______ ______ ``` -# 任务 +## 任务 P9:我们发现以下两个函数看起来实现的非常相似,是否可以进行改进,将其整合? @@ -113,11 +114,11 @@ def is_prime(n): 需求: -你需要通过自己写一个函数: `count_cond` ,来接受一个含有两个参数的函数 `condition(n, i)`(使用lambda表达式), +你需要通过自己写一个函数: `count_cond` ,来接受一个含有两个参数的函数 `condition(n, i)`(使用 lambda 表达式), -且`condition`函数应该满足第一个参数为N,而第二个参数将会在`condition`函数中遍历 1 to N。 +且`condition`函数应该满足第一个参数为 N,而第二个参数将会在`condition`函数中遍历 1 to N。 -`count_cond` 将返回一个单参数函数(ps:一个匿名函数),此单参数函数将会在被调用时返回 1 to N 中所有满足`condition`的数字的个数(如:1到n中素数的个数)。 +`count_cond` 将返回一个单参数函数 (ps:一个匿名函数),此单参数函数将会在被调用时返回 1 to N 中所有满足`condition`的数字的个数 (如:1 到 n 中素数的个数)。 ```python def count_cond(condition): diff --git a/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md b/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md index a268330..c59468a 100644 --- a/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md +++ b/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md @@ -1,6 +1,6 @@ # 阶段五:迭代生成 -# 前言 +## 前言 在写乘法表的时候,你可能写过类似 @@ -18,13 +18,13 @@ for (int i = 0; i < n; i ++) 但是,你想过 Python 在处理 for in 语句的时候,具体发生了什么吗?什么样的对象可以被 for in 来枚举呢? -# 容器迭代 +## 容器迭代 容器这个概念非常好理解。 在 Python 中一切皆对象,对象的抽象就是类,而对象的集合就是容器。 -列表(list: [0, 1, 2]),元组(tuple: (0, 1, 2)),字典(dict: {0:0, 1:1, 2:2}),集合(set: set([0, 1, 2]))都是容器。 +列表`list: [0, 1, 2]`,元组`tuple: (0, 1, 2)`,字典`dict: {0:0, 1:1, 2:2}`,集合`set: set([0, 1, 2])`都是容器。 对于容器,你可以很直观地想象成多个元素在一起的单元;而不同容器的区别,正是在于内部数据结构的实现方法。 @@ -74,11 +74,11 @@ StopIteration [1, 2, 3, 4] ``` -# 英语练习,对迭代器的类比 +## 英语练习,对迭代器的类比 Analogy: An iterable is like a book (one can flip through the pages) and an iterator for a book would be a bookmark (saves the position and can locate the next page). Calling `iter` on a book gives you a new bookmark independent of other bookmarks, but calling `iter` on a bookmark gives you the bookmark itself, without changing its position at all. Calling `next` on the bookmark moves it to the next page, but does not change the pages in the book. Calling `next` on the book wouldn't make sense semantically. We can also have multiple bookmarks, all independent of each other. -# 生成器:懒人迭代器! +## 生成器:懒人迭代器! ```python def test_iterator(): @@ -114,7 +114,8 @@ Wall time: 12.5 s 声明一个迭代器很简单,[i for i in range(100000000)]就可以生成一个包含一亿元素的列表。每个元素在生成后都会保存到内存中,你通过代码可以看到,它们占用了巨量的内存,内存不够的话就会出现 OOM 错误。 -了解下 yield()函数吧,他可以返回一个生成器对象,试试看懂这个 +::: warning 🤔 了解下 yield()函数吧,他可以返回一个生成器对象,试试看懂这个 +::: ```python >>> def gen_list(lst): @@ -133,7 +134,7 @@ Wall time: 12.5 s StopIteration ``` -# 思考题:python 会显示什么?为什么? +## 思考题:python 会显示什么?为什么? ```python >>> s = [1, 2, 3, 4] @@ -185,9 +186,9 @@ ______ ______ ``` -# 任务 +## 任务 -P10:实现 `count`,它接受一个迭代器 `t` 并返回该值 `x` 出现在 的第一个 n 个元素中的次数 `t` +P10:实现 `count`,它接受一个迭代器 `t` 并返回该值 `x` 出现在的前 n 个元素中的次数 `t` ```python def count(t, n, x): diff --git a/3.编程思维体系构建/3.6.4.6结语.md b/3.编程思维体系构建/3.6.4.6结语.md index 27fb94b..d70bdb5 100644 --- a/3.编程思维体系构建/3.6.4.6结语.md +++ b/3.编程思维体系构建/3.6.4.6结语.md @@ -1,6 +1,6 @@ # 结语 -# 感觉学了不少内容,又感觉什么都没学? +## 感觉学了不少内容,又感觉什么都没学? 确实,这也是学习过程中一个非常普遍存在的状态,你学了五个非常重要的 python 语言的特性,但是在你用他们真正来优化代码解决代码之前,你都无法真正的掌握他们。 @@ -10,11 +10,11 @@ 同时,python 的核心特性就这些吗?远远不止呢,这些只是你入手其的敲门砖,我在下面会列举一些别的特性,你可以自行前去了解,也可以等到你真正遇到问题的时候去思考? -# 为什么没有突出面向对象 +## 为什么没有突出面向对象 因为代码量实在是太少了,当你去理解面向对象的时候的伟大意义时,最好与 C 语言这种面向过程的语言进行对比,不过,如果你完成了我们的文字冒险小游戏的时候,你可能会有非常深刻的体验。 -# 还有什么是我值得注意的? +## 还有什么是我值得注意的? 这些内容值得你去学习与思考,但是碍于各种因素,我暂时没有详细介绍 @@ -30,9 +30,9 @@ 如果有机会,我会继续补充相关内容 -值得一提的是:后面人工智能模块,我们将以 python 为主去进行编程,这对完成了所有任务的你一定是 a piece of cake! +值得一提的是:后面人工智能模块,我们将以 python 为主去进行编程,这对完成了所有任务的你一定是 a piece of cake! -# 一些不错的补充 +## 一些不错的补充 [WTF for python](https://github.com/robertparley/wtfpython-cn) diff --git a/3.编程思维体系构建/3.6.4Python for fun.md b/3.编程思维体系构建/3.6.4Python for fun.md index 0310404..c5f7df7 100644 --- a/3.编程思维体系构建/3.6.4Python for fun.md +++ b/3.编程思维体系构建/3.6.4Python for fun.md @@ -1,6 +1,6 @@ # Python for fun -值得一提的是,Python 是面向对象的编程语言,与你之前书写的 C 语言(面向过程)有非常多的不同。 +值得一提的是,Python 是面向对象的编程语言,与你之前书写的 C 语言(面向过程)有非常多的不同。 我们为什么要选择要使用 Python 来首先讲解面向对象这个概念? diff --git a/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md b/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md index 0cdee98..9abf2f6 100644 --- a/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md +++ b/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md @@ -69,9 +69,9 @@ walk(dir); 此外,还有广义的设计模式,这块内容就很多了,但也是讨论如何降低代码复杂度的,包括: -1. 程序代码怎么组织(在开发 web 应用时这块经常有争议,可以参考 [https://cloud.tencent.com/developer/article/1837487](https://cloud.tencent.com/developer/article/1837487)) +1. 程序代码怎么组织(在开发 web 应用时这块经常有争议,可以参考 [浅析整洁架构之道 (二) 初步了解 The Clean Architecture](https://cloud.tencent.com/developer/article/1837487)) 2. 程序之间怎么组织(是放在一个编成个大的,还是微服务,还是用 FaaS 之类的变体) -3. 一些帮助减少程序复杂度的代码原则:[https://zhuanlan.zhihu.com/p/82324809](https://zhuanlan.zhihu.com/p/82324809) +3. 一些帮助减少程序复杂度的代码原则:[设计模式之 SOLID 原则](https://zhuanlan.zhihu.com/p/82324809) 这部分的学习不能操之过急。个人的建议是: diff --git a/3.编程思维体系构建/3.Y 附加模块:Linux.md b/3.编程思维体系构建/3.Y 附加模块:Linux.md index 70e9b42..52b56d7 100644 --- a/3.编程思维体系构建/3.Y 附加模块:Linux.md +++ b/3.编程思维体系构建/3.Y 附加模块:Linux.md @@ -1,14 +1,15 @@ # 附加模块:Linux -本来这个模块在编程模块内,但是鉴于大家都反应做这一块非常难,因此我将他提出作为一个额外的附加模块。 +::: warning 😇 本来这个模块在编程模块内,但是鉴于大家都反应做这一块非常难,因此我将他提出作为一个额外的附加模块。 如果你想尝试使用 Linux 编程或者想了解更多计算机科学领域知识,你可以学习并阅览本部分内容。 当然你也可以先尝试完成第三部分的一些内容再回过头解决本部分的内容。 可能会花费你大量的时间,并且让你感受到非常困难,但是可以保证的是:你的一切投入,都是有收获的。 +::: -# What???Linux??? +## What???Linux??? 大家可能知道我们的电脑是 Windows 作为操作系统的。 @@ -16,12 +17,12 @@ 它既免费也自由 (能知道它内部的实现),而且互联网上有丰富的 (英文) 文档。 -它的设计继承自 “Keep it simple, stupid” 的 UNIX,这个经典的设计背后的动机反而更容易为第一次接触操作系统的初学者所理解。让我们看看它的威力: +它的设计继承自“Keep it simple, stupid”的 UNIX,这个经典的设计背后的动机反而更容易为第一次接触操作系统的初学者所理解。让我们看看它的威力: - 首先,操作系统里的一切对象都用文件表示 (Everything is a file)。进程、设备……都可以在任何编程语言里用文件 API 访问。 -- Linux 的命令行 Shell 是一门编程语言——没错,你每天都在 “编程”!更准确地说,Shell 的功能就是把你想要做的事情 (类似自然语言描述的代码) 翻译成操作系统能看懂的文件/进程管理 API 调用。 +- Linux 的命令行 Shell 是一门编程语言——没错,你每天都在“编程”!更准确地说,Shell 的功能就是把你想要做的事情 (类似自然语言描述的代码) 翻译成操作系统能看懂的文件/进程管理 API 调用。 -# Why Linux??? +## Why Linux??? 作为一个双系统用户体验者来说,他除了玩游戏不那么方便以外,可以更为高效且便捷的办到 Windows 费很大力气才能办到的事情。 @@ -29,11 +30,11 @@ 并且目前,服务器上为了保证低损耗,高效率,基本上百分之九十九都是 Linux 的系统,实验室的服务器也是 Linux 系统。 -简单来说就是,你如果想干点事情,肯定要靠 Linux,因此学会 Linux 的操作是不可或缺的 +简单来说就是,你如果想干点事情,肯定要靠 Linux,因此学会 Linux 的操作是不可或缺的 -而且我个人认为,linux的自由性对于CSer来说非常适合,他不会阻止你干任何操作,你可以充分体会所以你的命令带来的影响(rm -rf /) +而且我个人认为,linux 的自由性对于 CSer 来说非常适合,他不会阻止你干任何操作,你可以充分体会所以你的命令带来的影响 (rm -rf /) -## GUI 与 CLI +### GUI 与 CLI 诚然,我们现在的图形化界面(GUI)已经深入到了生活的方方面面,但是优劣如何对比呢? @@ -41,15 +42,15 @@ 这篇文章详细对比了图形化界面和单纯的终端命令的优劣 -# How Linux??? +## How Linux??? 那么这么好的东西哪里可以获得呢? 因为 Linux 有诸多发行版本,我在这里建议大家使用 Ubuntu22.04 作为主要版本进行使用 -如果你很猛,去试试arch! +如果你很猛,去试试 arch! -任务:装 Ubuntu22.04或者debian,如果你想删了自己的系统,可以试试deepin,当然,也会有一些兼容性问题,不过很支持一些中文软件 +任务:装 Ubuntu22.04 或者 debian,如果你想删了自己的系统,可以试试 deepin,当然,也会有一些兼容性问题,不过会支持一些中文软件 tip1:推荐这个 [3.Y.1VMware 的安装与安装 ubuntu22.04 系统](3.Y.1VMware%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E5%AE%89%E8%A3%85Ubuntu22.04%E7%B3%BB%E7%BB%9F.md) @@ -57,4 +58,4 @@ tip2:可以使用 WSL[3.Y.2WSL 的安装](3.Y.2WSL%E7%9A%84%E5%AE%89%E8%A3%85. tip3:前两个 tip 二选一 -任务:阅读 GUI 与命令行之间对比的文章,尝试开始阅读英文文章 +任务:阅读 GUI 与命令行之间对比的文章,尝试开始阅读英文文章 diff --git a/3.编程思维体系构建/3.Y.0计算机教育中缺失的一课.md b/3.编程思维体系构建/3.Y.0计算机教育中缺失的一课.md index 08d8fb6..fc4069a 100644 --- a/3.编程思维体系构建/3.Y.0计算机教育中缺失的一课.md +++ b/3.编程思维体系构建/3.Y.0计算机教育中缺失的一课.md @@ -1,18 +1,16 @@ -Author : ek1ng , Data : 2023.07.24 , Mail : ek1ng@qq.com +# 计算机教育中缺失的一课 + +Author : ek1ng , Data : 2023.07.24 , Mail : ## 计算机教育中缺失的一课 - +> > [https://missing-semester-cn.github.io/](https://missing-semester-cn.github.io/) -> > [https://ek1ng.com/Missing%20Semester.html](https://ek1ng.com/Missing%20Semester.html) 这是一份国外的课程,主要专注于各类工具的使用,可以看一看课程的介绍: -``` -大学里的计算机课程通常专注于讲授从操作系统到机器学习这些学院派的课程或主题,而对于如何精通工具这一主题则往往会留给学生自行探索。在这个系列课程中,我们讲授命令行、强大的文本编辑器的使用、使用版本控制系统提供的多种特性等等。学生在他们受教育阶段就会和这些工具朝夕相处(在他们的职业生涯中更是这样)。 - -因此,花时间打磨使用这些工具的能力并能够最终熟练地、流畅地使用它们是非常有必要的。 -``` +>大学里的计算机课程通常专注于讲授从操作系统到机器学习这些学院派的课程或主题,而对于如何精通工具这一主题则往往会留给学生自行探索。在这个系列课程中,我们讲授命令行、强大的文本编辑器的使用、使用版本控制系统提供的多种特性等等。学生在他们受教育阶段就会和这些工具朝夕相处(在他们的职业生涯中更是这样)。 +>因此,花时间打磨使用这些工具的能力并能够最终熟练地、流畅地使用它们是非常有必要的。 以及相应的目录: @@ -21,7 +19,7 @@ Author : ek1ng , Data : 2023.07.24 , Mail : ek1ng@qq.com - **1/15**: [编辑器 (Vim)](https://missing-semester-cn.github.io/2020/editors/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//editors-solution) - **1/16**: [数据整理](https://missing-semester-cn.github.io/2020/data-wrangling/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//data-wrangling-solution) - **1/21**: [命令行环境](https://missing-semester-cn.github.io/2020/command-line/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//command-line-solution) -- **1/22**: [版本控制(Git)](https://missing-semester-cn.github.io/2020/version-control/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//version-control-solution) +- **1/22**: [版本控制 (Git)](https://missing-semester-cn.github.io/2020/version-control/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//version-control-solution) - **1/23**: [调试及性能分析](https://missing-semester-cn.github.io/2020/debugging-profiling/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//debugging-profiling-solution) - **1/27**: [元编程](https://missing-semester-cn.github.io/2020/metaprogramming/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//metaprogramming-solution) - **1/28**: [安全和密码学](https://missing-semester-cn.github.io/2020/security/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//security-solution) @@ -30,4 +28,4 @@ Author : ek1ng , Data : 2023.07.24 , Mail : ek1ng@qq.com 目录中的内容和这份`Wiki`中不少内容重合,当然我觉得作为一份校园学生为爱发电多人合作编辑的`Wiki`,内容有重复冗余再所难免。我比较推荐以这份教材作为计算机工具的学习,下面是我大一时学习课程的一些记录,这些课程都比较缺少一些中文的文章,能够直接看英文的一些材料当然很好,但是如果遇到一些困难,也许你可以在这里找到我先前所踩的坑。 -> [https://ek1ng.com/Missing%20Semester.html](https://ek1ng.com/Missing%20Semester.html) \ No newline at end of file +> [The Missing Semester of Your CS Education](https://ek1ng.com/Missing%20Semester.html) diff --git a/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md b/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md index cc42b14..e88b0e7 100644 --- a/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md +++ b/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md @@ -1,6 +1,7 @@ # VMware 的安装与安装 Ubuntu22.04 系统 -与 wsl 安装二选一 安装了 wsl 不用 VMware +::: warning 💡 与 wsl 安装二选一 安装了 wsl 不用 VMware +::: 首先下载 VMware @@ -8,7 +9,7 @@ 如果是 pro17 版本(key JU090-6039P-08409-8J0QH-2YR7F ) -本文写的时候用的版本是 pro16 ,但目前已经更新到 pro17 所以来更新个 key (如下安装与 16 版本无异) +本文写的时候用的版本是 pro16,但目前已经更新到 pro17 所以来更新个 key(如下安装与 16 版本无异) [https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html](https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html) @@ -32,7 +33,7 @@ ![](https://cdn.xyxsw.site/boxcnGHnjgZvtcBrm0XXitFl4Jg.png) -创建新的虚拟机-典型(推荐)-下一步-安装程序 iso 选中你刚下的 iso 下一步 +创建新的虚拟机 - 典型(推荐)- 下一步 - 安装程序 iso 选中你刚下的 iso 下一步 ![](https://cdn.xyxsw.site/boxcnXilUhHNEyU4r95FxiVgCdg.png) @@ -96,7 +97,7 @@ 右上角 logout 重新登陆 就是中文辣 -最后在设置-电源把息屏改成从不 +最后在设置 - 电源把息屏改成从不 ![](https://cdn.xyxsw.site/boxcnnLCJzGoFrUbWIMAPGFkxcb.png) diff --git a/3.编程思维体系构建/3.Y.2WSL的安装.md b/3.编程思维体系构建/3.Y.2WSL的安装.md index 2a8aaed..e70a953 100644 --- a/3.编程思维体系构建/3.Y.2WSL的安装.md +++ b/3.编程思维体系构建/3.Y.2WSL的安装.md @@ -1,6 +1,7 @@ # WSL 的安装 -与 VMware 安装二选一 安装了 VMware 不用 wsl +::: warning 💡与 VMware 安装二选一 安装了 VMware 不用 wsl +::: 先说坏处: diff --git a/3.编程思维体系构建/3.Y.3Linux初探索.md b/3.编程思维体系构建/3.Y.3Linux初探索.md index 55e0b8f..0d97033 100644 --- a/3.编程思维体系构建/3.Y.3Linux初探索.md +++ b/3.编程思维体系构建/3.Y.3Linux初探索.md @@ -1,131 +1,134 @@ # Linux 初探索 -如果你是第一次接触link,请一边仔细阅读,一边尝试敲命令在终端内。 +如果你是第一次接触 link,请一边仔细阅读,一边尝试敲命令在终端内。 有一点非常重要,这章节的内容到后面会略为困难,并且 linux 知识繁杂多样。 希望你可以参考这个链接! [一些基本常识](https://linux.cn/article-6160-1.html) -当然,你也可以从蓝桥云课开始,不过学会linux的最好办法是删掉你的windows换一个linux系统当开发环境,比任何临时的训练都有效! +当然,你也可以从蓝桥云课开始,不过学会 linux 的最好办法是删掉你的 windows 换一个 linux 系统当开发环境,比任何临时的训练都有效! -# 探索命令行 +[蓝桥云课-Linux 基础入门](https://www.lanqiao.cn/courses/1) -Linux 命令行中的命令使用格式都是相同的: +## 探索命令行 -``` +Linux 命令行中的命令使用格式都是相同的: + +```bash 命令名称 参数1 参数2 参数3 ... ``` -参数之间用任意数量的空白字符分开. 关于命令行, 可以先阅读[一些基本常识](https://linux.cn/article-6160-1.html). 然后我们介绍最常用的一些命令: +参数之间用任意数量的空白字符分开。关于命令行,可以先阅读[一些基本常识](https://linux.cn/article-6160-1.html). 然后我们介绍最常用的一些命令: - (重要)首先教一个命令 `sudo su` 进入 root 账户(敲完之后会让你敲当前登录账户的密码 密码敲得过程中没有*****这种传统敲密码的提示 为 linux 传统艺能 其实是敲进去了),因为本身普通账户没什么权限,会出现处处的权限提示,建议直接使用 root 账户。 -``` -这里有一个彩蛋 (如果你用的是centos的话) -当用户第一次使用sudo权限时CentOS的系统提示: +```text +这里有一个彩蛋(如果你用的是 centos 的话) +当用户第一次使用 sudo 权限时 CentOS 的系统提示: 我们信任您已经从系统管理员那里了解了日常注意事项。 总结起来无外乎这三点: #1) 尊重别人的隐私。 -#2) 输入前要先考虑(后果和风险)。 +#2) 输入前要先考虑 (后果和风险)。 #3) 权力越大,责任越大。 ``` -- `ls` 用于列出当前目录(即"文件夹")下的所有文件(或目录). 目录会用蓝色显示. `ls -l` 可以显示详细信息. -- `pwd` 能够列出当前所在的目录. -- `cd DIR` 可以切换到 `DIR` 目录. 在 Linux 中, 每个目录中都至少包含两个目录: `.` 指向该目录自身, `..` 指向它的上级目录. 文件系统的根是 `/`. -- `touch NEWFILE` 可以创建一个内容为空的新文件 `NEWFILE`, 若 `NEWFILE` 已存在, 其内容不会丢失. -- `cp SOURCE DEST` 可以将 `SOURCE` 文件复制为 `DEST` 文件; 如果 `DEST` 是一个目录, 则将 `SOURCE` 文件复制到该目录下. -- `mv SOURCE DEST` 可以将 `SOURCE` 文件重命名为 `DEST` 文件; 如果 `DEST` 是一个目录, 则将 `SOURCE` 文件移动到该目录下. -- `mkdir DIR` 能够创建一个 `DIR` 目录. -- `rm FILE` 能够删除 `FILE` 文件; 如果使用 `-r` 选项则可以递归删除一个目录. 删除后的文件无法恢复, 使用时请谨慎! -- `man` 可以查看命令的帮助. 例如 `man ls` 可以查看 `ls` 命令的使用方法. 灵活应用 `man` 和互联网搜索, 可以快速学习新的命令. +- `ls` 用于列出当前目录 (即"文件夹") 下的所有文件 (或目录). 目录会用蓝色显示。`ls -l` 可以显示详细信息。 +- `pwd` 能够列出当前所在的目录。 +- `cd DIR` 可以切换到 `DIR` 目录。在 Linux 中,每个目录中都至少包含两个目录:`.` 指向该目录自身,`..` 指向它的上级目录。文件系统的根是 `/`. +- `touch NEWFILE` 可以创建一个内容为空的新文件 `NEWFILE`, 若 `NEWFILE` 已存在,其内容不会丢失。 +- `cp SOURCE DEST` 可以将 `SOURCE` 文件复制为 `DEST` 文件; 如果 `DEST` 是一个目录,则将 `SOURCE` 文件复制到该目录下。 +- `mv SOURCE DEST` 可以将 `SOURCE` 文件重命名为 `DEST` 文件; 如果 `DEST` 是一个目录,则将 `SOURCE` 文件移动到该目录下。 +- `mkdir DIR` 能够创建一个 `DIR` 目录。 +- `rm FILE` 能够删除 `FILE` 文件; 如果使用 `-r` 选项则可以递归删除一个目录。删除后的文件无法恢复,使用时请谨慎! +- `man` 可以查看命令的帮助。例如 `man ls` 可以查看 `ls` 命令的使用方法。灵活应用 `man` 和互联网搜索,可以快速学习新的命令。 -`man` 的功能不仅限于此. `man` 后可以跟两个参数, 可以查看不同类型的帮助(请在互联网上搜索). 例如当你不知道 C 标准库函数 `freopen` 如何使用时, 可以键入命令 +`man` 的功能不仅限于此。`man` 后可以跟两个参数,可以查看不同类型的帮助 (请在互联网上搜索). 例如当你不知道 C 标准库函数 `freopen` 如何使用时,可以键入命令 -``` +```bash man 3 freopen ``` -## 统计代码行数 +### 统计代码行数 -第一个例子是统计一个目录中(包含子目录)中的代码行数. 如果想知道当前目录下究竟有多少行的代码, 就可以在命令行中键入如下命令: +第一个例子是统计一个目录中 (包含子目录) 中的代码行数。如果想知道当前目录下究竟有多少行的代码,就可以在命令行中键入如下命令: -``` +```bash find . | grep '\.c$\|\.h$' | xargs wc -l ``` -如果用 `man find` 查看 `find` 操作的功能, 可以看到 `find` 是搜索目录中的文件. Linux 中一个点 `.` 始终表示 Shell 当前所在的目录, 因此 `find .` 实际能够列出当前目录下的所有文件. 如果在文件很多的地方键入 `find .`, 将会看到过多的文件, 此时可以按 `CTRL + c` 退出. +如果用 `man find` 查看 `find` 操作的功能,可以看到 `find` 是搜索目录中的文件。Linux 中一个点 `.` 始终表示 Shell 当前所在的目录,因此 `find .` 实际能够列出当前目录下的所有文件。如果在文件很多的地方键入 `find .`, 将会看到过多的文件,此时可以按 `CTRL + c` 退出。 -同样, 用 `man` 查看 `grep` 的功能——"print lines matching a pattern". `grep` 实现了输入的过滤, 我们的 `grep` 有一个参数, 它能够匹配以 `.c` 或 `.h` 结束的文件. 正则表达式是处理字符串非常强大的工具之一, 每一个程序员都应该掌握其相关的知识. ? 上述的 `grep` 命令能够提取所有 `.c` 和 `.h` 结尾的文件. +同样,用 `man` 查看 `grep` 的功能——"print lines matching a pattern". `grep` 实现了输入的过滤,我们的 `grep` 有一个参数,它能够匹配以 `.c` 或 `.h` 结束的文件。正则表达式是处理字符串非常强大的工具之一,每一个程序员都应该掌握其相关的知识。? 上述的 `grep` 命令能够提取所有 `.c` 和 `.h` 结尾的文件。 -刚才的 `find` 和 `grep` 命令, 都从标准输入中读取数据, 并输出到标准输出. 关于什么是标准输入输出, 请参考[这里](http://en.wikipedia.org/wiki/Standard_streams). 连接起这两个命令的关键就是管道符号 `|`. 这一符号的左右都是 Shell 命令, `A | B` 的含义是创建两个进程 `A` 和 `B`, 并将 `A` 进程的标准输出连接到 `B` 进程的标准输入. 这样, 将 `find` 和 `grep` 连接起来就能够筛选出当前目录(`.`)下所有以 `.c` 或 `.h` 结尾的文件. +刚才的 `find` 和 `grep` 命令,都从标准输入中读取数据,并输出到标准输出。关于什么是标准输入输出,请参考[这里](http://en.wikipedia.org/wiki/Standard_streams). 连接起这两个命令的关键就是管道符号 `|`. 这一符号的左右都是 Shell 命令,`A | B` 的含义是创建两个进程 `A` 和 `B`, 并将 `A` 进程的标准输出连接到 `B` 进程的标准输入。这样,将 `find` 和 `grep` 连接起来就能够筛选出当前目录 (`.`) 下所有以 `.c` 或 `.h` 结尾的文件。 -我们最后的任务是统计这些文件所占用的总行数, 此时可以用 `man` 查看 `wc` 命令. `wc` 命令的 `-l` 选项能够计算代码的行数. `xargs` 命令十分特殊, 它能够将标准输入转换为参数, 传送给第一个参数所指定的程序. 所以, 代码中的 `xargs wc -l` 就等价于执行 `wc -l aaa.c bbb.c include/ccc.h ...`, 最终完成代码行数统计. +我们最后的任务是统计这些文件所占用的总行数,此时可以用 `man` 查看 `wc` 命令。`wc` 命令的 `-l` 选项能够计算代码的行数。`xargs` 命令十分特殊,它能够将标准输入转换为参数,传送给第一个参数所指定的程序。所以,代码中的 `xargs wc -l` 就等价于执行 `wc -l aaa.c bbb.c include/ccc.h ...`, 最终完成代码行数统计。 -## 统计磁盘使用情况 +### 统计磁盘使用情况 -以下命令统计 `/usr/share` 目录下各个目录所占用的磁盘空间: +以下命令统计 `/usr/share` 目录下各个目录所占用的磁盘空间: -``` +```bash du -sc /usr/share/* | sort -nr ``` -`du` 是磁盘空间分析工具, `du -sc` 将目录的大小顺次输出到标准输出, 继而通过管道传送给 `sort`. `sort` 是数据排序工具, 其中的选项 `-n` 表示按照数值进行排序, 而 `-r` 则表示从大到小输出. `sort` 可以将这些参数连写在一起. +`du` 是磁盘空间分析工具,`du -sc` 将目录的大小顺次输出到标准输出,继而通过管道传送给 `sort`. `sort` 是数据排序工具,其中的选项 `-n` 表示按照数值进行排序,而 `-r` 则表示从大到小输出。`sort` 可以将这些参数连写在一起。 -然而我们发现, `/usr/share` 中的目录过多, 无法在一个屏幕内显示. 此时, 我们可以再使用一个命令: `more` 或 `less`. +然而我们发现,`/usr/share` 中的目录过多,无法在一个屏幕内显示。此时,我们可以再使用一个命令:`more` 或 `less`. -``` +```bash du -sc /usr/share/* | sort -nr | more ``` -此时将会看到输出的前几行结果. `more` 工具使用空格翻页, 并可以用 `q` 键在中途退出. `less` 工具则更为强大, 不仅可以向下翻页, 还可以向上翻页, 同样使用 `q` 键退出. 这里还有一个[关于 less 的小故事](http://en.wikipedia.org/wiki/Less_(Unix)). +此时将会看到输出的前几行结果。`more` 工具使用空格翻页,并可以用 `q` 键在中途退出。`less` 工具则更为强大,不仅可以向下翻页,还可以向上翻页,同样使用 `q` 键退出。这里还有一个[关于 less 的小故事](http://en.wikipedia.org/wiki/Less_(Unix)). -## 在 Linux 下编写 Hello World 程序 +### 在 Linux 下编写 Hello World 程序 -Linux 中用户的主目录是 `/home/用户名称`, 如果你的用户名是 `user`, 你的主目录就是 `/home/user`. 用户的 `home` 目录可以用波浪符号 `~` 替代, 例如临时文件目录 `/home/user/Templates` 可以简写为 `~/Templates`. 现在我们就可以进入主目录并编辑文件了. 如果 `Templates` 目录不存在, 可以通过 `mkdir` 命令创建它: +Linux 中用户的主目录是 `/home/用户名称`, 如果你的用户名是 `user`, 你的主目录就是 `/home/user`. 用户的 `home` 目录可以用波浪符号 `~` 替代,例如临时文件目录 `/home/user/Templates` 可以简写为 `~/Templates`. 现在我们就可以进入主目录并编辑文件了。如果 `Templates` 目录不存在,可以通过 `mkdir` 命令创建它: -``` +```bash cd ~ mkdir Templates ``` -创建成功后, 键入 +创建成功后,键入 -``` +```bash cd Templates ``` -可以完成目录的切换. 注意在输入目录名时, `tab` 键可以提供联想. +可以完成目录的切换。注意在输入目录名时,`tab` 键可以提供联想。 -##### 你感到键入困难吗? +#### 你感到键入困难吗? -你可能会经常要在终端里输入类似于 +::: warning 💡 你可能会经常要在终端里输入类似于 cd AVeryVeryLongFileName -的命令, 你一定觉得非常烦躁. 回顾上面所说的原则之一: 如果你感到有什么地方不对, 就一定有什么好办法来解决. 试试 `tab` 键吧. +的命令,你一定觉得非常烦躁。回顾上面所说的原则之一:如果你感到有什么地方不对,就一定有什么好办法来解决。试试 `tab` 键吧。 -Shell 中有很多这样的小技巧, 你也可以使用其他的 Shell 例如 zsh, 提供更丰富好用的功能. 总之, 尝试和改变是最重要的. +Shell 中有很多这样的小技巧,你也可以使用其他的 Shell 例如 zsh, 提供更丰富好用的功能。总之,尝试和改变是最重要的。 +::: -进入正确的目录后就可以编辑文件了, 开源世界中主流的两大编辑器是 `vi(m)` 和 `emacs`, 你可以使用其中的任何一种. 如果你打算使用 `emacs`, 你还需要安装它 +进入正确的目录后就可以编辑文件了,开源世界中主流的两大编辑器是 `vi(m)` 和 `emacs`, 你可以使用其中的任何一种。如果你打算使用 `emacs`, 你还需要安装它 -``` +```bash apt-get install emacs ``` -`vi` 和 `emacs` 这两款编辑器都需要一定的时间才能上手, 它们共同的特点是需要花较多的时间才能适应基本操作方式(命令或快捷键), 但一旦熟练运用, 编辑效率就比传统的编辑器快很多. +`vi` 和 `emacs` 这两款编辑器都需要一定的时间才能上手,它们共同的特点是需要花较多的时间才能适应基本操作方式 (命令或快捷键), 但一旦熟练运用,编辑效率就比传统的编辑器快很多。 -进入了正确的目录后, 输入相应的命令就能够开始编辑文件. 例如输入 +进入了正确的目录后,输入相应的命令就能够开始编辑文件。例如输入 -``` +```bash vi hello.c 或emacs hello.c ``` -就能开启一个文件编辑. 例如可以键入如下代码(对于首次使用 `vi` 或 `emacs` 的同学, 键入代码可能会花去一些时间, 在编辑的同时要大量查看网络上的资料): +就能开启一个文件编辑。例如可以键入如下代码 (对于首次使用 `vi` 或 `emacs` 的同学,键入代码可能会花去一些时间,在编辑的同时要大量查看网络上的资料): -``` +```c #include int main(void) { printf("Hello, Linux World!\n"); @@ -134,23 +137,22 @@ int main(void) { ``` > 相信你在写完代码之后苦于不知道怎么保存并退出,不用担心,这个是正常的,毕竟上面提到的两个文本编辑器都是以入门时的学习曲线及其陡峭而著称。 -> 对于 vi(m)风格的编辑器,你需要先按 `ESC` 返回 NORMAL 模式(具体处于那个模式可以观察窗口左下角,NORMAL 模式是空白的),再输入 `:wq` 来保存并退出(注意 `:` 是输入的一部分 )(`:q 仅退出` `:q! 不保存退出` ) +> 对于 vi(m) 风格的编辑器,你需要先按 `ESC` 返回 NORMAL 模式(具体处于那个模式可以观察窗口左下角,NORMAL 模式是空白的),再输入 `:wq` 来保存并退出(注意 `:` 是输入的一部分)(`:q 仅退出` `:q! 不保存退出` ) > > [【保姆级入门】Vim 编辑器](https://www.bilibili.com/video/BV13t4y1t7Wg) > > -保存后就能够看到 `hello.c` 的内容了. 终端中可以用 `cat hello.c` 查看代码的内容. 如果要将它编译, 可以使用 `gcc` 命令: +保存后就能够看到 `hello.c` 的内容了。终端中可以用 `cat hello.c` 查看代码的内容。如果要将它编译,可以使用 `gcc` 命令: -``` +```bash gcc hello.c -o hello ``` -`gcc` 的 `-o` 选项指定了输出文件的名称, 如果将 `-o hello` 改为 `-o hi`, 将会生成名为 `hi` 的可执行文件. 如果不使用 `-o` 选项, 则会默认生成名为 `a.out` 的文件, 它的含义是 [assembler output](http://en.wikipedia.org/wiki/A.out). 在命令行输入 +`gcc` 的 `-o` 选项指定了输出文件的名称,如果将 `-o hello` 改为 `-o hi`, 将会生成名为 `hi` 的可执行文件。如果不使用 `-o` 选项,则会默认生成名为 `a.out` 的文件,它的含义是 [assembler output](http://en.wikipedia.org/wiki/A.out). 在命令行输入 -``` +```bash ./hello ``` -就能够运行改程序. 命令中的 `./` 是不能少的, 点代表了当前目录, 而 `./hello` 则表示当前目录下的 `hello` 文件. 与 Windows 不同, Linux 系统默认情况下并不查找当前目录, 这是因为 Linux 下有大量的标准工具(如 `test` 等), 很容易与用户自己编写的程序重名, 不搜索当前目录消除了命令访问的歧义. - +就能够运行改程序。命令中的 `./` 是不能少的,点代表了当前目录,而 `./hello` 则表示当前目录下的 `hello` 文件。与 Windows 不同,Linux 系统默认情况下并不查找当前目录,这是因为 Linux 下有大量的标准工具 (如 `test` 等), 很容易与用户自己编写的程序重名,不搜索当前目录消除了命令访问的歧义。 diff --git a/3.编程思维体系构建/3.Y.4Vim初探索.md b/3.编程思维体系构建/3.Y.4Vim初探索.md index eb75c52..0c67c33 100644 --- a/3.编程思维体系构建/3.Y.4Vim初探索.md +++ b/3.编程思维体系构建/3.Y.4Vim初探索.md @@ -1,29 +1,31 @@ # Vim 初探索 -# 下载 vim +## 下载 vim vim 被称为编辑器之神 -看到这一句可能就激发了你学习 vim 的热情,但是看完整篇文章和文章里面的所有参考资料,可能这股来之不易的热情也早就消失了。为了避免这种情况,我给一个小小的建议: +::: warning 💡 看到这一句可能就激发了你学习 vim 的热情,但是看完整篇文章和文章里面的所有参考资料,可能这股来之不易的热情也早就消失了。为了避免这种情况,我给一个小小的建议: 1. 首先学会盲打,不会的话,不是很建议用 vim / Emacs 这样的编辑器,还是拥抱鼠标吧 2. 学习使用 hjklia 这六个键,然后理解插入模式和普通模式,再了解怎么退出 3. 使用 vim 作为日常的编辑工具,在你所有的代码编辑器里面都装上 vim 插件并使用,强迫自己习惯 hjkl 的移动和带模式的输入,习惯按 `` 4. 到这个时候你就会感觉的确可以不用鼠标了,但是有的时候会比较别扭,比如想新建一行时,得按 L 移到行尾,然后按 a 追加,再按回车,远远比鼠标麻烦有没有,这种情况就可以上网查询,`vim 如何新建一行`,就会学到 o 可以向下新建一行,O 可以向上新建一行,然后你就能自然地学会更多的操作。 +::: 因为其具有着非常完整的生态以及诸多配套的插件,但是第一次使用得你可能感觉很不习惯。 讲一个笑话,你如何获得一个随机字符串,只要让新人使用 vim 就好了。 -不开玩笑,为了让你不小心在命令行模式下进入 vim 又不知道怎么退出时不需要拔电源来退出,先按几次 `` 键(避免你之前不小心按到了 i 或 a 或 o 或等等按键)进入普通模式,然后顺序敲击 `:q`(冒号 和 q 两个按键 ),再按回车就可以退出了。 +::: waning 💡 不开玩笑,为了让你不小心在命令行模式下进入 vim 又不知道怎么退出时不需要拔电源来退出,先按几次 `` 键(避免你之前不小心按到了 i 或 a 或 o 或等等按键)进入普通模式,然后顺序敲击 `:q`(冒号 和 q 两个按键 ),再按回车就可以退出了。 +::: -``` +```bash apt-get install vim ``` 但是我仍然推荐你尝试使用或者结合 VSC 一起使用,使用习惯后将有效提高你的开发效率。 -# 如何学习 vim +## 如何学习 vim 作为程序员,我们大部分时间都花在代码编辑上,所以花点时间掌握某个适合自己的编辑器是非常值得的。通常学习使用一个新的编辑器包含以下步骤: @@ -33,25 +35,25 @@ apt-get install vim 如果您能够遵循上述步骤,并且坚持使用新的编辑器完成您所有的文本编辑任务,那么学习一个复杂的代码编辑器的过程一般是这样的:头两个小时,您会学习到编辑器的基本操作,例如打开和编辑文件、保存与退出、浏览缓冲区。当学习时间累计达到 20 个小时之后,您使用新编辑器的效率应该已经和使用老编辑器一样快。在此之后,其益处开始显现:有了足够的知识和肌肉记忆后,使用新编辑器将大大节省你的时间。而现代文本编辑器都是些复杂且强大的工具,永远有新东西可学:学的越多,效率越高。 -# Vim 的哲学 +## Vim 的哲学 -在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以,Vim 是一个_多模态_编辑 器:它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言),Vim 的接口本身也是一个程序语言:键入操作(以及其助记名) 是命令,这些命令也是可组合的。Vim 避免了使用鼠标,因为那样太慢了;Vim 甚至避免用 上下左右键因为那样需要太多的手指移动。 +在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以,Vim 是一个_多模态_编辑 器:它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言),Vim 的接口本身也是一个程序语言:键入操作(以及其助记名)是命令,这些命令也是可组合的。Vim 避免了使用鼠标,因为那样太慢了;Vim 甚至避免用 上下左右键因为那样需要太多的手指移动。 这样的设计哲学使得 Vim 成为了一个能跟上你思维速度的编辑器。 -# 学习 Vim +## 学习 Vim 如果想要使用他最基本的操作的话,在电脑上键入 vimtutor 会有官方的教程进行引导哦。 -# 配置 vim +## 配置 vim vim 有大量的配置,通过更改./vimrc 文件或者安装插件都可以有效提高你的开发效率,定制属于你个人的编辑器哦~ 快去试试吧 -# 任务 +## 任务 定制 vim 成为你喜欢的模样,加装足够多的插件和更改足够多的配置让他满足以下几点或以上 @@ -67,7 +69,7 @@ vim 有大量的配置,通过更改./vimrc 文件或者安装插件都可以 [vim awesome](https://vimawesome.com/) -# 拓展阅读 +## 拓展阅读 [Learn-Vim(the Smart Way) 中文翻译](https://github.com/wsdjeg/Learn-Vim_zh_cn) diff --git a/3.编程思维体系构建/3.Y.5linux小任务.md b/3.编程思维体系构建/3.Y.5linux小任务.md index 33fecfb..fa93a8d 100644 --- a/3.编程思维体系构建/3.Y.5linux小任务.md +++ b/3.编程思维体系构建/3.Y.5linux小任务.md @@ -6,19 +6,19 @@ 4. 用 `touch` 在 `missing` 文件夹中新建一个叫 `semester` 的文件。 5. 将以下内容一行一行地写入 `semester` 文件: -``` +```bash #!/bin/sh curl --head --silent https://missing.csail.mit.edu ``` -第一行可能有点棘手, `#` 在 Bash 中表示注释,而 `!` 即使被双引号(`"`)包裹也具有特殊的含义。 单引号(`'`)则不一样,此处利用这一点解决输入问题。更多信息请参考 Bash quoting 手册 +第一行可能有点棘手, `#` 在 Bash 中表示注释,而 `!` 即使被双引号(`"`)包裹也具有特殊的含义。单引号(`'`)则不一样,此处利用这一点解决输入问题。更多信息请参考 Bash quoting 手册 1. 尝试执行这个文件。例如,将该脚本的路径(`./semester`)输入到您的 shell 中并回车。如果程序无法执行,请使用 `ls` 命令来获取信息并理解其不能执行的原因。 -2. 查看 `chmod` 的手册(例如,使用 `man chmod` 命令) +2. 查看 `chmod` 的手册 (例如,使用 `man chmod` 命令) 3. 使用 `chmod` 命令改变权限,使 `./semester` 能够成功执行,不要使用 `sh semester` 来执行该程序。您的 shell 是如何知晓这个文件需要使用 `sh` 来解析呢?更多信息请参考:shebang 4. 使用 `|` 和 `>` ,将 `semester` 文件输出的最后更改日期信息,写入主目录下的 `last-modified.txt` 的文件中 5. 写一段命令来从 `/sys` 中获取笔记本的电量信息,或者台式机 CPU 的温度 -6. 使用shell编程写一个类似脚本的图书管理系统,包含增删改查四个功能 +6. 使用 shell 编程写一个类似脚本的图书管理系统,包含增删改查四个功能 当然,可能会有点困难我在这里附上一段参考代码 @@ -124,4 +124,3 @@ search() } ``` - diff --git a/3.编程思维体系构建/3.编程思维体系构建.md b/3.编程思维体系构建/3.编程思维体系构建.md index 58191cb..9e44401 100644 --- a/3.编程思维体系构建/3.编程思维体系构建.md +++ b/3.编程思维体系构建/3.编程思维体系构建.md @@ -8,7 +8,7 @@ 但是,他作为一个交通工具,你不开你就得腿着去学校。想想如果你从杭电走到西湖只能走着去,那是多么恐怖的一件事。 -(当然,现在GPT的强大功能可以帮大伙解决相当多的工作,因此,我们可能需要掌握更多的逻辑思维能力和分解问题的能力,将问题简化之后用GPT解决也不失为一个选择) +(当然,现在 GPT 的强大功能可以帮大伙解决相当多的工作,因此,我们可能需要掌握更多的逻辑思维能力和分解问题的能力,将问题简化之后用 GPT 解决也不失为一个选择) 因此本章节的目标是让大家面对一个实际问题,有使用编程解决的思路和能力。 @@ -16,37 +16,34 @@ 本章提供了非常多的软实力文章,阅读相关软实力文章,你可以根据自己的情况构建适合自己一通百通的学习编程知识的方法论。 -本章提供了相当完善的,足够面对多数需求的C语言体系结构,通过完成C语言的体系,你可以较为熟练地掌握C语言,并且对构建一个较小规模的项目组织和项目拆分有一定的理解 +本章提供了相当完善的,足够面对多数需求的 C 语言体系结构,通过完成 C 语言的体系,你可以较为熟练地掌握 C 语言,并且对构建一个较小规模的项目组织和项目拆分有一定的理解 -python内容完成后,基本学习到如何使用python当一门工具使用,当有具体的需求可以进行后续的补充学习 +python 内容完成后,基本学习到如何使用 python 当一门工具使用,当有具体的需求可以进行后续的补充学习 -与此同时,Git or Linux也是作为一个CSer 或者说想要提升自身效率的程序员,不可或缺的一个内容,希望你能掌握 +与此同时,Git or Linux 也是作为一个 CSer 或者说想要提升自身效率的程序员,不可或缺的一个内容,希望你能掌握 -如果你要开始,推荐你从3.0开始阅读,然后挑选你喜欢的内容 +如果你要开始,推荐你从 3.0 开始阅读,然后挑选你喜欢的内容 ![](https://cdn.xyxsw.site/boxcnOrKXUsIPJAUXyGB3Txewve.png) - ## 本章参考内容 [cs61a](https://cs61a.org/) -[CS自学指南](https://csdiy.wiki/) +[CS 自学指南](https://csdiy.wiki/) [MIT-Missing-Semester](https://missing.csail.mit.edu/2020/) [Introductory C Programming](https://www.coursera.org/specializations/c-programming) -[一生一芯nemu](https://ysyx.oscc.cc/) +[一生一芯 nemu](https://ysyx.oscc.cc/) -[jyy的OS课程](https://jyywiki.cn/) +[jyy 的 OS 课程](https://jyywiki.cn/) -[迷宫game](https://github.com/helderman/htpataic) +[迷宫 game](https://github.com/helderman/htpataic) [GDB User Manual](https://www.sourceware.org/gdb/) [learn vim](https://github.com/wsdjeg/Learn-Vim_zh_cn) Book:教材替换用书——《C Primer Plus》 - -