chore: add 3.4.3

chore: add 3.4.4
chore: add 3.4.5
chore: add 3.4.5.1
chore: add 3.4.6.1
chore: add 3.4.6.2
chore: add 3.4.6.3
chore: add 3.4.6.4
chore: add 3.4.6.5
This commit is contained in:
FallenYing
2023-07-26 02:49:38 +08:00
parent 7a29488280
commit 2373723d17
9 changed files with 91 additions and 97 deletions

View File

@@ -65,4 +65,3 @@
## Debug Program
一旦在代码中发现了问题,就需要修复它,这个过程称为调试。许多新手程序员(甚至一些经验丰富的程序员)以临时方式调试,试图更改代码中的某些内容,并希望它能解决他们的问题。这样的方法很少有效,常常会导致很多挫折。

View File

@@ -18,7 +18,7 @@
7.Web[LinuxC 一站式编程](https://akaedu.github.io/book/)(难度大,枯燥硬核,收获多,基于 linux
### 学习建议:可以选择其一或多种学习
## 学习建议:可以选择其一或多种学习
- 对于缺乏计算机基础这里的基础指的是计算机的日常使用的同学1、2是不错的选择但在学完后要选择 4、5、6 进行补充巩固提高。
- 对于有一定计算机基础的同学,直接上手 4、5、6 都是很不错的选择。

View File

@@ -42,13 +42,13 @@ typedef struct Node* Link;
图 4 所示的链表并不完整,一个完整的链表应该由以下几部分构成:
头指针:是指向链表中一个结点所在存储位置的指针。如果链表中有头结点,则头指针指向头结点;若链表中没有头结点,则头指针指向链表中第一个数据结点(也叫首元结点)。
头指针是指向链表中一个结点所在存储位置的指针。如果链表中有头结点,则头指针指向头结点;若链表中没有头结点,则头指针指向链表中第一个数据结点(也叫首元结点)。
链表有头指针,当我们需要使用链表中的数据时,我们可以使用遍历查找等方法,从头指针指向的结点开始,依次搜索,直到找到需要的数据;反之,若没有头指针,则链表中的数据根本无法使用,也就失去了存储数据的意义。
结点:链表中的节点又细分为头结点、首元结点和其它结点:
头结点:位于链表的表头,即链表中第一个结点,其一般不存储任何数据,特殊情况可存储表示链表信息(表的长度等)的数据。
头结点位于链表的表头,即链表中第一个结点,其一般不存储任何数据,特殊情况可存储表示链表信息(表的长度等)的数据。
头结点的存在,其本身没有任何作用,就是一个空结点,但是在对链表的某些操作中,链表有无头结点,可以直接影响编程实现的难易程度。
@@ -95,7 +95,7 @@ Link* head = (Link*)malloc(sizeof(Link)); //创建头指针
```c
Link p;
while (Judgement) //for同理
while (Judgement) //for 同理
{
p = (Link)malloc(sizeof(Node));
p->elem = element;
@@ -111,7 +111,7 @@ while (Judgement)
```c
Link p;
Link r = (*head); //临时中间结构指针,在尾插法中始终指向最后一个结点
while (Judgement) //for同理
while (Judgement) //for 同理
{
p = (Link)malloc(sizeof(Node));
p->elem = element;
@@ -141,20 +141,20 @@ while (Judgement) //for同理
```c
#define error 0
#define ok 1
/*用e返回L中第i个数据元素的值*/
/*用 e 返回 L 中第 i 个数据元素的值*/
int GetElem(Link *L, int i; int *e)
{
Link p;
p = (*L)->next; //p指向第一个结点
p = (*L)->next; //p 指向第一个结点
int j = 1;
while (p && j < i) //p不为空或者计数器j还没有等于i时,循环继续
while (p && j < i) //p 不为空或者计数器 j 还没有等于 i 时,循环继续
{
p = p->next; //p指向下一个结点
p = p->next; //p 指向下一个结点
j++;
}
if (!p) //第i个元素不存在
if (!p) //第 i 个元素不存在
return error;
*e = p->elem; //取第i个元素的数据
*e = p->elem; //取第 i 个元素的数据
return ok;
}
```
@@ -178,17 +178,17 @@ int GetElem(Link *L, int i; int *e)
![](https://cdn.xyxsw.site/boxcnxjex5Q3Lt9AAx6roN3ClUg.png)
从图中可以看出,虽然新元素的插入位置不同,但实现插入操作的方法是一致的,都是先执行步骤 1 ,再执行步骤 2。实现代码如下
从图中可以看出,虽然新元素的插入位置不同,但实现插入操作的方法是一致的,都是先执行步骤 1再执行步骤 2。实现代码如下
```c
/*在L中第i个位置注意链表中的位置不一定为结点的个数之前插入新的数据元素e
L的长度加一可以用头结点存储链表长度*/
/*在 L 中第 i 个位置(注意链表中的位置不一定为结点的个数)之前插入新的数据元素 e
L 的长度加一(可以用头结点存储链表长度)*/
int ListInsert(Link *L, int i, int e)
{
Link p, r; //r为临时中间结构指针用于实现插入
p = *L; //p指向头结点
Link p, r; //r 为临时中间结构指针,用于实现插入
p = *L; //p 指向头结点
int j = 1;
while (p && j < i) //寻找第i个结点,
while (p && j < i) //寻找第 i 个结点,
{
p = p->next;
j++;
@@ -217,8 +217,8 @@ int ListInsert(Link *L, int i, int e)
实现代码如下:
```c
/*在L中第i个位置注意链表中的位置不一定为结点的个数之前插入新的数据元素e
L的长度加一可以用头结点存储链表长度*/
/*在 L 中第 i 个位置(注意链表中的位置不一定为结点的个数)之前插入新的数据元素 e
L 的长度加一(可以用头结点存储链表长度)*/
int ListInsert(Link *L, int i, int e)
{
if (i == 1)
@@ -258,7 +258,7 @@ temp->next=temp->next->next;
实现代码如下:
```c
/*删除L中的第i个数据元素,并用e返回其值L的长度减一
/*删除 L 中的第 i 个数据元素,并用 e 返回其值L 的长度减一
(可以用头结点存储链表长度)*/
int ListDelete(Link *L, int i, int* e)
{
@@ -271,7 +271,7 @@ int ListDelete(Link *L, int i, int* e)
j++;
}
if (!(p->next))
return error; //L中不存在第i个元素
return error; //L 中不存在第 i 个元素
r = p->next; //标记要删除的结点
p->next = r->next; //移除结点
*e = r->elem; //返回结点所存数据
@@ -287,7 +287,7 @@ int ListDelete(Link *L, int i, int* e)
实现代码如下:
```c
/*删除L中的第i个数据元素,并用e返回其值L的长度减一
/*删除 L 中的第 i 个数据元素,并用 e 返回其值L 的长度减一
(可以用头结点存储链表长度)*/
int ListDelete(Link *L, int i, int* e)
{

View File

@@ -1,30 +1,30 @@
# 阶段一:编程属性
# [C 语言任务模块](https://github.com/E1PsyCongroo/HDU_C_Assignments/)
## [C 语言任务模块](https://github.com/E1PsyCongroo/HDU_C_Assignments/)
作为一名合格的大学生,更应深谙“纸上得来终觉浅,绝知此事要躬行”的道理,编程语言就像是一个工具,无论你如何熟读说明书(语法、特性),未经实践终究是靠不住的。
本模块将以有趣的任务的形式替你检测是否你已经达到了基本掌握C语言语法和一些特性的目的
本模块将以有趣的任务的形式替你检测是否你已经达到了基本掌握 C 语言语法和一些特性的目的
- 该任务模块旨在帮助巩固 C 语言基础知识,传递一些编程思维,入门学习请看 [3.4.4C 语言前置概念学习](3.4.4C%E8%AF%AD%E8%A8%80%E5%89%8D%E7%BD%AE%E6%A6%82%E5%BF%B5%E5%AD%A6%E4%B9%A0.md)
- 你可以通过使用 git `git clone ``https://github.com/E1PsyCongroo/HDU_C_Assignments.git` 获取任务
- 或者访问https://github.com/E1PsyCongroo/HDU_C_Assignments 学习
- 你可以通过使用 git `git clone https://github.com/E1PsyCongroo/HDU_C_Assignments.git` 获取任务
- 或者访问 [https://github.com/E1PsyCongroo/HDU_C_Assignments](https://github.com/E1PsyCongroo/HDU_C_Assignments) 学习
# 任务一做前必查
## 任务一做前必查
1. 理解[3.4.3解决编程问题的普适性过程](3.4.3%E8%A7%A3%E5%86%B3%E7%BC%96%E7%A8%8B%E9%97%AE%E9%A2%98%E7%9A%84%E6%99%AE%E9%80%82%E6%80%A7%E8%BF%87%E7%A8%8B.md) 。
1. 理解[3.4.3 解决编程问题的普适性过程](3.4.3%E8%A7%A3%E5%86%B3%E7%BC%96%E7%A8%8B%E9%97%AE%E9%A2%98%E7%9A%84%E6%99%AE%E9%80%82%E6%80%A7%E8%BF%87%E7%A8%8B.md) 。
2. 理解 C 语言语法基础:变量、表达式、函数、判断、循环、常用标准库函数。
3. 理解 C 语言中的一切都是数字。
4. 初步理解 C 语言各类数据类型:基本数据类型和复杂自定义数据类型。
5. 初步理解 C 语言数组及字符串。
# 任务二做前必查
## 任务二做前必查
1. 深入理解 C 语言指针、数组和字符串。
2. 理解递归思想。
3. 理解复杂自定义数据类型。
### 请阅读各个任务的 README.md了解完成任务所需的前置知识
## 请阅读各个任务的 README.md了解完成任务所需的前置知识
进阶:评价一个程序,大体分为以下四个层次。

View File

@@ -23,7 +23,7 @@ Bye!
尽管可能微不足道,但该程序确实展示 <em>了</em>任何文本冒险中最重要的方面:描述性文本。一个好的故事是制作一款好的冒险游戏的要素之一。
# 为什么要用英文?
## 为什么要用英文?
因为中文的编码模式可能会带来奇怪的影响。

View File

@@ -2,25 +2,25 @@
::: tip 提醒
# <strong> 驾驭项目, 而不是被项目驾驭</strong>
## <strong> 驾驭项目而不是被项目驾驭</strong>
你和一个项目的关系会经历 4 个阶段:
你和一个项目的关系会经历 4 个阶段
1. 被驾驭: 你对它一无所知
2. 一知半解: 你对其中的主要模块和功能有了基本的了解
3. 驾轻就熟: 你对整个项目的细节都了如指掌
4. 为你所用: 你可以随心所欲地在项目中添加你认为有用的功能
1. 被驾驭你对它一无所知
2. 一知半解你对其中的主要模块和功能有了基本的了解
3. 驾轻就熟你对整个项目的细节都了如指掌
4. 为你所用你可以随心所欲地在项目中添加你认为有用的功能
如果你想要达成第二个阶段,你需要仔细学习不断探索更新的内容, 达到第三个阶段的主要手段是独立完成实验内容和独立调试. 至于要达到第四个阶段, 就要靠你的主观能动性了: 代码还有哪里做得不够好? 怎么样才算是够好? 应该怎么做才能达到这个目标?
如果你想要达成第二个阶段,你需要仔细学习不断探索更新的内容达到第三个阶段的主要手段是独立完成实验内容和独立调试至于要达到第四个阶段就要靠你的主观能动性了代码还有哪里做得不够好怎么样才算是够好应该怎么做才能达到这个目标
你毕业后到了工业界或学术界, 就会发现真实的项目也都是这样:
你毕业后到了工业界或学术界就会发现真实的项目也都是这样
1. 刚接触一个新项目, 不知道如何下手
1. 刚接触一个新项目不知道如何下手
2. RTFM, RTFSC, 大致明白项目组织结构和基本的工作流程
3. 运行项目的时候发现有非预期行为(可能是配置错误或环境错误, 可能是和已有项目对接出错, 也可能是项目自身的 bug), 然后调试. 在调试过程中, 对这些模块的理解会逐渐变得清晰.
4. 哪天需要你在项目中添加一个新功能, 你会发现自己其实可以胜任.
3. 运行项目的时候发现有非预期行为 (可能是配置错误或环境错误可能是和已有项目对接出错也可能是项目自身的 bug), 然后调试在调试过程中对这些模块的理解会逐渐变得清晰
4. 哪天需要你在项目中添加一个新功能你会发现自己其实可以胜任
这说明了: 如果你一遇到 bug 就找大神帮你调试, 你失去的机会和能力会比你想象的多得多
这说明了如果你一遇到 bug 就找大神帮你调试你失去的机会和能力会比你想象的多得多
:::
文字冒险游戏的基本交互很简单
@@ -41,7 +41,7 @@
2. 函数<em>parseAndExecute</em>。
3. 函数<em>main</em>,负责重复调用其他两个函数。
# main.c
## main.c
```c
#include <stdbool.h>
@@ -55,7 +55,7 @@ static bool getInput(void)
printf("\n--> ");
//你可以将他改成你喜欢的内容
return fgets(input, sizeof input, stdin) != NULL;
//fgets用于收集键盘的输入
//fgets 用于收集键盘的输入
}
int main()
@@ -71,7 +71,7 @@ int main()
思考题static 是什么意思?我为什么要用他?
# <strong>parsexec.h</strong>
## <strong>parsexec.h</strong>
```c
extern bool parseAndExecute(char *input);
@@ -85,7 +85,7 @@ extern bool parseAndExecute(char *input);
在这里用指针是为了传参的时候可以传字符串哦
# <strong>parsexec.c</strong>
## <strong>parsexec.c</strong>
```c
#include <stdbool.h>
@@ -97,11 +97,11 @@ bool parseAndExecute(char *input)
{
char *verb = strtok(input, " \n");
char *noun = strtok(NULL, " \n");
//strtokstring库下的一个函数
//strtokstring 库下的一个函数
if (verb != NULL)
{
if (strcmp(verb, "quit") == 0)
//strcmp也是
//strcmp 也是
{
return false;
}
@@ -116,14 +116,14 @@ bool parseAndExecute(char *input)
else
{
printf("I don't know how to '%s'.\n", verb);
//%s是verb附加参数的占位符
//%s是 verb 附加参数的占位符
}
}
return true;
}
```
你的编译器可能会给出警告 the unused variable noun这些不用担心将会在下一章解决。
你的编译器可能会给出警告 the unused variablenoun这些不用担心将会在下一章解决。
返回<em>false</em>将导致主循环结束。

View File

@@ -2,11 +2,11 @@
某种极其糟糕的编程习惯
# Copy-paste
## Copy-paste
我们很多同学在编程的过程中,可能会写出一大堆重复性很强的代码,在最近看的 pa 中,举了这样一个例子,你不需要看懂只需要感受到就可:
```
```c
if (strcmp(s, "$0") == 0)
return cpu.gpr[0]._64;
else if (strcmp(s, "ra") == 0)
@@ -90,13 +90,13 @@ bx = torch.cat((xs[0], bs[0], xs[1], bs[1], xs[2], bs[2], xs[3], bs[3], xs[4], b
更可怕的是,这种编码模式可能会导致意想不到的 bug。
当你发现这些代码有 bug 的时候, 噩梦才刚刚开始. 也许花了好几天你又调出一个 bug 的时候, 才会想起这个 bug 你好像之前在哪里调过. 你也知道代码里面还有类似的 bug, 但你已经分辨不出哪些代码是什么时候从哪个地方复制过来的了.
当你发现这些代码有 bug 的时候噩梦才刚刚开始也许花了好几天你又调出一个 bug 的时候才会想起这个 bug 你好像之前在哪里调过你也知道代码里面还有类似的 bug, 但你已经分辨不出哪些代码是什么时候从哪个地方复制过来的了
这种糟糕的编程习惯叫 Copy-Paste, 经过上面的分析, 相信你也已经领略到它的可怕了. 事实上, [周源源教授](https://cseweb.ucsd.edu/~yyzhou/)的团队在 2004 年就设计了一款工具 CP-Miner, 来自动检测操作系统代码中由于 Copy-Paste 造成的 bug. 这个工具还让周源源教授收获了一篇[系统方向顶级会议 OSDI 的论文](http://pages.cs.wisc.edu/~shanlu/paper/OSDI04-CPMiner.pdf), 这也是她当时所在学校 UIUC 史上的第一篇系统方向的顶级会议论文.
这种糟糕的编程习惯叫 Copy-Paste, 经过上面的分析相信你也已经领略到它的可怕了事实上[周源源教授](https://cseweb.ucsd.edu/~yyzhou/)的团队在 2004 年就设计了一款工具 CP-Miner, 来自动检测操作系统代码中由于 Copy-Paste 造成的 bug. 这个工具还让周源源教授收获了一篇[系统方向顶级会议 OSDI 的论文](http://pages.cs.wisc.edu/~shanlu/paper/OSDI04-CPMiner.pdf), 这也是她当时所在学校 UIUC 史上的第一篇系统方向的顶级会议论文
后来周源源教授发现, 相比于操作系统, 应用程序的源代码中 Copy-Paste 的现象更加普遍. 于是她们团队把 CP-Miner 的技术应用到应用程序的源代码中, 并创办了 PatternInsight 公司. 很多 IT 公司纷纷购买 PatternInsight 的产品, 并要求提供相应的定制服务, 甚至 PatternInsight 公司最后还被 VMWare 收购了.
后来周源源教授发现相比于操作系统应用程序的源代码中 Copy-Paste 的现象更加普遍于是她们团队把 CP-Miner 的技术应用到应用程序的源代码中并创办了 PatternInsight 公司很多 IT 公司纷纷购买 PatternInsight 的产品并要求提供相应的定制服务甚至 PatternInsight 公司最后还被 VMWare 收购了
这个故事折射出, 大公司中程序员的编程习惯也许不比你好多少, 他们也会写出 Copy-Paste 这种难以维护的代码. 但反过来说, 重视编码风格这些企业看中的能力, 你从现在就可以开始培养.
这个故事折射出大公司中程序员的编程习惯也许不比你好多少他们也会写出 Copy-Paste 这种难以维护的代码但反过来说重视编码风格这些企业看中的能力你从现在就可以开始培养
<em>传统上,文本冒险是由(许多)不同位置组成的虚拟世界。虽然这不是必需的(一些冒险发生在一个房间里!),但这是解释</em><em>数据结构</em><em>使用的好方法。</em>
@@ -112,13 +112,13 @@ struct location {
};
```
思考题:我们为什么要用结构体来保存位置?
::: warning 🤔思考题:
我们为什么要用结构体来保存位置?
```
这样子做有什么好处?
```
这样子做有什么好处?
const 又是什么?
const 又是什么?
:::
接下来,我们定义一个位置数组。目前,我们保持它非常简单:只有两个位置。
@@ -135,9 +135,9 @@ struct location locs[2] = {
};
```
让我们把它付诸实践。在上一章 <em>parsexec.c</em> 的代码示例中,我们更改了第 4、18 和 22 行)。
让我们把它付诸实践。在上一章(<em>parsexec.c</em> 的代码示例中,我们更改了第 4、18 和 22 行)。
# <strong>parsexec.c</strong>
## <strong>parsexec.c</strong>
```c
#include <stdbool.h>
@@ -174,14 +174,14 @@ bool parseAndExecute(char *input)
接下来,我们将一个新模块添加到项目中
# <strong>location.h</strong>
## <strong>location.h</strong>
```c
extern void executeLook(const char *noun);
extern void executeGo(const char *noun);
```
# <strong>location.c</strong>
## <strong>location.c</strong>
```c
#include <stdio.h>

View File

@@ -100,7 +100,7 @@ for (obj = objs; obj < objs + 5; obj++)
但是,对象通常具有同样有效的其他特征:
- <strong>Locations 通过</strong><strong>道路</strong><strong>连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。</strong>
- <strong>Locations通过</strong><strong>道路</strong><strong>连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。</strong>
- <strong>Items玩家唯一可以捡起的物品;</strong><strong>可以给他们整一个重量的属性</strong>
- <strong>Actors玩家唯一可以与之交谈交易战斗的对象;当然,前提是他们还活着!</strong><strong>可以加一个 HP 属性</strong>
@@ -122,7 +122,7 @@ player->location->description
是时候把它们放在一起了。我们从对象数组的全新模块开始
# Object.h
## Object.h
```c
typedef struct object {
@@ -143,7 +143,7 @@ extern OBJECT objs[];
#define endOfObjs (objs + 6)
```
# Object.c
## Object.c
```c
#include <stdio.h>
@@ -163,15 +163,15 @@ OBJECT objs[] = {
以下模块将帮助我们找到与指定名词匹配的对象。
# noun.h
## noun.h
```c
extern OBJECT *getVisible(const char *intention, const char *noun);
```
# 指针?函数?希望你已经掌握这是什么了
## 指针?函数?希望你已经掌握这是什么了
# noun.c
## noun.c
```c
#include <stdbool.h>
@@ -229,13 +229,13 @@ OBJECT *getVisible(const char *intention, const char *noun)
这是另一个辅助程序的函数。它打印存在于特定位置的对象物品NPC的列表。它将用于函数 <em>executeLook</em>,在下一章中,我们将介绍另一个需要它的命令。
# misc.h
## misc.h
```c
extern int listObjectsAtLocation(OBJECT *location);
```
# misc.c
## misc.c
```c
#include <stdio.h>
@@ -251,7 +251,7 @@ int listObjectsAtLocation(OBJECT *location)
//排除玩家在玩家的位置这种蠢东西
{
if (count++ == 0)
//我们需要保证找到一个东西之前他不会打印you see
//我们需要保证找到一个东西之前他不会打印 you see
{
printf("You see:\n");
}
@@ -265,14 +265,14 @@ int listObjectsAtLocation(OBJECT *location)
在 <em>location.c</em> 中,命令环<em>顾四周的实现</em>,并根据新的数据结构进行调整。旧的位置数组被删除,变量 <em>locationOfPlayer</em> 也是如此。
# location.h
## location.h
```c
extern void executeLook(const char *noun);
extern void executeGo(const char *noun);
```
# location.c
## location.c
```c
#include <stdio.h>

View File

@@ -8,19 +8,14 @@
玩家属性不再需要存储在单独的变量中;我们可以使用与任何其他对象相同的数据结构。所以玩家,作为一个对象必须具有以下特点:
- 所处位置(我在哪)
- 所处位置我在哪)
- 玩家可能持有的任何物品的位置。
这使得某些常见操作非常容易实现:
```
<strong> Action </strong> <strong>Typical</strong>
```
<strong> command </strong> <strong>Example</strong>
| 玩家从一个位置移动到另一个位置 | go | player->location = cave; |
|**Action**|**Typical Command**|**Example**|
| ------------------------------ | --------- | ------------------------------------ |
| 玩家从一个位置移动到另一个位置 | go | player->location = cave; |
| 列出某个位置存在的项和参与者 | look | listObjectsAtLocation(cave); |
| 玩家获取物品 | get | silver->location = player; |
| 玩家掉落物品 | drop | silver->location = player->location; |
@@ -35,7 +30,7 @@
如果你可以在不参考下面内容的情况下就写出基本内容会有很大收获的
# <strong>parsexec.c</strong>
## <strong>parsexec.c</strong>
```c
#include <stdbool.h>
@@ -48,7 +43,7 @@ bool parseAndExecute(char *input)
{
char *verb = strtok(input, " \n");
char *noun = strtok(NULL, " \n");
//第二次使用strtok要用NULL传参
//第二次使用 strtok 要用 NULL 传参
if (verb != NULL)
{
if (strcmp(verb, "quit") == 0)
@@ -94,7 +89,7 @@ bool parseAndExecute(char *input)
新命令由以下模块实现。
# <strong>inventory.h</strong>
## <strong>inventory.h</strong>
```c
extern void executeGet(const char *noun);
@@ -104,7 +99,7 @@ extern void executeGive(const char *noun);
extern void executeInventory(void);
```
# <strong>inventory.c</strong>
## <strong>inventory.c</strong>
```c
#include <stdio.h>
@@ -171,13 +166,13 @@ void executeInventory(void)
从本质上讲,<em>get</em>, <em>drop</em>, <em>give</em> and <em>ask 这些命令</em>除了将项目从一个地方移动到另一个地方之外,什么都不做。单个函数 <em>move 对象</em>可以对所有四个命令执行该操作。
# move.h
## move.h
```c
extern void moveObject(OBJECT *obj, OBJECT *to);
```
# move.c
## move.c
```c
#include <stdio.h>
@@ -231,14 +226,14 @@ void moveObject(OBJECT *obj, OBJECT *to)
命令“get”使用函数<em>getVisible</em>将名词转换为 object就像命令“go”一样;请参阅上一章。但是对于对玩家(或其他一些参与者)已经持有的对象进行<em>drop</em>, <em>ask</em>, <em>give 等</em>命令时,我们需要稍微不同的东西。我们将在 <em>noun.c</em> 中添加一个函数 <em>getPossession</em>。
# noun.h
## noun.h
```c
extern OBJECT *getVisible(const char *intention, const char *noun);
extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun);
```
# noun.c
## noun.c
```c
#include <stdbool.h>
@@ -318,18 +313,18 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun)
}
```
注意新函数45-75 行) <em>getPossession</em> 是 <em>getObject</em> 的装饰器wrapper )(参见第 52 行),它要么返回匹配的对象,要么返回 NULL如果没有合适的对象与名词匹配
注意新函数45-75 行) <em>getPossession</em> 是 <em>getObject</em> 的装饰器wrapper参见第 52 行),它要么返回匹配的对象,要么返回 NULL如果没有合适的对象与名词匹配
函数 <em>actor 这里</em>用于命令 <em>give</em> 和 <em>ask</em>,但它也可能由其他命令调用。所以我们在<em>misc.c</em>中定义了它。
# misc.h
## misc.h
```c
extern OBJECT *actorHere(void);
extern int listObjectsAtLocation(OBJECT *location);
```
# misc.c
## misc.c
```c
#include <stdio.h>