[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]