[Powered by Google Translate] [4]周
[戴维·J·马兰] [哈佛大学]
这是CS50。[CS50.TV]
>> 好吧，这是CS50，这是第4周开始，
这是最慢的可能的排序算法之一。
哪一个是，我们只能眼睁睁的看着吗？
这是冒泡排序，以大O（N ^ 2）+总和，
而事实上，我们是不是唯一的，在这个世界上似乎知道
什么是冒泡排序，或它的运行时间。
事实上，这是与谷歌的埃里克·施密特（Eric Sc​​hmidt）接受记者采访时
和前参议员巴拉克·奥巴马只不过几年前。
>> 现在，参议员，你在谷歌，
面试的，我喜欢把总统。
现在，它是很难得到一份工作作为总统，你现在正在经历的严峻考验。
它也很难在谷歌找到一份工作。
我们有问题，我们要求我们的候选人的问题，
而这一次是从拉里·施维默。
你们觉得我在开玩笑吗？就在这里。
排序一百万的32位整数的最有效的方法是什么？
[笑声]
良好
对不起。>>不，不，不，不。
我认为，冒泡排序是错误的方式去。
>> 来吧，告诉他这？
上周还记得我们休息了一下，从代码中，至少一天，
并开始专注于一些更高层次的想法和​​解决问题的更一般的
的上下文中搜索和排序，
我们介绍的东西，我们没有一巴掌这个名字在上周，
但渐近符号，大O，大欧米茄，
有时大θ符号，而这些简单的方法
描述的算法的运行时间，
需要多少时间的一种算法来运行。
>> 你可能还记得，你谈到的运行时间的大小
的投入，我们一般称之为N，什么问题可能是，
其中，n是多少人在房间里，
在电话簿的页面的数量，我们开始写东西了
像O（N ^ 2）或O（n）或O（n日志n），
即使在数学没有相当的工作如此完美
为² - N / 2或类似的东西
相反，我们会扔掉一些低阶，
和动机是我们真的想要一个
客观地评估排序
程序的性能或算法的性能
在一天结束的时候有没有做的，例如，
今天你的电脑速度。
>> 例如，如果实现冒泡排序，
或者你在今天的计算机上，实现合并排序或选择排序，
在2 GHz计算机，并运行它，
需要一定的秒数，明年有一个3 GHz
4 GHz的电脑，你可能会然后声称：“哇，我的算法
是现在的两倍快，“在现实中显然不是这样。
这只是硬件已经变得更快，但您的计算机
并没有，所以我们真的要扔掉的东西一样
乘2或3的倍数，当涉及到描述
的速度有多快或慢的算法是真的只是集中
在n或某些因素，
其一些功率中的种类的情况下，从上周。
回想一下，归并排序的帮助
我们能够这样做大大优于冒泡排序，选择排序
甚至插入排序。
>> 我们得到了n日志n，并再次，
记得，日志n一般是指生长
更慢则n，所以n日志n迄今还是不错的
因为它是比n²少。
但要实现n日志n归并排序
什么是基本的想法，我们必须充分利用胚芽
我们还利用在0周吗？
我们是怎么解决的排序问题，巧妙地与归并排序？
什么是重要的见解，也许？
任何人在所有。
好吧，让我们退后一步。
你自己的话描述归并排序。
它是如何工作的？
好了，我们将排回0周。
好吧，是的。
[听不见的学生]
好了，好了，所以我们的数字数组划分成2个。
我们整理的那件，然后我们合并，
我们已经看到了这个想法之前，这个大的问题
和切碎成一个问题，这个大，这个大。
>> 调出电话簿例如。
回想一下自我计数算法从数周前，
这里总结了这个伪所以合并排序。
当你给定的n个元素，首先是仔细检查。
如果N <2，没有做任何事情在所有
因为如果n <2，那么显然，n是0或1，
，因此，如果它是0或1，没有什么排序。
你就大功告成了。
您的列表是平凡的排序。
否则，如果你有2个或更多的元素，然后再划分
分为两半，左边和右边。
排序每个那些半部，然后合并排序条件半部。
但这里的问题是，乍看之下，这感觉就像我们撑船。
如果我问你，这n个元素进行排序，这是一个循环的定义
你告诉我，“好吧，好吧，我们将那些N / 2和那些N / 2个元素进行排序，”
然后我的下一个问题将是：“好，你是怎么排序的n / 2个元素？”
>> 但是，由于这项计划的结构，
因为有这个基础的情况下，可以这么说，
这种特殊情况下，如果n <2回一些固定的值，如立即说。
不回应与相同的圆形的答案。
这个过程中，这种周期性终将结束。
如果我问你“排序n个元素，”和你说，“好吧，整理这些N / 2”
然后你说，“很好，排序这些N / 4，N / 8，N/16，”
最终你会除以一个足够大的数
，你将有只有1元左，在这一点，你可以说，
“这里，这里是一个有序的单个元素。”
然后该算法的辉煌在这里是从这一事实派生
一旦你把所有这些单独排序的列表，
所有这一切都是大小为1，这似乎是无用的，
一旦你开始把它们合并，将它们合并
建立终于抢在视频的最后排序的名单。
>> 但这样的想法远远超出了排序。
有这种想法，在这个程序称为递归嵌入，
是一个程序，让你的想法，
解决一些问题，你叫你自己，
或把你是一个函数的编程语言的上下文中，
为了解决一个问题，你的函数调用自己
一而再，再而三，但你的功能
不能称自己为无限多次。
最终，你必须走出谷底，可以这么说，
并有一些硬编码的基本条件，
在这一点上停止这样要求自己，整个过程
其实最终停止。
这究竟是什么意思，递归？
>> 让我们来看看，如果我们可以做一个简单的，简单的例子，比方说，
3人，在这里我在舞台上，如果有人很舒服。
1，来时，2和3上。
如果你要来这里。
如果你想站在旁边，我在这里行，假设手头上的问题
是非常平凡的人谁是这里数一数。
但坦率地说，我累了所有这些计数的例子。
这将需要一些时间，1，2，点，点，点。
这是怎么回事采取永远。
我宁愿只平底船这个问题的帮助下，你叫什么名字？
>>萨拉，萨拉。所有权利。
凯利。>>凯利？
>> >>威利，莎拉，凯莉和威利，威利。
现在，我一直在问的问题，有人
有多少人在这个舞台上，我不知道。
这是一个很长的列表，所以不是我会做这一招。
我要问旁边的人给我做的大部分工作，
有一次她做的大部分工作
我会做最少的工作，只需添加1
她的回答是，所以在这里我们去。
我一直在问有多少人在舞台上演出。
有多少人在舞台上你左边的吗？
我的左边？>>好吧，但不要欺骗。
这是很好的，这是正确的，但如果我们要继续这样的逻辑
让我们假设你同样希望能撑船你左边的这个问题，
因此，而不是答案直接去前进，只是推卸责任。
哦，很多人都为我的左边吗？
有多少人是左边？
1。
[笑声]
好了，所以0，所以现在什么威利已完成
你回到你的答案这方向说0。
现在，你应该怎么办？>> 1。
好了，你是1，所以你说，“好吧，我要加1
威利的计数，“1 + 0。
您现在所以你正确的答案是现在，
1。“和我的是2。
好，所以你会觉得前面的回答1，
加入少量的工作，你想要做的，这是+1。
您现在有2个，然后把我哪个值？
3，我的意思是，很抱歉，2。
好。
>> 好了，我们拥有0到左边。
然后我们有1，然后再加2，
现在你递过来的2号，
所以我说，没关系，+1，3。
确实有3人，站在我旁边的这个舞台上，
因此，我们可以很明显这样做非常线性，
非常显而易见的方式，但我们真的什么呢？
我们采取了一个大小为3最初的问题。
然后，我们把它弄坏了一个问题分解成大小为2，
然后一个问题大小为1，然后在最后的基本情况
是真的，哦，还有一个人也没有，
在这一点威利有效地返回一个硬编码的答案了几次，
第二个，然后向上冒泡，冒泡，冒泡，
然后以增加一个额外的1在这
我们已经实现了这个递归的基本思想。
>> 现在，在这种情况下，它并没有真正解决的一个问题
任何更有效地发挥作用，那么我们迄今为止见过的。
但仔细想想，我们所做的舞台上迄今为止的算法。
我们有8个纸写在黑板上，
视频时，肖恩一直在寻找的7号，他真的什么？
，他没有做任何形式的鸿沟和征服。
他没有做任何形式的递归。
相反，他只是做这个线性算法。
但是，当我们的思想介绍舞台上的排序数字生活上周
然后我们有这种本能的中间，
在这一点，我们有一个小的列表大小为4或另一个列表的大小为4，
然后我们有相同的问题，所以我们重复，重复，重复。
换句话说，我们递归。
非常感谢您给我们的3名志愿者在这里展示我们的递归。
>> 让我们来看看如果我们不能更具体一点，
解决问题了，我们可以很轻松地做，
但我们将使用它作为实现这一基本思路的垫脚石。
如果我想的一串数字来计算的总和，
例如，如果你通过在3号，
我想给你3西格玛的价值，
所以总和3 + 2 + 1 + 0。
我想要得到的答案6
让我们来实现这个sigma函数，这个求和函数
，再次取入输入，然后返回求和
这一数字一直下降到0。
我们可以做到这一点非常简单，对不对？
我们能做到这一点，一些种循环结构，
所以，让我继续前进，赶快开始。
>> 包括stdio.h中。
让我让我自己到这里主要工作。
让我们拯救为sigma.c。
然后，我要在这里，我要声明的廉政n，
我要做到以下几点，而用户不配合。
当用户还没有给我一个正数
让我继续前进，促使他们为n =调用getInt，
并让我给他们一些指示做什么，
因此我们知道printf（“请正整数”）。
只是像这样简单的东西比较的时候，我们打了14行
现在，我们有可能在n为正整数。
>> 现在，让我们用它做什么。
让我继续和计算的总和，所以int总和=Σ（N）。
Sigma是求和，所以我只是写爱好者。
我们只把它西格玛有。
的总和，现在我要打印出来的结果，
printf（“请的总和为％d \ n”，总结）。
然后我就返回0的良好措施。
除了有趣的部分，我们所做的一切，这个程序需要，
这实际上是实施六西格玛的功能。
>> 让我走在这里的底部，并让我申报功能标准差。
它采取了一个整数类型的变量，
和什么样的数据类型，我想大概是从Σ返回吗？
诠释，因为我想它符合我的期望，第15行。
在这里，让我继续前进，实现这
一个非常简单的方法。
>> 让我们继续前进，并说int总和= 0，
现在我要在这儿有一个小的循环
会说这样的事情，
（INT I = 0; I <=数字，我+ +）之和+ =。
然后我将返回总和。
我可以在任何数量的方式实现这个。
我可以使用一个while循环。
我可以跳过的总和变量，如果我真的想，
但在短期，我们只需要一个函数，如果我不混日子声明总和为0。
然后，它会遍历并贯穿数，从0
在每次迭代补充说，目前的价值总和，然后返回总和。
>> 现在，这里有一个轻微的优化。
这可能是一个死不瞑目，但就这样吧。这就是现在的罚款。
我们至少彻底和投0中一路就到了。
并不难，很简单，
但事实证明，我们的sigma函数有同样的机会
我们在这里所做过的舞台上。
在舞台上，我们就只能有多少人在我旁边，
而如果我们想数一数3 + 2 + 1
同样，我们可以下降到0平底船的功能
相反，我会形容为递归。
下面让我们做一个快速的完整性检查，确保我没有混日子。
>> 我知道有这个程序，至少有一件事我没有做错。
当我按下回车键，我会得到什么样的骂我吗？
我该怎么大叫：约？
是啊，我忘了原型，所以我用西格玛第15行调用的函数，
但它没有宣布，直到第22行，所以我最好主动去这里
声明原型，我会说：INTΣ（整型数），就是这样。
它的实施在底部。
>> 或者我可以解决这个问题的另一种方式，
我可以移动的功能在那里，这是不坏，
但至少当你的程序开始长，坦率地说，
我觉得有一定的价值，总是有主的顶部
让你的读者可以打开该文件，然后立即看到
什么是程序做，而不必通过搜索
寻找，主要功能。
让我们深入到我的终端窗口，在这里，试图使SIGMA西格玛，
我搞砸了。
隐式声明的函数调用getInt我忘了做什么？
[听不见的学生]
好，显然是一个常见的​​错误，让我们把这个在这里，
cs50.h，现在让我们回到我的终端窗口。
>> 我会清除屏幕，我会重新运行西格玛。
它似乎已编译的。让我跑去标准差。
我会输入数字3，我没得到6，所以不是严格的检查，
但它至少乍一看似乎是工作，但现在让我们撕裂它除了，
让我们再次，利用递归的想法，
在一个非常简单的背景，所以，在几个星期的时间
当我们开始探索爱好者的数据结构阵列
我们有另一个工具箱中的工具，用以
操作这些数据结构，正如我们将看到的。
这是迭代的方法，基于循环的方法。
>> 让我，而不是现在这样做。
让我可以这样说，数字的总和
下降到0真的是同样的事情，
数+Σ（数量 - 1）。
换句话说，就像在舞台上，我踢了我旁边的人，
而他们又不停地踢，直到我们终于走出谷底，威利，
返回一个硬编码的答案，如0。
现在，我们同样踢西格玛
最初被称为相同的功能，但这里的关键洞察力
是我们，而不是调用标准差相同。
我们不及格的n。
我们清楚地传递 - 1，
所以一个略小的问题，稍小的问题。
>> 不幸的是，这是不完全的解决方案，但和之前我们解决
什么可能会跳出你们中的一些明显
让我继续前进，重新运行使。
它似乎是编译好的。
让我重新运行西格玛6。
哎呀，让我重新运行西格玛6。
这之前我们已经看到，尽管偶然一次为好。
为什么我得到这个神秘的分割故障？是啊。
[听不见的学生]
有没有碱的情况下，更具体地，可能发生的事情吗？
这是一个症状，什么样的行为呢？
说大声一点。
[听不见的学生]
这是一个无限循环，有效地无限循环的问题
当它们涉及在这种情况下，一个函数递归调用自身，
每次你调用一个函数，会发生什么？
好了，回想起我们提出了如何在一台电脑的内存。
我们说，有这样的内存块，叫做堆栈的底部，
每次你调用一个函数多一点的内存被放
这个所谓的堆栈，其中包含该函数的局部变量或参数，
因此，如果SIGMA调用SIGMA西格玛来电要求西格玛
要求SIGMA这个故事的结束？
>> 那么，它最终超支总额
，你必须提供给您的计算机的内存。
您溢出的部分，你应该留在，
你得到这个分割故障，核心转储，
什么是核心转储的意思是，我现在有一个文件名为核心
这是一个文件，包含零和一
实际上在未来将是有用诊断。
如果这不是很明显，你在哪里，你的错误是
实际上，你可以做一些取证分析，可以这么说，
这一核心转储文件，这，又是一大堆的零和一
你的程序在内存中，基本上代表了
坠毁在这样的时刻。
>> 这里的修复，我们不能只是一味地返回西格玛，
的数目+西格玛一个略小的问题。
我们需要有一些基本情况，
什么的基本情况大概是什么？
[听不见的学生]
好了，只要数是积极的，我们其实应该返回这一点，
或者换一种说法，如果数字是多少，说，<= 0
你知道吗，我会继续前进，返回0，
很像威利，和其他人，我要继续前进
并将此，所以它不是，要短得多
比，我们掀起了第一个使用for循环的迭代版本，
但请注意，这种优雅。
而不是返回一些数字，并执行所有的数学
并加入了局部变量
相反，你说：“好吧，如果这是一个超级简单的问题，
像<0，让我立即返回0。“
>> 我们不会去打扰支持负数，
所以我要硬编码的值为0。
但是，除此之外，要实现这个想法的总结
所有这些数字放在一起，可以有效地一小口
出了问题，就像我们在这里所做过的舞台上，
然后平底船剩下的问题，旁边的人，
但在这种情况下一个人是自己。
这是一个具有相同名称的功能。
只要把它体积更小，小的问题，每次
即使我们没有很正式的事情在这里的代码
这究竟是怎么回事0周的电​​话簿。
这究竟是怎么回事，在过去的几周里，肖恩
和我们寻找数字的示威。
它的问题，划分了一遍又一遍。
>> 换句话说，现在有一种方法翻译
这个现实世界的结构，这种更高的层次结构
分而治之，一遍又一遍的东西
在代码中，所以这是随着时间的推移，我们将再次看到的东西。
现在，顺便说一句，如果你是新递归，你应该至少现在明白了
为什么这很有趣。
我要访问google.com，
我要寻找一些技巧和窍门递归进入。
告诉你旁边的人，如果他们不是刚才笑。
你的意思是递归？
难道你的意思是啊，我们走吧。
好了，现在剩下的大家。
某处有一个小的嵌入式复活节彩蛋在谷歌。
顺便说一句，我们把课程的网站上的链接
今天是这个网格的各种排序算法，
其中有些我们看着最后一周，但这种可视化有什么好处
当你试图周围包裹你的心有关的各种事情算法
我知道，你可以很容易地现在就开始与不同类型的输入。
所有的输入反转，输入大多排序条件，输入随机的，等等。
当你再次尝试，区分这些东西在你的心中
实现了课程网站的讲座上，该URL
可能会帮助你通过其中的一些原因。
>> 今天，我们终于得到了一段时间后要解决这个问题，
这是交换功能，这只是没有工作，
和什么是最根本的问题，这个功能交换，
目标，其中的时间是，再次，交换的值，在这里和这里
如出现这种情况呢？
这实际上并没有工作。为什么呢？
是啊。
[听不见的学生]
没错，这bugginess的解释
简直是因为当你调用函数在C
这些功能需要的参数，就像A和B，
你是通过你的任何值，该功能提供副本。
你是不是自己提供的原始值，
所以我们看到这在buggyc的背景下，
buggy3.c，这看起来有点像这样。
>> 回想一下，我们有x和y分别初始化为1和2。
然后，我们打印出它们是什么。
然后，我要求我的x，y调用swap交换他们的。
但问题是，交换的工作，
但只有在交换的范围的函数本身。
只要我们打了40行这些交换值
被扔掉了，所以没有什么
在实际上改变了原有的功能，主要是在所有，
所以，如果你认为这看起来像在我们的记忆中
如果此电路板的左手侧表示-
我会尽我所能为大家看到这个如果左侧板
代表，说，你的RAM，堆栈增长了这种方式，
和我们调用一个函数像主，主有2个局部变量，x和y，
让我们在这里描述为x，让我们在这里描述为y，
，让我们把值1和2中，所以在此主要是，
当主呼叫交换功能的操作系统
给自己的大片的内存堆栈上的交换功能，
它自己的堆栈帧，可以这么说。
它也分配这些32位的int型。
它发生在A和B，但是这完全是任意的。
它可以叫他们为所欲为，但会发生什么，当主
调用swap是需要1，把一个副本，将副本。
>> 掉期为1的局部变量，不过，叫什么？>> TMP。
TMP，所以让我给自己32位，
我做了什么在这个功能吗？
我，诠释TMP说得到，因此有1，所以我这样做时，我们上次播放的这个例子。
然后，得到b，所以b是2，所以现在变成2个，
现在b得到温度，因此温度是1，
所以现在B变成这样。
这是伟大的。它的工作。
但是，当尽快在函数返回
交换的存储器有效地消失，以便它可以被重用
由一些在未来的其他功能，和主要是显然完全不变。
我们需要一种从根本上解决此问题，
今天我们就终于有办法这样做，据此
我们可以引进一些所谓的指针。
事实证明，我们可以解决这个问题
而不是通过在x和y的副本
而是通过在哪，你想，交换功能？
是啊，什么的地址吗？
我们还没有真正谈过地址在很多细节，
但如果这个黑板代表我的电脑的内存
当然，我们可以开始编号，我的内存中的字节
并说，这是字节＃1，这是字节＃2，＃3字节，
字节第4字节＃2亿元，如果我有2 GB的RAM，
所以我们当然可以拿出一些任意的编号方案
在我的电脑的内存中的所有单个字节。
>> 什么，如果不是，当我打电话交换
在x和y的副本，而不是通
为什么不要我，而不是通过在这里的x的地址，
地址为y这里，基本上邮政的地址
因为x和y交换，如果他的通知
x和y的存储器中的地址;
然后交换，如果我们把他训练的一点点，
他有可能开车到该地址，可以这么说，
X，和有改变，然后开车到y的地址，
数，即使没有实际得到，自己这些值的副本，
因此，即使我们谈到这个作为主要的记忆体
作为交换的内存，强大的和危险的C
的是，任何函数可以触摸内存在计算机中的任何地方，
这是强大的，你可以做很花哨的东西，计算机程序C.
这是很危险的，因为你也可以很容易搞砸了。
事实上，一个最常见的方式的方案，这些天被利用
仍是一个程序员没有意识到
他或她被允许的数据
要被写入存储器中的一个位置不打算。
>> 例如，他或她声明一个数组大小为10
但后来意外地试图把11个字节到该数组的内存，
你开始接触的内存部分不再有效。
只是为了上下文此，有些人可能知道，
软件经常会提示您输入序列号或注册键，
的Photoshop和Word这样的程序。
存在裂缝，你们有些人知道，网上，您可以运行一个小程序，
瞧，没有更多的请求的序列号。
如何工作？
在许多情况下，这些东西都只是寻求在电脑
在计算机的实际零和一的文本段
其中是，其中被请求的序列号的功能，
您覆盖空间，在程序运行时，
你可以找出其中的关键是实际存储
使用一些所谓的调试器，你可以破解软件的方式。
这是不是说，这是我们的目标，在未来几天，
但它具有非常现实世界的后果。
这发生的涉及盗窃软件，
但也有妥协的整个机器。
>> 事实上，当网站这几天都在利用
和妥协的数据被泄露和被窃取密码
这往往涉及到一个人的记忆管理不善，
或者，在数据库的情况下，未能预见
对抗性的输入，所以更多的是在未来几周内，
但现在只是一个先睹为快的那种伤害，你可以做
不太了解引擎盖下是如何工作的。
让我们去了解，这是为什么打破
一个工具，将成为越来越多的有用
因为我们的课程变得更加复杂。
到目前为止，当你在你的程序中有一个错误
你如何调试了吗？
你有什么技术迄今为止，无论是你的TF教
或只是自学成才的吗？
[学生]的printf。
printf的，因此我们知道printf有可能是你的朋友，如果你想看到的
这是怎么回事，在你的程序
你只是在这里把输出，输出在这里，输出在这里。
然后运行它，你会得到一大堆的东西在屏幕上
，然后你可以用它来推断出什么是真正在你的程序错误。
>> printf的往往是一个非常强大的东西，
但它是一个非常手动过程。
你必须把这里的printf，是printf这里，
如果你把它里面的一个循环，你可能会得到100行
的输出，你就必须通过筛选。
这不是一个非常用户友好的调试程序或互动机制，
但幸运的是存在替代品。
有一个程序，例如，GDB，GNU调试器，
这是一个有点神秘的，你如何使用它。
这是一个有点复杂，但坦率地说，
这是一个的东西在那里，如果你把在本周和未来
额外的一小时了解类似GDB
从长远来看，它可能会为你节省几十个小时，
所以，让我给你一个传情的这个东西是如何工作的。
>> 我在我的终端窗口。
让我继续前进，编译这个程序，buggy3。
这已经是最新的。
让我运行它，就像我们做了一段时间后，而事实上，它打破了。
但是，这是为什么？也许是我搞砸了交换功能。
也许它的A和B。我不是很感动他们周围是否正确。
让我继续这样做。
而不是仅仅buggy3，而不是让我运行这个程序，GDB，
我要告诉它运行buggy3，
我要包括一个命令行参数，TUI，
我们会把这规格提醒未来的问题。
而现在这个黑和白的接口弹出，再次，
是有点势不可挡，因为这一切
保修信息到这里，但至少有一些熟悉的东西。
在窗口顶部的是我的实际代码，
如果我向上滚动，在这里让我滚动到最顶端的我的文件，
而事实上，在此窗口底部有buggy3.c，并通知
我有这样的GDB提示。
>> 这是我的正常的约翰·哈佛提示不一样的。
这是一个提示，是怎么回事，让我来控制GDB。
GDB调试器。
调试器是一个程序，让你走过
一行行的执行你的程序行，
前进的道路上，做任何你想要的程序，
即使调用函数，或寻找，更重要的是，
在各种变量的值。
让我们继续前进，并做到这一点。
我会继续前进，在运行中输入GDB的提示符下，
所以注意在屏幕的左下方，我输入的运行，
和我已经打输入，和什么做呢？
它的字面运行我的程序，但我并没有真正看到很多在这里
因为我还没有告诉调试器
暂停在一个特定的时刻。
只需键入运行，运行该程序。
我没有看到任何东西。我不能操纵它。
>> 而是让我这样做。
在此GDB提示符下，让我，而不是键入突破，进入。
这不是我的意思是什么类型的。
让我们，而不是主要键入休息。
换句话说，我想设置一个断点，
这是恰当地命名，是因为它会破坏或暂停
执行你的程序在特定的地方。
主要是我的函数的名称。
请注意，GDB是非常聪明的。
想通了，主要发生在大约在第18行开始
的buggy3.c，然后注意到这里在左上角
B +第18行是正确的旁边。
那是在提醒我，我已经在第18行设置一个断点。
这一次，当我键入run，我要运行我的程序
直到它击中断点，
这样的程序将暂停，我在第18行。
在这里，我们去运行。
什么也没有发生，但通知左下角
启动程序，buggy3，断点1在主在buggy3.c第18行。
我现在能做些什么呢？
>> 请注意，我可以开始输入打印类的东西，
不是printf，打印x，而现在很奇怪。
1美元的仅仅是一个好奇心，我们会看到
每次你打印的东西，你会得到一个新的美元价值。
这是如此，你可以参考以前的值，以防万一，
但现在打印告诉我的是，在这个故事中的点x的值
显然是134514032。
什么？在哪里，即使是从何而来呢？
[听不见的学生]
事实上，这就是我们要调用一个垃圾值，我们还没有谈到这一点，
但原因，你初始化变量
显然，让他们有一定的价值，你希望他们有。
但问题是这样，就可以声明变量
像我刚才在我的适马的例子
实际上是给他们一个值。
回想我做了什么，在这里西格玛。
我宣布n，但是什么样的价值，我给它呢？
没有，因为我知道，在接下来的几行
调用getInt会照顾的问题，把里面的值的n。
>> 但在这一点上在第11行的故事
和线12和线13和第14行
在那些几行n的值是什么？
在C语言中，你只是不知道。
这是一些垃圾的价值，有些完全是随机的数字
剩下的基本上是从以前的一些功能
已运行，这样你的程序运行
记得函数获取函数，函数，函数。
所有这些帧被放到内存中，然后这些函数的返回，
就像我建议用橡皮擦最终被重复使用他们的记忆。
好了，它只是恰巧在这个程序，这个变量x
似乎已经包含了一些垃圾的价值，如134514032
从以前的一些功能，而不是我写的。
这可能是有效的操作系统的东西来，
引擎盖下的一些功能。
>> 好了，这很好，但现在，让我们进入到下一行。
如果我在我的GDB提示符中键入“下一步”，我按下回车键，
注意突出显示向下移动到第19行，
但合乎逻辑的言下之意是，第18行
现在已经执行完毕，所以如果我再输入“打印X”
我现在应该看到，事实上，我做的。
同样，美元的东西是一个GDB提醒你的方式
打印的历史是什么，你已经完成了。
现在让我和打印输出Y，而事实上，y是一些疯狂的价值，以及，
但没有什么大不了的，因为在第19行中，我们将其分配给
值2，所以让我再次键入“下一步”。
现在，我们正上的printf线。
让我做打印x。
让我做印刷品Y。坦率地说，我有点累了印刷本。
让我，而不是键入“显示x”和“显示Y”
现在每次我在未来键入命令
我会想起什么x和y，x和y，x和y是什么。
>> 我还可以，顺便说一句，在“信息当地人类型。”
信息是一种特殊的命令。
当地人意味着它让我看到局部变量。
以防万一我忘了这是一个疯狂的，复杂的功能
我或其他人编写的信息当地人会告诉你
什么是这里面的本地函数的所有局部变量
如果你想闲逛，你可能会关心。
现在，printf是执行，所以让我继续前进，只需键入“未来”。
因为我们是在这样的环境中，我们实际上没有看到它
执行下来，但要注意它变得有点错位。
但是请注意，它的首要屏幕上出现，
所以它不是一个完美的方案，但是这没关系，因为我可以随时闲逛
如果我想使用打印。
>> 让我再输入下，现在这里是最有趣的部分。
在这一点上在故事y是2，x是1，
的建议，并再次，
这是自动显示的原因是因为我使用的命令
显示x和显示Y，I型下的那一刻
x和y在理论上应该成为交换。
现在，我们已经知道这是不会的情况下，
但我们会看到一个时刻，我们如何能更深入地找出原因，这是真的。
下一步，不幸的是，Y仍然是2，x是1，我可以证实尽可能多的。
打印x，印刷品Y。
事实上，没有交换实际上已经发生了，所以让我们开始这个问题。
显然，交换被打破了。
的，而不是让我们再次键入“运行”。
让我说是的，我要重新启动它从一开始，进入。
>> 现在，我回来了在第18行。
现在，注意到x和y的值再次是垃圾。
下一步，下一步，下一步，下一步。
如果我感到无聊，我也只需要输入n转到下一个。
您可以缩写，以最短的字符序列。
现在被破坏掉。
我们来看看，而不是输入下，
现在，我要输入步骤，加强，使我里面的这个函数
这样我就可以穿过它，所以我打步骤，然后输入。
注意突出跳下在我的程序中第36行。
现在的局部变量是什么？
信息本地人。
没有，只是还没有，因为我们还没有得到该行，
所以让我们继续前进，并说：“下一个。”
现在，我们似乎，有tmp目录，打印TMP。
垃圾的价值，对不对？我是这么认为的。
如何打印，打印B，1和2吗？
在某一时刻，只要我再输入下
tmp是将要采取的值为1，希望，
因为tmp目录将被分配的值。
>> 现在，让我们做打印，页B，
但现在打印tmp，以及它的确是1。
让我做下一个。让我做下一个。
我已经完成了交换功能。
我还在里面，它在第40行，所以让我打印，
打印B，我不关心tmp是什么。
它看起来像掉期是正确的，当谈到交换a和b。
但是，如果我现在键入下，我跳回到第25行，
当然，如果我在x和印刷品Y型
他们仍然是不变的，所以我们没有固定的问题。
但诊断也许这GDB程序
至少我们已经变得更近了一步的了解
这是怎么回事错误，不乱抛垃圾，我们把一个printf的代码，
输出，输出，然后运行一遍又一遍
试图找出什么地方出了错。
>> 我要继续前进并退出这完全退出。
这是怎么回事，然后说，“要离开吗？”是。
现在，我回到了我的正常提示，我使用GDB。
顺便说一句，你不需要使用这个TUI标志。
事实上，如果你忽略它，你基本上是在屏幕的下半部分。
如果我然后键入突破主，然后运行
我仍然可以运行我的程序，但它会做的是文本上
你给我的当前行一次一个。
TUI，文本用户界面，
只能说明你的程序一次，这可能是有点概念上更容易。
不过说实在的，我只是做下一个，下一个，下一个，
我看到一个在一个时间线，如果我真的想看看会发生什么
我可以输入列表，看到一大堆的相邻线路。
>> 有一个视频，我们问过，你看问题集3
内特覆盖一些GDB的复杂性，
这是一个人的东西，说实话，你的一些不平凡的百分比
再也不会去碰GDB，这将是一件坏事
因为从字面上你会花更多的时间，这学期
追错误，那么你如果你把在这半小时/小时
本周和下周的学习，获得舒适的使用GDB。
printf的是你的朋友。
GDB现在应该是你的朋友。
>> 对GDB的任何问题？
这里有一个快速的一些最强大，最有用的命令列表。
是啊。>>你可以打印一个字符串？
你可以打印一个字符串？当然可以。
它不具有只是整数。
如果一个变量s是一个字符串类型的打印小号。
它会告诉你是什么字符串变量。
[听不见的学生]
它会给你的地址和字符串本身。
它会告诉你。
最后一件事，只是因为这是好知道的太多。
回溯和框架，让我潜入这是最后一次，
GDB完全相同的程序。
让我继续运行的文本用户界面版本，
打破为主。
让我继续前进，再次运行。我在这里。
现在让我去下一个，下一个，下一个，下一个，下一个步骤中，输入。
>> 现在假设我现在在交换故意的，但我很喜欢“妈的，什么是x的值吗？”
我不能做X了。
我不能做y，因为他们不在范围内。
他们不是在上下文中，但没有问题。
我可以输入回溯。
这说明我已经执行了这个时间点的所有的功能。
请注意，一个在底部，主，线与主
这里是我们的图片的底部。
事实上，交换与交换在它上面的内存是它上面的线，
如果我想暂时回到主，我可以说，“框架”。
几号？主要是帧＃1。
我要继续前进，并说：“第1帧”。
>> 现在我的主，我可以打印x，我可以印刷品Y，
但我无法打印或b。
但我可以的，如果我说，“好吧，请等待一分钟。交换在哪里？”
让我继续说：“第0帧。”
现在我回来了，我想是的，和顺便说一句，
也有其他命令一样，如果你真的感到无聊打字下一步，下一步，下一步，下一步，
一般情况下，你可以说“下一个10的事情，”和，将逐步在未来10行。
你也可以写“继续”时，你真的厌倦了单步运行它。
继续运行你的程序没有中断，直到碰到另一个断点，
无论是在一个循环或降低在你的程序中。
>> 在这种情况下，我们继续到最后，程序正常退出。
这是一种奇特的方式，劣质的过程。
只要你的程序正常退出。
更多的视频和调试会话来。
这是一个很大。
让我们把我们的5分钟的休息时间，在这里，我们将返回结构和文件。
>> 如果你已经一头扎进这个星期的pset中
你就会知道，我们使用的分布代码，
为出发点，一些新的技术，我们为您提供的源代码。
特别是，我们推出了一个新的关键字称为struct结构，
这样我们就可以创建自定义的各种变量。
我们还介绍了文件I / O，文件输入和输出的概念，
这是使我们能够保存状态
争夺董事会光盘上的文件
，教学研究员，我可以理解
你的程序内部发生了什么事情，而无需手动播放
几十场比赛的争夺。
我们可以做更多automatedly的。
>> 这个想法的结构解决了一个相当引人注目的问题。
假设我们要实现的一些程序
，不知怎的，对学生的信息跟踪，
和学生可能具有，例如，一个ID，一个名称
和一所房子在哈佛这样的地方，所以这3个信息
我们要保持周围，所以让我继续前进，开始在这里写了一个小程序，
包括stdio.h中。
让我包括cs50.h.的
然后开始我的主要功能。
我不会打扰任何命令行参数，
在这里，我想有一个学生，所以我说
一个学生都有一个名字，所以我会说“字符串名称。”
然后我说一个学生，也有一个ID，所以int ID，
学生有一所房子，所以我也说“字符串房子。”
然后，我会为了这些更干净一点是这样的。
好吧，现在我有3个变量代表一个学生，这样的学生。“
>> 现在我要来填充这些值，所以让我继续前进，这样说
“ID = 123”。
名称是会得到大卫。
比方说，房子是会得到奥美，
，然后我要做的事情，随意如printf（“％s，
的ID是％d，住在％s。
现在，我要在这里堵塞，一前一后？
姓名，身份证，房屋返回0。
好吧，除非在此我搞砸了
我认为我们有一个不错的方案，存储一个学生。
当然，这不是那么有趣。如果我想有2名学生？
这没什么大不了的。我可以支持2人。
让我去，并强调这一点，去这里，
我可以说“ID = 456”像罗布人住在华盛顿州Kirkland的人。
>> 好了，等待，但我不能把这些同样的事情，
它看起来像我要复制，
所以让我说，这将是大卫的变量，
并让我得到一些副本，这些罗布。
我们会打电话给这些Rob的，但，这是行不通的，现在
因为我已经等待，让我们改变了我的ID1，name1和house1。
罗布将是2，2。
我已经改变了这里，这里，这里，这里，这里，这里。
等待，汤米？让我们再这样做。
显然，如果你仍然认为这是一个很好的方式，这样做，不是的话，
所以复制/粘贴坏。
但是，我们解决了这一个星期前。
>> 我们的解决方案时，我们希望有相同的数据类型的多个实例吗？
[学生]一个数组。
一个数组，所以让我尝试清理它。
让我为自己出一些空间的顶部，而不是让我在这里做。
我们会打电话给这些人，而不是我会说“诠释IDS，”
我要支持我们现在。
我会说“字符串名称”，我会支持我们，
然后，我会说“字符串的房子，”我要支持我们。
现在，在这里，而不是大卫得到他自己的局部变量
我们可以摆脱这些。
这感觉很好，我们正在清理这个。
然后，我可以说大卫将是[0]和名称[0]
房子[0]。
然后抢，我们同样可以省了。
让我们把这个在这里，所以他是怎么回事，随意入侵检测系统[1]。
他的名字[1]
然后最后，房屋[1]。
>> 还是有点繁琐，现在我已经明白这一点，
因此，让我们说：“名[0]，ID [0]，房屋[0]
的复数此。
入侵检测系统，入侵检测系统，入侵检测系统。
再次，我这样做，如此反复，我已经诉诸再次复制/粘贴，
所以赔率是有另一种解决方案。
我也许可以清理，进一步加快循环或类似的东西，
总之，这是好一点，但仍然感觉像
我诉诸复制/粘贴，但即使这样，我要求，
是不是真的从根本上正确的解决方案，因为
如果某个时候，我们决定你知道吗？
我们真的应该存储电子邮件地址为大卫和Rob
每个人都在这个程序。
我们也应当存储的电话号码。
我们也应该储存紧急联络电话号码。
我们有所有这些作品，我们要存储的数据，
那么你如何去这样做呢？
>> 声明另一个阵列的顶部，然后手动添加
[0]，[1]的电子邮件地址的电子邮件地址
大卫和Rob等等。
但真的只是一个假设这样的设计
我使用的是荣誉系统知道
[i]的每个的多个阵列
恰好指的是同一个人，
[0] IDS中的编号为123，
我要去承担，名字[0]
是同一个人的名字和房子[0]
是同一个人的房子等等，我创造的所有的不同的阵列。
但是请注意，有没有根本的联系
除这3个信息，id，name和房子，
即使我们正在努力模型，这个程序是实体，而不是数组。
数组是这一纲领性的方式这样做。
我们真正想要的模型在我们的节目是一个人
像大卫一样，像Rob内，其中一个人
或封装的名称和ID和一所房子。
>> 我们可以以某种方式表达这种思想的封装
由此一个人有一个ID，一个名称和一个房子
而不是这个黑客真的，我们只是
相信，支架的东西
指的是同一人在这些不同的阵列的实体？
事实上，我们可以做到这一点。
让我去上面的主，现在，让我创建自己的数据类型
确实是第一次。
我们使用这种技术的争夺，
但在这里，我要继续前进，并创建一个数据类型，
你知道吗，我现在就打电话给学生或个人，
我要使用typedef定义一个类型。
我会说，这是一个结构，
那么这个结构类型的学生，我们会说，
即使这是一个对我来说有点过时了。
我们会说：“int的ID。”
我们会说：“字符串名称。”
然后，我们会说：“的字符串房子，”
所以现在年底的这几行代码
我刚才教铛存在
除了int类型的数据类型，除了字符串，除了增加一倍，除了花车。
>> 11在时间线的这一刻，现在有一个新的数据类型，称为学生，
现在我学生可以声明一个变量，任何地方，我想，
所以让我向下滚动这里的人。
现在我可以摆脱这种，我可以回去大卫在这里，
和大卫，其实我可以说，大卫，
我们可以从字面上命名变量照顾自己，
将是类型的学生。
这可能看起来有点怪，但是这还不是全部，不同的
作为一个int或一个字符串或浮点数申报的东西。
碰巧的是被称为学生的现在，
如果我想这种结构把里面的东西
我现在要使用新的语法，但它是非常简单的，
david.id = 123，david.name =“大卫”在资本ð，
david.house =“奥美”
现在我可以摆脱这东西在这里。
请注意，我们现在已经重新设计我们的计划确实是一个更好的方法
现在，我们的节目反映了真实的世界。
>> 有一个现实世界的概念，一个人或一个学生。
在这里，我们有一个人或更具体的学生的C版本。
里面的那个人是这些相关的特性，
ID，名称和房子，所以罗布基本上变成同样的事情，在这里，
让学生抢，现在rob.id的= 456，
rob.name =“抢”。
事实上，该变量被称为罗布是一种毫无意义的。
我们可以把它叫做x或y或z。
我们只是把它命名为抢在语义上是一致的，
但真正的名字是里面的那场，
所以现在我有这个。
这也是不觉得自己是最优秀的设计，我已经硬编码的大卫。
我硬编码的罗布。
我还是要采取一些复制和粘贴的时候，我想新的变量。
此外，我显然给每个变量的名称，
即使我宁愿描述这些变量
更一般的学生。
>> 现在，我们可以合并的想法，一直致力于为我们的
，而是说：“你知道吗，给我一个变量所谓的学生，
，让我们有它的大小为3，“所以现在我可以进一步细化此，
摆脱手动声明的大卫，
相反，我可以说学生一样的东西[0]在这里。
然后，我可以说，学生[0]在这里，
学生[0]在这里，等等，我可以去转转
和清理罗布。
我也可以去，现在可能增加循环
使用GetString和调用getInt从用户获取这些值。
我可以加上一个常数，因为这是不好的做法
硬编码的，有些像在这里任意数量
，然后只需记住，你应该不超过3名学生在。
它可能是更好的在我的文件的顶部使用＃define
因素说了出来，的确，让我去和推广。
>> 让我打开了一个例子，在今天的
例子提前structs1。
这是一个比较完整的程序，使用＃定义在这里
并说，我们要默认情况下，有3名学生。
在这里，我声明一个类学生的价值，
所以教室里的学生，现在我使用的是循环
只是为了使代码更优雅的一点，填充类
与用户的输入，所以循环从i = 0上的学生，它是3。
然后，我提示用户在这个版本中
什么是学生的ID，我得到它与调用getInt。
什么是学生的名字，然后我得到它的GetString。
学生的家是什么？我得到它的GetString。
然后在底部在这里，我决定改变
我如何打印这些和实际使用的循环，
我是谁打印？
根据我的评论我打印Mather中的任何人，
这就是它所以罗布和Tommy等等，其实汤米的Mather中。
汤米和大卫将被打印在这种情况下，这是怎么工作的？
我们还没有看到这个功能，但猜测这是什么做的。
比较字符串。
>> 如何比较字符串，因为事实证明，这是一个有点非明显
如果返回0，表示的字符串是相等的。
如果返回-1，这意味着人来之前，其他的字母顺序，
如果返回+1，这意味着其他的字来按字母顺序
前，你可以看看网上的手册页
它说，看究竟哪一种方式是，但是这一切现在正在做的是
如果[i]的房子是等于“奥美”
然后继续前进，打印出来，并在奥美也是如此。
但在这里我们还没有看到过的东西，我们会回到这个。
我不记得曾经在我的程序中做到这一点。
免费显然是指内存，释放内存，
但什么记忆，我明显地释放在这个循环的底部，这个程序吗？
它看起来像我释放一个人的名字
和一个人的房子，但为什么会这样？
>> 原来，这几个星期，你已经使用GetString
我们已经被引入到你的程序中的每一个错误。
GetString的设计分配内存，因此它可以返回一个字符串，
像大卫一样，罗布，和你就可以做任何你想要的
以该字符串在你的程序中，因为我们已经为您保留内存。
问题是每到这个时候，你需要调用getString
GetString的作者，​​我们已经要求操作系统
给我们一个位RAM的字符串。
给我们一个位的RAM，这一个字符串。
给我们一些更多的RAM，这一个字符串。
你，程序员，从来没有做什么
给我们，恢复记忆，
所以这几个星期，你写的所有程序
有什么所谓的内存的飞跃，让他们继续使用
越来越多的内存每次调用GetString，这很好。
我们刻意做的第一周，因为它是不是很有趣
有担心的字符串是来自哪里。
所有你想要的是这个词抢回来当用户键入它。
>> 但是向前发展，我们现在必须开始对这个变得越来越复杂。
任何时候，我们分配内存，我们最终把它。
否则，在现实世界中，在您的Mac或PC，你可能偶尔有经验丰富的
在您的计算机可能烂尾最终的症状
或愚蠢的纺纱沙滩球只是占用计算机的
全部精力，你不能做的事情。
这可以解释为任意数量的错误，但在这些可能的错误
事情称为内存泄漏，有人是谁写的一块软件
你不记得，以便释放内存
他或她问的操作系统，
不使用GetString，因为这是一个CS50的事情，但使用类似的功能
问操作系统的内存。
如果你或他们搞砸了，从来没有真正返回该内存
一个程序，可以减缓放缓和减慢的症状，
除非你记得打电话免费。
>> 我们会回来的时候，为什么你会打电话免费，
但让我们继续前进的好措施，并尝试运行特定的程序。
这被称为structs1，请输入。
让我继续运行structs1的，123，大卫·马瑟
456，789，罗布·柯克兰，
汤米·马瑟，我们看到大卫的Mather中，汤米Mather中。
这仅仅是一个小的完整性检查程序的工作。
现在，不幸的是，这个方案是一个有点沮丧，
我做过的一切工作，我输入了9种不同的字符串，点击进入，
被告知是谁在奥美，但很明显，我知道是谁在奥美已经定了，因为我输入的。
至少这将是很好，如果这个计划更像是一个数据库
它实际上还记得我所输入的
所以我永远不会再有输入这些学生记录。
也许这是像registrarial系统。
>> 为此，我们可以使用这种技术被称为文件I / O，文件输入和输出，
一个非常通用的方法，说任何时候你想要读取文件或写入文件
一组特定的功能，你可以做到这一点。
让我继续并打开这个例子structs2.c，
这几乎是相同的，但让我们来看看它现在所做的。
在该文件的顶部，我宣布一个班的学生。
我然后填充类用户的输入，
所以这些代码行之前是完全一样的。
然后，如果我向下滚动，在这里我打印大家谁是Mather中任意像以前一样，
但是，这是一个有趣的新功能。
这两行代码是新的，他们在这里介绍一些，
FILE，全部大写，并且它有*在这里也。
让我搬过来，*在这里。
>> 这个功能，我们还没有看到之前，FOPEN，
但它意味着打开文件，让我们翻阅这些，
这是我们会回来的东西在未来的pset，
但此行基本上是在这里打开一个名为“数据库，
具体地说，它以这样一种方式，它可以做它打开？
[听不见的学生]
对，所以“W”只是意味着它告诉操作系统
以这样的方式，我可以写它，打开此文件。
我不想读它。我不想只是来看看。
我想改变它，添加的东西可能，
和文件将被称为数据库。
这可能是什么。
这可能是database.txt。这可能是分贝。
如foo这可能是一个词，但我随意选择命名的文件数据库。
这是一个小的完整性检查，我们会回来的很详细随着时间的推移，
如果fp文件指针，不等于NULL，这意味着一切都很好。
>> 长话短说，像fopen的功能有时会失败。
可能是文件不存在。也许你的磁盘空间。
也许你没有该文件夹的权限，
因此，如果FOPEN返回null的东西糟糕的事情发生。
相反，如果FOPEN没有返回null一切都很好
我就可以开始写这个文件。
这里有一个新的伎俩。
这是一个for循环遍历每个学生，
这看起来如此的相似，我们做了什么之前，
但这个函数是一个表姐的printf称为fprintf文件输出，
并注意在只有2种方式是不同的。
一，它开始用f代替p，
但后来它的第一个参数显然是什么？
[学生]文件。这是一个文件。
这件事称为FP，我们将最终梳理出一个文件指针是什么，
但现在FP仅仅代表我已经打开的文件，
fprintf这里说的文件打印用户的ID，而不是屏幕。
打印用户的名称的文件，而不是在屏幕上，
房子的文件，而不是在屏幕上，然后在这里，很明显，
关闭该文件，然后在这里释放内存。
>> 这个版本2和版本1之间的唯一区别
是fopen和引进此文件*
这个概念fprintf，让我们看看最终的结果是什么。
让我进入我的终端窗口。
让我跑structs2，进入。
看起来一切都很好。让我们重新运行structs2。
123，456，罗布·柯克兰，大卫·马瑟，
789，汤米·马瑟进入。
看起来像它的表现是相同的，但如果我现在做的LS
注意到什么文件是在这里，在我所有的代码，数据库，
让我们打开的是，gedit的数据库，看看。
这不是最性感的文件格式。
这真的是每行，每行一条数据线，
但那些你们谁使用Excel或CSV文件，逗号分隔值，
当然，我可以用fprintf，而不是可能做这样的事情
这样我就可以创建一个Excel文件，相当于
分离用逗号，不只是新的生产线。
>> 在这种情况下，如果我，而不是使用逗号，而不是新的生产线
我可以从字面上如果我在Excel中打开该数据库文件，而不是看起来像这样。
总之，现在我们有能力写入文件
我们现在可以开始持久化数据，保持光盘上
这样我们就可以保持信息的周围一遍又一遍。
注意其他的东西，现在有点熟悉的一对夫妇。
在这个C文件的顶部，我们有一个typedef
因为我们想创建一个数据类型，它表示一个字，
所以这种类型被称为字，和内部的这种结构
这是一个小票友。
为什么一个字组成的，显然是一个数组？
什么是一个词，仅仅凭直觉？
>> 这是一个字符数组。
这是一个字符序列，背靠背。
全部大写的字母恰好是我们武断地说，最大长度
任何字在字典中，我们使用的争夺。
为什么我有一个+1？
空字符。
记得当我们做了Bananagrams的例子，我们需要一个特殊的值
的词语的结尾处，以便跟踪
在的话实际上结束的情况下，作为问题集规范说
在这里，我们正在与一个给定的单词一个布尔值，
一个标志，可以这么说，真或假。
你有没有发现这个词，因为我们意识到
我们真正需要的一种方式记忆不仅是一个字是在争夺
但是否你的人，已经找到了
所以，如果你发现这个词“：”你不能只键入，进入，进入，进入
并得到3分，3分，3分，3分。
我们希望能够黑名单这个词通过设置一个布尔值，
为true，如果你已经发现了，所以这就是为什么我们
封装在该结构中。
>> 现在，在这里争夺，这种结构称为字典。
缺少这里是字的typedef，因为在这种情况下
我们需要封装的一本字典的想法，
和一本字典包含了一大堆的话，
这个数组所暗示的，和那些话是多少呢？
好吧，不管说这个变量的大小。
但我们只需要一个字典。
我们并不需要的数据类型称为字典。
我们只需要其中的一个，所以在C
如果你不说的typedef，你刚才说的结构，然后在大括号中
你把你的变量，然后你把这个名字。
这是声明一个变量称为字典
像这样的。
与此相反，这些行调用Word创建一个可重复使用的数据结构
您可以创建多个副本，就像我们创建
学生的多个副本。
>> 这是什么最终让我们做什么？
让我回去，比方说，一个简单的例子，从简单的时代，
让我开了，让我们说，compare1.c。
的问题，在这里实际上是剥开
层的一个字符串，并开始起飞训练车轮
因为它把一个字符串的所有时间
我们承诺在第1周真的只是一个昵称，
CS50库的东西，看起来多了几分神秘的代名词，
是char *，我们已经看到了这颗恒星。
我们看到它在文件中。
>> 现在，让我们看到为什么我们一直躲在这个细节有一段时间了。
这里是一个名为compare1.c，
它显然要求用户为2个字符串，s和t，
然后，它试图比较这些字符串平等的第26行，
如果他们是平等的说，“你输入同样的事情。”
如果他们不相等，它说，“您输入不同的事情。”
让我继续运行这个程序。
让我进入我的源目录，做一个比较1。编译没问题。
让我运行比较。
我会放大，进入。
说些什么。 HELLO。
我会说些什么了。 HELLO。
我绝对没有输入不同的东西。
>> 让我再试一次。 BYE BYE。
绝对没有什么不同，所以在这里发生了什么事？
那么，什么是真正被比较的第26行吗？
[听不见的学生]
是的，所以它变成了一个字符串，数据类型，是一种善意的谎言。
一个字符串，是一个char *，但什么是一个char *？
，正如他们所说的，是一个char *指针，
和一个指针是一个有效的地址，
一笔在内存中的位置，如果你恰好有输入一个字，如HELLO，
回忆起过去的讨论中的字符串
之类的词，这是HELLO。
请记住，一个词可以表示喜欢HELLO
作为一个字符数组，这样
然后用一个特殊字符结束时称为空字符，
\表示。
实际上是一个字符串是什么？
请注意，这是多的内存块，
而事实上，它的结束是唯一的已知的，一旦你通过整个字符串
寻找特殊的NULL字符。
但是，如果这是一个从我的电脑的内存中的内存块，
让我们武断地说，这个字符串只是很幸运，
它被认为是放置在开始的时候，我的电脑的RAM。
这是字节0，1，2，3，4，5，6 ...
>> 当我说类似的GetString和我做字符串s = GetString的
什么是真正的回来了吗？
为这些过去的几个星期，真的被储存在s
是不是这个字符串本身，而是在这种情况下，被存储的是
因为GetString的确实数0
它是物理上不返回一个字符串。
甚至没有真正概念上的意义。
它的回报率是多少。
这个数字是在内存中的地址，
字符串s，然后，如果我们剥开这层，字符串并不真正存在。
这只是一个简化的CS50库中。
>> 这真的是所谓的char *。
字符是有道理的，因为什么是一个词，像HELLO？
嗯，这是一系列的字符，字符系列。
字符*表示一个字符的地址，
所以这是什么意思返回一个字符串？
一个不错的，简单的方法，返回一个字符串，
而不是试图找出如何我返回到5或6个不同的字节
让我回到哪个字节的地址？
第一个。
换句话说，让我给你一个字符在内存中的地址。
这就是字符“*”代表一个单一的字符在内存中的地址。
调用该变量s。
存放在那个特定的地址，我随意说的是0，
只是为了让事情简单，但在现实中，它通常是一个比较大的数字。
>> 等待一分钟。
如果你只给我的第一个字符的地址，我怎么知道的地址是什么
第二个字符，第三，第四和第五？
[听不见的学生]
你只知道结尾的字符串的方法是通过这个方便的窍门，
因此，当你使用的东西像printf，printf的变相作为它的参数，
还记得我们用％s占位符，然后你传递
变量的存储字符串。
你真正传递的是该字符串的第一个字符的地址。
的printf然后使用for循环或while循环在收到该地址，
例如，0，所以让我现在这样做，
输出（“％s \ n”）;
当我调用printf（“％s \ n”）;我真正提供输出与
在s中的第一个字符的地址，在这种任意的情况下，这是H。
>> printf的知道如何显示在屏幕上，究竟是什么？
的人谁执行printf的实现了一个while循环或循环
说这个字符等于空字符？
如果没有，打印。这个怎么样？
如果不能打印，打印出来，打印出来，打印出来。
哦，这是特殊的。停止打印，并返回给用户。
这是字面上所有的引擎盖下发生的，
这是一个很大消化的第一天，一类，
但现在它是真正了解一切的基石
已经持续我们的电脑的内存内的，
，最终，我们会逗除了一点点帮助
我们的一个朋友在斯坦福大学。
>> 在斯坦福大学的教授尼克Parlante已经这样做了精彩的视频序列
从各种不同的语言，介绍
这个小的黏土动画人物Binky。
你的声音，听到在短短的几秒钟先睹为快
是斯坦福大学教授，你要
现在只有5或6秒的这一权利，
但是这是说明我们将结束今天
（星期三）开始。
我给你宾基，预览的指针乐趣。
[♪音乐♪]教授Parlante]嘿，宾基。
唤醒。它的时间的指针乐趣。
[宾基]那是什么？了解指针吗？
哦，好极了！
>> 我们将看到你在周三。
[CS50.TV]