1 00:00:00,000 --> 00:00:03,000 [Powered by Google Translate] [4]周 2 00:00:03,000 --> 00:00:05,000 [戴维·J·马兰] [哈佛大学] 3 00:00:05,000 --> 00:00:08,000 这是CS50。[CS50.TV] 4 00:00:08,000 --> 00:00:12,000 >> 好吧,这是CS50,这是第4周开始, 5 00:00:12,000 --> 00:00:16,000 这是最慢的可能的排序算法之一。 6 00:00:16,000 --> 00:00:19,000 哪一个是,我们只能眼睁睁的看着吗? 7 00:00:19,000 --> 00:00:24,000 这是冒泡排序,以大O(N ^ 2)+总和, 8 00:00:24,000 --> 00:00:28,000 而事实上,我们是不是唯一的,在这个世界上似乎知道 9 00:00:28,000 --> 00:00:30,000 什么是冒泡排序,或它的运行时间。 10 00:00:30,000 --> 00:00:33,000 事实上,这是与谷歌的埃里克·施密特(Eric Sc​​hmidt)接受记者采访时 11 00:00:33,000 --> 00:00:45,000 和前参议员巴拉克·奥巴马只不过几年前。 12 00:00:45,000 --> 00:00:48,000 >> 现在,参议员,你在谷歌, 13 00:00:48,000 --> 00:00:54,000 面试的,我喜欢把总统。 14 00:00:54,000 --> 00:00:58,000 现在,它是很难得到一份工作作为总统,你现在正在经历的严峻考验。 15 00:00:58,000 --> 00:01:00,000 它也很难在谷歌找到一份工作。 16 00:01:00,000 --> 00:01:05,000 我们有问题,我们要求我们的候选人的问题, 17 00:01:05,000 --> 00:01:10,000 而这一次是从拉里·施维默。 18 00:01:10,000 --> 00:01:14,000 你们觉得我在开玩笑吗?就在这里。 19 00:01:14,000 --> 00:01:18,000 排序一百万的32位整数的最有效的方法是什么? 20 00:01:18,000 --> 00:01:21,000 [笑声] 21 00:01:21,000 --> 00:01:24,000 良好 22 00:01:24,000 --> 00:01:26,000 对不起。>>不,不,不,不。 23 00:01:26,000 --> 00:01:34,000 我认为,冒泡排序是错误的方式去。 24 00:01:34,000 --> 00:01:39,000 >> 来吧,告诉他这? 25 00:01:39,000 --> 00:01:43,000 上周还记得我们休息了一下,从代码中,至少一天, 26 00:01:43,000 --> 00:01:46,000 并开始专注于一些更高层次的想法和​​解决问题的更一般的 27 00:01:46,000 --> 00:01:49,000 的上下文中搜索和排序, 28 00:01:49,000 --> 00:01:53,000 我们介绍的东西,我们没有一巴掌这个名字在上周, 29 00:01:53,000 --> 00:01:56,000 但渐近符号,大O,大欧米茄, 30 00:01:56,000 --> 00:02:00,000 有时大θ符号,而这些简单的方法 31 00:02:00,000 --> 00:02:02,000 描述的算法的运行时间, 32 00:02:02,000 --> 00:02:05,000 需要多少时间的一种算法来运行。 33 00:02:05,000 --> 00:02:08,000 >> 你可能还记得,你谈到的运行时间的大小 34 00:02:08,000 --> 00:02:11,000 的投入,我们一般称之为N,什么问题可能是, 35 00:02:11,000 --> 00:02:13,000 其中,n是多少人在房间里, 36 00:02:13,000 --> 00:02:17,000 在电话簿的页面的数量,我们开始写东西了 37 00:02:17,000 --> 00:02:21,000 像O(N ^ 2)或O(n)或O(n日志n), 38 00:02:21,000 --> 00:02:24,000 即使在数学没有相当的工作如此完美 39 00:02:24,000 --> 00:02:28,000 为² - N / 2或类似的东西 40 00:02:28,000 --> 00:02:31,000 相反,我们会扔掉一些低阶, 41 00:02:31,000 --> 00:02:34,000 和动机是我们真的想要一个 42 00:02:34,000 --> 00:02:37,000 客观地评估排序 43 00:02:37,000 --> 00:02:39,000 程序的性能或算法的性能 44 00:02:39,000 --> 00:02:42,000 在一天结束的时候有没有做的,例如, 45 00:02:42,000 --> 00:02:45,000 今天你的电脑速度。 46 00:02:45,000 --> 00:02:47,000 >> 例如,如果实现冒泡排序, 47 00:02:47,000 --> 00:02:50,000 或者你在今天的计算机上,实现合并排序或选择排序, 48 00:02:50,000 --> 00:02:53,000 在2 GHz计算机,并运行它, 49 00:02:53,000 --> 00:02:56,000 需要一定的秒数,明年有一个3 GHz 50 00:02:56,000 --> 00:02:59,000 4 GHz的电脑,你可能会然后声称:“哇,我的算法 51 00:02:59,000 --> 00:03:03,000 是现在的两倍快,“在现实中显然不是这样。 52 00:03:03,000 --> 00:03:06,000 这只是硬件已经变得更快,但您的计算机 53 00:03:06,000 --> 00:03:10,000 并没有,所以我们真的要扔掉的东西一样 54 00:03:10,000 --> 00:03:13,000 乘2或3的倍数,当涉及到描述 55 00:03:13,000 --> 00:03:17,000 的速度有多快或慢的算法是真的只是集中 56 00:03:17,000 --> 00:03:20,000 在n或某些因素, 57 00:03:20,000 --> 00:03:24,000 其一些功率中的种类的情况下,从上周。 58 00:03:24,000 --> 00:03:27,000 回想一下,归并排序的帮助 59 00:03:27,000 --> 00:03:31,000 我们能够这样做大大优于冒泡排序,选择排序 60 00:03:31,000 --> 00:03:33,000 甚至插入排序。 61 00:03:33,000 --> 00:03:36,000 >> 我们得到了n日志n,并再次, 62 00:03:36,000 --> 00:03:39,000 记得,日志n一般是指生长 63 00:03:39,000 --> 00:03:43,000 更慢则n,所以n日志n迄今还是不错的 64 00:03:43,000 --> 00:03:45,000 因为它是比n²少。 65 00:03:45,000 --> 00:03:47,000 但要实现n日志n归并排序 66 00:03:47,000 --> 00:03:51,000 什么是基本的想法,我们必须充分利用胚芽 67 00:03:51,000 --> 00:03:54,000 我们还利用在0周吗? 68 00:03:54,000 --> 00:03:58,000 我们是怎么解决的排序问题,巧妙地与归并排序? 69 00:03:58,000 --> 00:04:04,000 什么是重要的见解,也许? 70 00:04:04,000 --> 00:04:07,000 任何人在所有。 71 00:04:07,000 --> 00:04:09,000 好吧,让我们退后一步。 72 00:04:09,000 --> 00:04:11,000 你自己的话描述归并排序。 73 00:04:11,000 --> 00:04:15,000 它是如何工作的? 74 00:04:15,000 --> 00:04:17,000 好了,我们将排回0周。 75 00:04:17,000 --> 00:04:19,000 好吧,是的。 76 00:04:19,000 --> 00:04:22,000 [听不见的学生] 77 00:04:22,000 --> 00:04:26,000 好了,好了,所以我们的数字数组划分成2个。 78 00:04:26,000 --> 00:04:29,000 我们整理的那件,然后我们合并, 79 00:04:29,000 --> 00:04:33,000 我们已经看到了这个想法之前,这个大的问题 80 00:04:33,000 --> 00:04:36,000 和切碎成一个问题,这个大,这个大。 81 00:04:36,000 --> 00:04:38,000 >> 调出电话簿例如。 82 00:04:38,000 --> 00:04:42,000 回想一下自我计数算法从数周前, 83 00:04:42,000 --> 00:04:45,000 这里总结了这个伪所以合并排序。 84 00:04:45,000 --> 00:04:48,000 当你给定的n个元素,首先是仔细检查。 85 00:04:48,000 --> 00:04:51,000 如果N <2,没有做任何事情在所有 86 00:04:51,000 --> 00:04:55,000 因为如果n <2,那么显然,n是0或1, 87 00:04:55,000 --> 00:04:57,000 ,因此,如果它是0或1,没有什么排序。 88 00:04:57,000 --> 00:04:59,000 你就大功告成了。 89 00:04:59,000 --> 00:05:01,000 您的列表是平凡的排序。 90 00:05:01,000 --> 00:05:04,000 否则,如果你有2个或更多的元素,然后再划分 91 00:05:04,000 --> 00:05:06,000 分为两半,左边和右边。 92 00:05:06,000 --> 00:05:09,000 排序每个那些半部,然后合并排序条件半部。 93 00:05:09,000 --> 00:05:13,000 但这里的问题是,乍看之下,这感觉就像我们撑船。 94 00:05:13,000 --> 00:05:17,000 如果我问你,这n个元素进行排序,这是一个循环的定义 95 00:05:17,000 --> 00:05:22,000 你告诉我,“好吧,好吧,我们将那些N / 2和那些N / 2个元素进行排序,” 96 00:05:22,000 --> 00:05:27,000 然后我的下一个问题将是:“好,你是怎么排序的n / 2个元素?” 97 00:05:27,000 --> 00:05:30,000 >> 但是,由于这项计划的结构, 98 00:05:30,000 --> 00:05:33,000 因为有这个基础的情况下,可以这么说, 99 00:05:33,000 --> 00:05:39,000 这种特殊情况下,如果n <2回一些固定的值,如立即说。 100 00:05:39,000 --> 00:05:42,000 不回应与相同的圆形的答案。 101 00:05:42,000 --> 00:05:46,000 这个过程中,这种周期性终将结束。 102 00:05:46,000 --> 00:05:50,000 如果我问你“排序n个元素,”和你说,“好吧,整理这些N / 2” 103 00:05:50,000 --> 00:05:53,000 然后你说,“很好,排序这些N / 4,N / 8,N/16,” 104 00:05:53,000 --> 00:05:56,000 最终你会除以一个足够大的数 105 00:05:56,000 --> 00:05:59,000 ,你将有只有1元左,在这一点,你可以说, 106 00:05:59,000 --> 00:06:02,000 “这里,这里是一个有序的单个元素。” 107 00:06:02,000 --> 00:06:06,000 然后该算法的辉煌在这里是从这一事实派生 108 00:06:06,000 --> 00:06:09,000 一旦你把所有这些单独排序的列表, 109 00:06:09,000 --> 00:06:12,000 所有这一切都是大小为1,这似乎是无用的, 110 00:06:12,000 --> 00:06:15,000 一旦你开始把它们合并,将它们合并 111 00:06:15,000 --> 00:06:19,000 建立终于抢在视频的最后排序的名单。 112 00:06:19,000 --> 00:06:22,000 >> 但这样的想法远远超出了排序。 113 00:06:22,000 --> 00:06:26,000 有这种想法,在这个程序称为递归嵌入, 114 00:06:26,000 --> 00:06:29,000 是一个程序,让你的想法, 115 00:06:29,000 --> 00:06:32,000 解决一些问题,你叫你自己, 116 00:06:32,000 --> 00:06:36,000 或把你是一个函数的编程语言的上下文中, 117 00:06:36,000 --> 00:06:39,000 为了解决一个问题,你的函数调用自己 118 00:06:39,000 --> 00:06:42,000 一而再,再而三,但你的功能 119 00:06:42,000 --> 00:06:44,000 不能称自己为无限多次。 120 00:06:44,000 --> 00:06:47,000 最终,你必须走出谷底,可以这么说, 121 00:06:47,000 --> 00:06:49,000 并有一些硬编码的基本条件, 122 00:06:49,000 --> 00:06:53,000 在这一点上停止这样要求自己,整个过程 123 00:06:53,000 --> 00:06:56,000 其实最终停止。 124 00:06:56,000 --> 00:06:58,000 这究竟是什么意思,递归? 125 00:06:58,000 --> 00:07:01,000 >> 让我们来看看,如果我们可以做一个简单的,简单的例子,比方说, 126 00:07:01,000 --> 00:07:03,000 3人,在这里我在舞台上,如果有人很舒服。 127 00:07:03,000 --> 00:07:06,000 1,来时,2和3上。 128 00:07:06,000 --> 00:07:09,000 如果你要来这里。 129 00:07:09,000 --> 00:07:12,000 如果你想站在旁边,我在这里行,假设手头上的问题 130 00:07:12,000 --> 00:07:15,000 是非常平凡的人谁是这里数一数。 131 00:07:15,000 --> 00:07:18,000 但坦率地说,我累了所有这些计数的例子。 132 00:07:18,000 --> 00:07:21,000 这将需要一些时间,1,2,点,点,点。 133 00:07:21,000 --> 00:07:23,000 这是怎么回事采取永远。 134 00:07:23,000 --> 00:07:25,000 我宁愿只平底船这个问题的帮助下,你叫什么名字? 135 00:07:25,000 --> 00:07:27,000 >>萨拉,萨拉。所有权利。 136 00:07:27,000 --> 00:07:29,000 凯利。>>凯利? 137 00:07:29,000 --> 00:07:31,000 >> >>威利,莎拉,凯莉和威利,威利。 138 00:07:31,000 --> 00:07:34,000 现在,我一直在问的问题,有人 139 00:07:34,000 --> 00:07:37,000 有多少人在这个舞台上,我不知道。 140 00:07:37,000 --> 00:07:40,000 这是一个很长的列表,所以不是我会做这一招。 141 00:07:40,000 --> 00:07:43,000 我要问旁边的人给我做的大部分工作, 142 00:07:43,000 --> 00:07:46,000 有一次她做的大部分工作 143 00:07:46,000 --> 00:07:49,000 我会做最少的工作,只需添加1 144 00:07:49,000 --> 00:07:51,000 她的回答是,所以在这里我们去。 145 00:07:51,000 --> 00:07:54,000 我一直在问有多少人在舞台上演出。 146 00:07:54,000 --> 00:07:57,000 有多少人在舞台上你左边的吗? 147 00:07:57,000 --> 00:08:00,000 我的左边?>>好吧,但不要欺骗。 148 00:08:00,000 --> 00:08:04,000 这是很好的,这是正确的,但如果我们要继续这样的逻辑 149 00:08:04,000 --> 00:08:08,000 让我们假设你同样希望能撑船你左边的这个问题, 150 00:08:08,000 --> 00:08:11,000 因此,而不是答案直接去前进,只是推卸责任。 151 00:08:11,000 --> 00:08:14,000 哦,很多人都为我的左边吗? 152 00:08:14,000 --> 00:08:16,000 有多少人是左边? 153 00:08:16,000 --> 00:08:18,000 1。 154 00:08:18,000 --> 00:08:27,000 [笑声] 155 00:08:27,000 --> 00:08:30,000 好了,所以0,所以现在什么威利已完成 156 00:08:30,000 --> 00:08:33,000 你回到你的答案这方向说0。 157 00:08:33,000 --> 00:08:36,000 现在,你应该怎么办?>> 1。 158 00:08:36,000 --> 00:08:39,000 好了,你是1,所以你说,“好吧,我要加1 159 00:08:39,000 --> 00:08:41,000 威利的计数,“1 + 0。 160 00:08:41,000 --> 00:08:43,000 您现在所以你正确的答案是现在, 161 00:08:43,000 --> 00:08:45,000 1。“和我的是2。 162 00:08:45,000 --> 00:08:48,000 好,所以你会觉得前面的回答1, 163 00:08:48,000 --> 00:08:51,000 加入少量的工作,你想要做的,这是+1。 164 00:08:51,000 --> 00:08:55,000 您现在有2个,然后把我哪个值? 165 00:08:55,000 --> 00:08:57,000 3,我的意思是,很抱歉,2。 166 00:08:57,000 --> 00:08:59,000 好。 167 00:08:59,000 --> 00:09:02,000 >> 好了,我们拥有0到左边。 168 00:09:02,000 --> 00:09:05,000 然后我们有1,然后再加2, 169 00:09:05,000 --> 00:09:07,000 现在你递过来的2号, 170 00:09:07,000 --> 00:09:10,000 所以我说,没关系,+1,3。 171 00:09:10,000 --> 00:09:13,000 确实有3人,站在我旁边的这个舞台上, 172 00:09:13,000 --> 00:09:16,000 因此,我们可以很明显这样做非常线性, 173 00:09:16,000 --> 00:09:19,000 非常显而易见的方式,但我们真的什么呢? 174 00:09:19,000 --> 00:09:21,000 我们采取了一个大小为3最初的问题。 175 00:09:21,000 --> 00:09:24,000 然后,我们把它弄坏了一个问题分解成大小为2, 176 00:09:24,000 --> 00:09:27,000 然后一个问题大小为1,然后在最后的基本情况 177 00:09:27,000 --> 00:09:29,000 是真的,哦,还有一个人也没有, 178 00:09:29,000 --> 00:09:33,000 在这一点威利有效地返回一个硬编码的答案了几次, 179 00:09:33,000 --> 00:09:36,000 第二个,然后向上冒泡,冒泡,冒泡, 180 00:09:36,000 --> 00:09:39,000 然后以增加一个额外的1在这 181 00:09:39,000 --> 00:09:41,000 我们已经实现了这个递归的基本思想。 182 00:09:41,000 --> 00:09:44,000 >> 现在,在这种情况下,它并没有真正解决的一个问题 183 00:09:44,000 --> 00:09:46,000 任何更有效地发挥作用,那么我们迄今为止见过的。 184 00:09:46,000 --> 00:09:48,000 但仔细想想,我们所做的舞台上迄今为止的算法。 185 00:09:48,000 --> 00:09:51,000 我们有8个纸写在黑板上, 186 00:09:51,000 --> 00:09:55,000 视频时,肖恩一直在寻找的7号,他真的什么? 187 00:09:55,000 --> 00:09:58,000 ,他没有做任何形式的鸿沟和征服。 188 00:09:58,000 --> 00:10:01,000 他没有做任何形式的递归。 189 00:10:01,000 --> 00:10:03,000 相反,他只是做这个线性算法。 190 00:10:03,000 --> 00:10:07,000 但是,当我们的思想介绍舞台上的排序数字生活上周 191 00:10:07,000 --> 00:10:09,000 然后我们有这种本能的中间, 192 00:10:09,000 --> 00:10:13,000 在这一点,我们有一个小的列表大小为4或另一个列表的大小为4, 193 00:10:13,000 --> 00:10:17,000 然后我们有相同的问题,所以我们重复,重复,重复。 194 00:10:17,000 --> 00:10:19,000 换句话说,我们递归。 195 00:10:19,000 --> 00:10:24,000 非常感谢您给我们的3名志愿者在这里展示我们的递归。 196 00:10:24,000 --> 00:10:28,000 >> 让我们来看看如果我们不能更具体一点, 197 00:10:28,000 --> 00:10:30,000 解决问题了,我们可以很轻松地做, 198 00:10:30,000 --> 00:10:34,000 但我们将使用它作为实现这一基本思路的垫脚石。 199 00:10:34,000 --> 00:10:37,000 如果我想的一串数字来计算的总和, 200 00:10:37,000 --> 00:10:39,000 例如,如果你通过在3号, 201 00:10:39,000 --> 00:10:42,000 我想给你3西格玛的价值, 202 00:10:42,000 --> 00:10:46,000 所以总和3 + 2 + 1 + 0。 203 00:10:46,000 --> 00:10:48,000 我想要得到的答案6 204 00:10:48,000 --> 00:10:51,000 让我们来实现这个sigma函数,这个求和函数 205 00:10:51,000 --> 00:10:54,000 ,再次取入输入,然后返回求和 206 00:10:54,000 --> 00:10:57,000 这一数字一直下降到0。 207 00:10:57,000 --> 00:10:59,000 我们可以做到这一点非常简单,对不对? 208 00:10:59,000 --> 00:11:01,000 我们能做到这一点,一些种循环结构, 209 00:11:01,000 --> 00:11:04,000 所以,让我继续前进,赶快开始。 210 00:11:04,000 --> 00:11:07,000 >> 包括stdio.h中。 211 00:11:07,000 --> 00:11:09,000 让我让我自己到这里主要工作。 212 00:11:09,000 --> 00:11:12,000 让我们拯救为sigma.c。 213 00:11:12,000 --> 00:11:14,000 然后,我要在这里,我要声明的廉政n, 214 00:11:14,000 --> 00:11:18,000 我要做到以下几点,而用户不配合。 215 00:11:18,000 --> 00:11:22,000 当用户还没有给我一个正数 216 00:11:22,000 --> 00:11:26,000 让我继续前进,促使他们为n =调用getInt, 217 00:11:26,000 --> 00:11:28,000 并让我给他们一些指示做什么, 218 00:11:28,000 --> 00:11:33,000 因此我们知道printf(“请正整数”)。 219 00:11:33,000 --> 00:11:39,000 只是像这样简单的东西比较的时候,我们打了14行 220 00:11:39,000 --> 00:11:42,000 现在,我们有可能在n为正整数。 221 00:11:42,000 --> 00:11:44,000 >> 现在,让我们用它做什么。 222 00:11:44,000 --> 00:11:50,000 让我继续和计算的总和,所以int总和=Σ(N)。 223 00:11:50,000 --> 00:11:54,000 Sigma是求和,所以我只是写爱好者。 224 00:11:54,000 --> 00:11:56,000 我们只把它西格玛有。 225 00:11:56,000 --> 00:11:58,000 的总和,现在我要打印出来的结果, 226 00:11:58,000 --> 00:12:08,000 printf(“请的总和为%d \ n”,总结)。 227 00:12:08,000 --> 00:12:11,000 然后我就返回0的良好措施。 228 00:12:11,000 --> 00:12:15,000 除了有趣的部分,我们所做的一切,这个程序需要, 229 00:12:15,000 --> 00:12:18,000 这实际上是实施六西格玛的功能。 230 00:12:18,000 --> 00:12:22,000 >> 让我走在这里的底部,并让我申报功能标准差。 231 00:12:22,000 --> 00:12:26,000 它采取了一个整数类型的变量, 232 00:12:26,000 --> 00:12:30,000 和什么样的数据类型,我想大概是从Σ返回吗? 233 00:12:30,000 --> 00:12:34,000 诠释,因为我想它符合我的期望,第15行。 234 00:12:34,000 --> 00:12:37,000 在这里,让我继续前进,实现这 235 00:12:37,000 --> 00:12:41,000 一个非常简单的方法。 236 00:12:41,000 --> 00:12:45,000 >> 让我们继续前进,并说int总和= 0, 237 00:12:45,000 --> 00:12:47,000 现在我要在这儿有一个小的循环 238 00:12:47,000 --> 00:12:50,000 会说这样的事情, 239 00:12:50,000 --> 00:13:01,000 (INT I = 0; I <=数字,我+ +)之和+ =。 240 00:13:01,000 --> 00:13:05,000 然后我将返回总和。 241 00:13:05,000 --> 00:13:07,000 我可以在任何数量的方式实现这个。 242 00:13:07,000 --> 00:13:09,000 我可以使用一个while循环。 243 00:13:09,000 --> 00:13:11,000 我可以跳过的总和变量,如果我真的想, 244 00:13:11,000 --> 00:13:15,000 但在短期,我们只需要一个函数,如果我不混日子声明总和为0。 245 00:13:15,000 --> 00:13:18,000 然后,它会遍历并贯穿数,从0 246 00:13:18,000 --> 00:13:23,000 在每次迭代补充说,目前的价值总和,然后返回总和。 247 00:13:23,000 --> 00:13:25,000 >> 现在,这里有一个轻微的优化。 248 00:13:25,000 --> 00:13:29,000 这可能是一个死不瞑目,但就这样吧。这就是现在的罚款。 249 00:13:29,000 --> 00:13:32,000 我们至少彻底和投0中一路就到了。 250 00:13:32,000 --> 00:13:34,000 并不难,很简单, 251 00:13:34,000 --> 00:13:37,000 但事实证明,我们的sigma函数有同样的机会 252 00:13:37,000 --> 00:13:39,000 我们在这里所做过的舞台上。 253 00:13:39,000 --> 00:13:42,000 在舞台上,我们就只能有多少人在我旁边, 254 00:13:42,000 --> 00:13:47,000 而如果我们想数一数3 + 2 + 1 255 00:13:47,000 --> 00:13:51,000 同样,我们可以下降到0平底船的功能 256 00:13:51,000 --> 00:13:55,000 相反,我会形容为递归。 257 00:13:55,000 --> 00:13:57,000 下面让我们做一个快速的完整性检查,确保我没有混日子。 258 00:13:57,000 --> 00:14:00,000 >> 我知道有这个程序,至少有一件事我没有做错。 259 00:14:00,000 --> 00:14:04,000 当我按下回车键,我会得到什么样的骂我吗? 260 00:14:04,000 --> 00:14:06,000 我该怎么大叫:约? 261 00:14:06,000 --> 00:14:11,000 是啊,我忘了原型,所以我用西格玛第15行调用的函数, 262 00:14:11,000 --> 00:14:16,000 但它没有宣布,直到第22行,所以我最好主动去这里 263 00:14:16,000 --> 00:14:22,000 声明原型,我会说:INTΣ(整型数),就是这样。 264 00:14:22,000 --> 00:14:24,000 它的实施在底部。 265 00:14:24,000 --> 00:14:27,000 >> 或者我可以解决这个问题的另一种方式, 266 00:14:27,000 --> 00:14:30,000 我可以移动的功能在那里,这是不坏, 267 00:14:30,000 --> 00:14:32,000 但至少当你的程序开始长,坦率地说, 268 00:14:32,000 --> 00:14:35,000 我觉得有一定的价值,总是有主的顶部 269 00:14:35,000 --> 00:14:38,000 让你的读者可以打开该文件,然后立即看到 270 00:14:38,000 --> 00:14:40,000 什么是程序做,而不必通过搜索 271 00:14:40,000 --> 00:14:42,000 寻找,主要功能。 272 00:14:42,000 --> 00:14:49,000 让我们深入到我的终端窗口,在这里,试图使SIGMA西格玛, 273 00:14:49,000 --> 00:14:51,000 我搞砸了。 274 00:14:51,000 --> 00:14:55,000 隐式声明的函数调用getInt我忘了做什么? 275 00:14:55,000 --> 00:14:57,000 [听不见的学生] 276 00:14:57,000 --> 00:15:00,000 好,显然是一个常见的​​错误,让我们把这个在这里, 277 00:15:00,000 --> 00:15:04,000 cs50.h,现在让我们回到我的终端窗口。 278 00:15:04,000 --> 00:15:08,000 >> 我会清除屏幕,我会重新运行西格玛。 279 00:15:08,000 --> 00:15:11,000 它似乎已编译的。让我跑去标准差。 280 00:15:11,000 --> 00:15:15,000 我会输入数字3,我没得到6,所以不是严格的检查, 281 00:15:15,000 --> 00:15:18,000 但它至少乍一看似乎是工作,但现在让我们撕裂它除了, 282 00:15:18,000 --> 00:15:21,000 让我们再次,利用递归的想法, 283 00:15:21,000 --> 00:15:24,000 在一个非常简单的背景,所以,在几个星期的时间 284 00:15:24,000 --> 00:15:27,000 当我们开始探索爱好者的数据结构阵列 285 00:15:27,000 --> 00:15:30,000 我们有另一个工具箱中的工具,用以 286 00:15:30,000 --> 00:15:33,000 操作这些数据结构,正如我们将看到的。 287 00:15:33,000 --> 00:15:36,000 这是迭代的方法,基于循环的方法。 288 00:15:36,000 --> 00:15:39,000 >> 让我,而不是现在这样做。 289 00:15:39,000 --> 00:15:44,000 让我可以这样说,数字的总和 290 00:15:44,000 --> 00:15:48,000 下降到0真的是同样的事情, 291 00:15:48,000 --> 00:15:53,000 数+Σ(数量 - 1)。 292 00:15:53,000 --> 00:15:57,000 换句话说,就像在舞台上,我踢了我旁边的人, 293 00:15:57,000 --> 00:16:00,000 而他们又不停地踢,直到我们终于走出谷底,威利, 294 00:16:00,000 --> 00:16:03,000 返回一个硬编码的答案,如0。 295 00:16:03,000 --> 00:16:07,000 现在,我们同样踢西格玛 296 00:16:07,000 --> 00:16:10,000 最初被称为相同的功能,但这里的关键洞察力 297 00:16:10,000 --> 00:16:12,000 是我们,而不是调用标准差相同。 298 00:16:12,000 --> 00:16:14,000 我们不及格的n。 299 00:16:14,000 --> 00:16:17,000 我们清楚地传递 - 1, 300 00:16:17,000 --> 00:16:20,000 所以一个略小的问题,稍小的问题。 301 00:16:20,000 --> 00:16:23,000 >> 不幸的是,这是不完全的解决方案,但和之前我们解决 302 00:16:23,000 --> 00:16:26,000 什么可能会跳出你们中的一些明显 303 00:16:26,000 --> 00:16:28,000 让我继续前进,重新运行使。 304 00:16:28,000 --> 00:16:30,000 它似乎是编译好的。 305 00:16:30,000 --> 00:16:32,000 让我重新运行西格玛6。 306 00:16:32,000 --> 00:16:37,000 哎呀,让我重新运行西格玛6。 307 00:16:37,000 --> 00:16:42,000 这之前我们已经看到,尽管偶然一次为好。 308 00:16:42,000 --> 00:16:48,000 为什么我得到这个神秘的分割故障?是啊。 309 00:16:48,000 --> 00:16:50,000 [听不见的学生] 310 00:16:50,000 --> 00:16:53,000 有没有碱的情况下,更具体地,可能发生的事情吗? 311 00:16:53,000 --> 00:16:58,000 这是一个症状,什么样的行为呢? 312 00:16:58,000 --> 00:17:00,000 说大声一点。 313 00:17:00,000 --> 00:17:02,000 [听不见的学生] 314 00:17:02,000 --> 00:17:05,000 这是一个无限循环,有效地无限循环的问题 315 00:17:05,000 --> 00:17:08,000 当它们涉及在这种情况下,一个函数递归调用自身, 316 00:17:08,000 --> 00:17:10,000 每次你调用一个函数,会发生什么? 317 00:17:10,000 --> 00:17:13,000 好了,回想起我们提出了如何在一台电脑的内存。 318 00:17:13,000 --> 00:17:16,000 我们说,有这样的内存块,叫做堆栈的底部, 319 00:17:16,000 --> 00:17:19,000 每次你调用一个函数多一点的内存被放 320 00:17:19,000 --> 00:17:24,000 这个所谓的堆栈,其中包含该函数的局部变量或参数, 321 00:17:24,000 --> 00:17:27,000 因此,如果SIGMA调用SIGMA西格玛来电要求西格玛 322 00:17:27,000 --> 00:17:29,000  要求SIGMA这个故事的结束? 323 00:17:29,000 --> 00:17:31,000 >> 那么,它最终超支总额 324 00:17:31,000 --> 00:17:33,000 ,你必须提供给您的计算机的内存。 325 00:17:33,000 --> 00:17:37,000 您溢出的部分,你应该留在, 326 00:17:37,000 --> 00:17:40,000 你得到这个分割故障,核心转储, 327 00:17:40,000 --> 00:17:43,000 什么是核心转储的意思是,我现在有一个文件名为核心 328 00:17:43,000 --> 00:17:46,000 这是一个文件,包含零和一 329 00:17:46,000 --> 00:17:49,000 实际上在未来将是有用诊断。 330 00:17:49,000 --> 00:17:52,000 如果这不是很明显,你在哪里,你的错误是 331 00:17:52,000 --> 00:17:54,000 实际上,你可以做一些取证分析,可以这么说, 332 00:17:54,000 --> 00:17:58,000 这一核心转储文件,这,又是一大堆的零和一 333 00:17:58,000 --> 00:18:02,000 你的程序在内存中,基本上代表了 334 00:18:02,000 --> 00:18:05,000 坠毁在这样的时刻。 335 00:18:05,000 --> 00:18:11,000 >> 这里的修复,我们不能只是一味地返回西格玛, 336 00:18:11,000 --> 00:18:14,000 的数目+西格玛一个略小的问题。 337 00:18:14,000 --> 00:18:16,000 我们需要有一些基本情况, 338 00:18:16,000 --> 00:18:19,000 什么的基本情况大概是什么? 339 00:18:19,000 --> 00:18:22,000 [听不见的学生] 340 00:18:22,000 --> 00:18:25,000 好了,只要数是积极的,我们其实应该返回这一点, 341 00:18:25,000 --> 00:18:29,000 或者换一种说法,如果数字是多少,说,<= 0 342 00:18:29,000 --> 00:18:32,000 你知道吗,我会继续前进,返回0, 343 00:18:32,000 --> 00:18:36,000 很像威利,和其他人,我要继续前进 344 00:18:36,000 --> 00:18:41,000 并将此,所以它不是,要短得多 345 00:18:41,000 --> 00:18:44,000 比,我们掀起了第一个使用for循环的迭代版本, 346 00:18:44,000 --> 00:18:48,000 但请注意,这种优雅。 347 00:18:48,000 --> 00:18:51,000 而不是返回一些数字,并执行所有的数学 348 00:18:51,000 --> 00:18:54,000 并加入了局部变量 349 00:18:54,000 --> 00:18:57,000 相反,你说:“好吧,如果这是一个超级简单的问题, 350 00:18:57,000 --> 00:19:01,000 像<0,让我立即返回0。“ 351 00:19:01,000 --> 00:19:03,000 >> 我们不会去打扰支持负数, 352 00:19:03,000 --> 00:19:05,000 所以我要硬编码的值为0。 353 00:19:05,000 --> 00:19:08,000 但是,除此之外,要实现这个想法的总结 354 00:19:08,000 --> 00:19:11,000 所有这些数字放在一起,可以有效地一小口 355 00:19:11,000 --> 00:19:14,000 出了问题,就像我们在这里所做过的舞台上, 356 00:19:14,000 --> 00:19:18,000 然后平底船剩下的问题,旁边的人, 357 00:19:18,000 --> 00:19:20,000 但在这种情况下一个人是自己。 358 00:19:20,000 --> 00:19:22,000 这是一个具有相同名称的功能。 359 00:19:22,000 --> 00:19:25,000 只要把它体积更小,小的问题,每次 360 00:19:25,000 --> 00:19:28,000 即使我们没有很正式的事情在这里的代码 361 00:19:28,000 --> 00:19:33,000 这究竟是怎么回事0周的电​​话簿。 362 00:19:33,000 --> 00:19:36,000 这究竟是怎么回事,在过去的几周里,肖恩 363 00:19:36,000 --> 00:19:39,000 和我们寻找数字的示威。 364 00:19:39,000 --> 00:19:42,000 它的问题,划分了一遍又一遍。 365 00:19:42,000 --> 00:19:44,000 >> 换句话说,现在有一种方法翻译 366 00:19:44,000 --> 00:19:47,000 这个现实世界的结构,这种更高的层次结构 367 00:19:47,000 --> 00:19:51,000 分而治之,一遍又一遍的东西 368 00:19:51,000 --> 00:19:56,000 在代码中,所以这是随着时间的推移,我们将再次看到的东西。 369 00:19:56,000 --> 00:20:00,000 现在,顺便说一句,如果你是新递归,你应该至少现在明白了 370 00:20:00,000 --> 00:20:02,000 为什么这很有趣。 371 00:20:02,000 --> 00:20:05,000 我要访问google.com, 372 00:20:05,000 --> 00:20:17,000 我要寻找一些技巧和窍门递归进入。 373 00:20:17,000 --> 00:20:21,000 告诉你旁边的人,如果他们不是刚才笑。 374 00:20:21,000 --> 00:20:23,000 你的意思是递归? 375 00:20:23,000 --> 00:20:25,000 难道你的意思是啊,我们走吧。 376 00:20:25,000 --> 00:20:28,000 好了,现在剩下的大家。 377 00:20:28,000 --> 00:20:30,000 某处有一个小的嵌入式复活节彩蛋在谷歌。 378 00:20:30,000 --> 00:20:33,000 顺便说一句,我们把课程的网站上的链接 379 00:20:33,000 --> 00:20:36,000 今天是这个网格的各种排序算法, 380 00:20:36,000 --> 00:20:39,000 其中有些我们看着最后一周,但这种可视化有什么好处 381 00:20:39,000 --> 00:20:43,000 当你试图周围包裹你的心有关的各种事情算法 382 00:20:43,000 --> 00:20:46,000 我知道,你可以很容易地现在就开始与不同类型的输入。 383 00:20:46,000 --> 00:20:50,000 所有的输入反转,输入大多排序条件,输入随机的,等等。 384 00:20:50,000 --> 00:20:53,000 当你再次尝试,区分这些东西在你的心中 385 00:20:53,000 --> 00:20:57,000 实现了课程网站的讲座上,该URL 386 00:20:57,000 --> 00:21:00,000 可能会帮助你通过其中的一些原因。 387 00:21:00,000 --> 00:21:05,000 >> 今天,我们终于得到了一段时间后要解决这个问题, 388 00:21:05,000 --> 00:21:08,000 这是交换功能,这只是没有工作, 389 00:21:08,000 --> 00:21:12,000 和什么是最根本的问题,这个功能交换, 390 00:21:12,000 --> 00:21:15,000 目标,其中的时间是,再次,交换的值,在这里和这里 391 00:21:15,000 --> 00:21:17,000 如出现这种情况呢? 392 00:21:17,000 --> 00:21:20,000 这实际上并没有工作。为什么呢? 393 00:21:20,000 --> 00:21:22,000 是啊。 394 00:21:22,000 --> 00:21:28,000 [听不见的学生] 395 00:21:28,000 --> 00:21:31,000 没错,这bugginess的解释 396 00:21:31,000 --> 00:21:34,000 简直是因为当你调用函数在C 397 00:21:34,000 --> 00:21:38,000 这些功能需要的参数,就像A和B, 398 00:21:38,000 --> 00:21:42,000 你是通过你的任何值,该功能提供副本。 399 00:21:42,000 --> 00:21:46,000 你是不是自己提供的原始值, 400 00:21:46,000 --> 00:21:49,000 所以我们看到这在buggyc的背景下, 401 00:21:49,000 --> 00:21:52,000 buggy3.c,这看起来有点像这样。 402 00:21:52,000 --> 00:21:57,000 >> 回想一下,我们有x和y分别初始化为1和2。 403 00:21:57,000 --> 00:21:59,000 然后,我们打印出它们是什么。 404 00:21:59,000 --> 00:22:03,000 然后,我要求我的x,y调用swap交换他们的。 405 00:22:03,000 --> 00:22:06,000 但问题是,交换的工作, 406 00:22:06,000 --> 00:22:10,000 但只有在交换的范围的函数本身。 407 00:22:10,000 --> 00:22:13,000 只要我们打了40行这些交换值 408 00:22:13,000 --> 00:22:16,000 被扔掉了,所以没有什么 409 00:22:16,000 --> 00:22:21,000 在实际上改变了原有的功能,主要是在所有, 410 00:22:21,000 --> 00:22:26,000 所以,如果你认为这看起来像在我们的记忆中 411 00:22:26,000 --> 00:22:29,000 如果此电路板的左手侧表示- 412 00:22:29,000 --> 00:22:33,000 我会尽我所能为大家看到这个如果左侧板 413 00:22:33,000 --> 00:22:37,000 代表,说,你的RAM,堆栈增长了这种方式, 414 00:22:37,000 --> 00:22:43,000 和我们调用一个函数像主,主有2个局部变量,x和y, 415 00:22:43,000 --> 00:22:48,000 让我们在这里描述为x,让我们在这里描述为y, 416 00:22:48,000 --> 00:22:55,000 ,让我们把值1和2中,所以在此主要是, 417 00:22:55,000 --> 00:22:58,000 当主呼叫交换功能的操作系统 418 00:22:58,000 --> 00:23:02,000 给自己的大片的内存堆栈上的交换功能, 419 00:23:02,000 --> 00:23:04,000 它自己的堆栈帧,可以这么说。 420 00:23:04,000 --> 00:23:08,000 它也分配这些32位的int型。 421 00:23:08,000 --> 00:23:11,000 它发生在A和B,但是这完全是任意的。 422 00:23:11,000 --> 00:23:13,000 它可以叫他们为所欲为,但会发生什么,当主 423 00:23:13,000 --> 00:23:19,000 调用swap是需要1,把一个副本,将副本。 424 00:23:19,000 --> 00:23:23,000 >> 掉期为1的局部变量,不过,叫什么?>> TMP。 425 00:23:23,000 --> 00:23:27,000 TMP,所以让我给自己32位, 426 00:23:27,000 --> 00:23:29,000 我做了什么在这个功能吗? 427 00:23:29,000 --> 00:23:34,000 我,诠释TMP说得到,因此有1,所以我这样做时,我们上次播放的这个例子。 428 00:23:34,000 --> 00:23:39,000 然后,得到b,所以b是2,所以现在变成2个, 429 00:23:39,000 --> 00:23:42,000 现在b得到温度,因此温度是1, 430 00:23:42,000 --> 00:23:44,000 所以现在B变成这样。 431 00:23:44,000 --> 00:23:46,000 这是伟大的。它的工作。 432 00:23:46,000 --> 00:23:49,000 但是,当尽快在函数返回 433 00:23:49,000 --> 00:23:52,000 交换的存储器有效地消失,以便它可以被重用 434 00:23:52,000 --> 00:23:58,000 由一些在未来的其他功能,和主要是显然完全不变。 435 00:23:58,000 --> 00:24:00,000 我们需要一种从根本上解决此问题, 436 00:24:00,000 --> 00:24:03,000 今天我们就终于有办法这样做,据此 437 00:24:03,000 --> 00:24:06,000 我们可以引进一些所谓的指针。 438 00:24:06,000 --> 00:24:09,000 事实证明,我们可以解决这个问题 439 00:24:09,000 --> 00:24:12,000 而不是通过在x和y的副本 440 00:24:12,000 --> 00:24:18,000 而是通过在哪,你想,交换功能? 441 00:24:18,000 --> 00:24:20,000 是啊,什么的地址吗? 442 00:24:20,000 --> 00:24:22,000 我们还没有真正谈过地址在很多细节, 443 00:24:22,000 --> 00:24:25,000 但如果这个黑板代表我的电脑的内存 444 00:24:25,000 --> 00:24:28,000 当然,我们可以开始编号,我的内存中的字节 445 00:24:28,000 --> 00:24:31,000 并说,这是字节#1,这是字节#2,#3字节, 446 00:24:31,000 --> 00:24:35,000 字节第4字节#2亿元,如果我有2 GB的RAM, 447 00:24:35,000 --> 00:24:38,000 所以我们当然可以拿出一些任意的编号方案 448 00:24:38,000 --> 00:24:41,000 在我的电脑的内存中的所有单个字节。 449 00:24:41,000 --> 00:24:43,000 >> 什么,如果不是,当我打电话交换 450 00:24:43,000 --> 00:24:47,000 在x和y的副本,而不是通 451 00:24:47,000 --> 00:24:51,000 为什么不要我,而不是通过在这里的x的地址, 452 00:24:51,000 --> 00:24:55,000 地址为y这里,基本上邮政的地址 453 00:24:55,000 --> 00:24:59,000 因为x和y交换,如果他的通知 454 00:24:59,000 --> 00:25:01,000 x和y的存储器中的地址; 455 00:25:01,000 --> 00:25:04,000 然后交换,如果我们把他训练的一点点, 456 00:25:04,000 --> 00:25:07,000 他有可能开车到该地址,可以这么说, 457 00:25:07,000 --> 00:25:11,000 X,和有改变,然后开车到y的地址, 458 00:25:11,000 --> 00:25:16,000 数,即使没有实际得到,自己这些值的副本, 459 00:25:16,000 --> 00:25:19,000 因此,即使我们谈到这个作为主要的记忆体 460 00:25:19,000 --> 00:25:23,000 作为交换的内存,强大的和危险的C 461 00:25:23,000 --> 00:25:28,000 的是,任何函数可以触摸内存在计算机中的任何地方, 462 00:25:28,000 --> 00:25:32,000 这是强大的,你可以做很花哨的东西,计算机程序C. 463 00:25:32,000 --> 00:25:36,000 这是很危险的,因为你也可以很容易搞砸了。 464 00:25:36,000 --> 00:25:39,000 事实上,一个最常见的方式的方案,这些天被利用 465 00:25:39,000 --> 00:25:42,000 仍是一个程序员没有意识到 466 00:25:42,000 --> 00:25:45,000 他或她被允许的数据 467 00:25:45,000 --> 00:25:49,000 要被写入存储器中的一个位置不打算。 468 00:25:49,000 --> 00:25:51,000 >> 例如,他或她声明一个数组大小为10 469 00:25:51,000 --> 00:25:56,000 但后来意外地试图把11个字节到该数组的内存, 470 00:25:56,000 --> 00:25:59,000 你开始接触的内存部分不再有效。 471 00:25:59,000 --> 00:26:02,000 只是为了上下文此,有些人可能知道, 472 00:26:02,000 --> 00:26:06,000 软件经常会提示您输入序列号或注册键, 473 00:26:06,000 --> 00:26:08,000 的Photoshop和Word这样的程序。 474 00:26:08,000 --> 00:26:12,000 存在裂缝,你们有些人知道,网上,您可以运行一个小程序, 475 00:26:12,000 --> 00:26:14,000 瞧,没有更多的请求的序列号。 476 00:26:14,000 --> 00:26:16,000 如何工作? 477 00:26:16,000 --> 00:26:21,000 在许多情况下,这些东西都只是寻求在电脑 478 00:26:21,000 --> 00:26:24,000 在计算机的实际零和一的文本段 479 00:26:24,000 --> 00:26:28,000 其中是,其中被请求的序列号的功能, 480 00:26:28,000 --> 00:26:31,000 您覆盖空间,在程序运行时, 481 00:26:31,000 --> 00:26:33,000 你可以找出其中的关键是实际存储 482 00:26:33,000 --> 00:26:37,000 使用一些所谓的调试器,你可以破解软件的方式。 483 00:26:37,000 --> 00:26:40,000 这是不是说,这是我们的目标,在未来几天, 484 00:26:40,000 --> 00:26:42,000 但它具有非常现实世界的后果。 485 00:26:42,000 --> 00:26:45,000 这发生的涉及盗窃软件, 486 00:26:45,000 --> 00:26:47,000 但也有妥协的整个机器。 487 00:26:47,000 --> 00:26:50,000 >> 事实上,当网站这几天都在利用 488 00:26:50,000 --> 00:26:53,000 和妥协的数据被泄露和被窃取密码 489 00:26:53,000 --> 00:26:58,000 这往往涉及到一个人的记忆管理不善, 490 00:26:58,000 --> 00:27:01,000 或者,在数据库的情况下,未能预见 491 00:27:01,000 --> 00:27:03,000 对抗性的输入,所以更多的是在未来几周内, 492 00:27:03,000 --> 00:27:07,000 但现在只是一个先睹为快的那种伤害,你可以做 493 00:27:07,000 --> 00:27:11,000 不太了解引擎盖下是如何工作的。 494 00:27:11,000 --> 00:27:14,000 让我们去了解,这是为什么打破 495 00:27:14,000 --> 00:27:17,000 一个工具,将成为越来越多的有用 496 00:27:17,000 --> 00:27:19,000 因为我们的课程变得更加复杂。 497 00:27:19,000 --> 00:27:21,000 到目前为止,当你在你的程序中有一个错误 498 00:27:21,000 --> 00:27:23,000 你如何调试了吗? 499 00:27:23,000 --> 00:27:25,000 你有什么技术迄今为止,无论是你的TF教 500 00:27:25,000 --> 00:27:27,000 或只是自学成才的吗? 501 00:27:27,000 --> 00:27:29,000 [学生]的printf。 502 00:27:29,000 --> 00:27:31,000 printf的,因此我们知道printf有可能是你的朋友,如果你想看到的 503 00:27:31,000 --> 00:27:33,000 这是怎么回事,在你的程序 504 00:27:33,000 --> 00:27:36,000 你只是在这里把输出,输出在这里,输出在这里。 505 00:27:36,000 --> 00:27:38,000 然后运行它,你会得到一大堆的东西在屏幕上 506 00:27:38,000 --> 00:27:43,000 ,然后你可以用它来推断出什么是真正在你的程序错误。 507 00:27:43,000 --> 00:27:45,000 >> printf的往往是一个非常强大的东西, 508 00:27:45,000 --> 00:27:47,000 但它是一个非常手动过程。 509 00:27:47,000 --> 00:27:49,000 你必须把这里的printf,是printf这里, 510 00:27:49,000 --> 00:27:51,000 如果你把它里面的一个循环,你可能会得到100行 511 00:27:51,000 --> 00:27:53,000 的输出,你就必须通过筛选。 512 00:27:53,000 --> 00:27:58,000 这不是一个非常用户友好的调试程序或互动机制, 513 00:27:58,000 --> 00:28:00,000 但幸运的是存在替代品。 514 00:28:00,000 --> 00:28:03,000 有一个程序,例如,GDB,GNU调试器, 515 00:28:03,000 --> 00:28:06,000 这是一个有点神秘的,你如何使用它。 516 00:28:06,000 --> 00:28:08,000 这是一个有点复杂,但坦率地说, 517 00:28:08,000 --> 00:28:11,000 这是一个的东西在那里,如果你把在本周和未来 518 00:28:11,000 --> 00:28:14,000 额外的一小时了解类似GDB 519 00:28:14,000 --> 00:28:18,000 从长远来看,它可能会为你节省几十个小时, 520 00:28:18,000 --> 00:28:21,000 所以,让我给你一个传情的这个东西是如何工作的。 521 00:28:21,000 --> 00:28:23,000 >> 我在我的终端窗口。 522 00:28:23,000 --> 00:28:26,000 让我继续前进,编译这个程序,buggy3。 523 00:28:26,000 --> 00:28:28,000 这已经是最新的。 524 00:28:28,000 --> 00:28:31,000 让我运行它,就像我们做了一段时间后,而事实上,它打破了。 525 00:28:31,000 --> 00:28:34,000 但是,这是为什么?也许是我搞砸了交换功能。 526 00:28:34,000 --> 00:28:37,000 也许它的A和B。我不是很感动他们周围是否正确。 527 00:28:37,000 --> 00:28:39,000 让我继续这样做。 528 00:28:39,000 --> 00:28:43,000 而不是仅仅buggy3,而不是让我运行这个程序,GDB, 529 00:28:43,000 --> 00:28:48,000 我要告诉它运行buggy3, 530 00:28:48,000 --> 00:28:52,000 我要包括一个命令行参数,TUI, 531 00:28:52,000 --> 00:28:55,000 我们会把这规格提醒未来的问题。 532 00:28:55,000 --> 00:28:57,000 而现在这个黑和白的接口弹出,再次, 533 00:28:57,000 --> 00:28:59,000 是有点势不可挡,因为这一切 534 00:28:59,000 --> 00:29:02,000 保修信息到这里,但至少有一些熟悉的东西。 535 00:29:02,000 --> 00:29:04,000 在窗口顶部的是我的实际代码, 536 00:29:04,000 --> 00:29:08,000 如果我向上滚动,在这里让我滚动到最顶端的我的文件, 537 00:29:08,000 --> 00:29:11,000 而事实上,在此窗口底部有buggy3.c,并通知 538 00:29:11,000 --> 00:29:13,000 我有这样的GDB提示。 539 00:29:13,000 --> 00:29:16,000 >> 这是我的正常的约翰·哈佛提示不一样的。 540 00:29:16,000 --> 00:29:19,000 这是一个提示,是怎么回事,让我来控制GDB。 541 00:29:19,000 --> 00:29:21,000 GDB调试器。 542 00:29:21,000 --> 00:29:24,000 调试器是一个程序,让你走过 543 00:29:24,000 --> 00:29:27,000 一行行的执行你的程序行, 544 00:29:27,000 --> 00:29:30,000 前进的道路上,做任何你想要的程序, 545 00:29:30,000 --> 00:29:33,000 即使调用函数,或寻找,更重要的是, 546 00:29:33,000 --> 00:29:35,000 在各种变量的值。 547 00:29:35,000 --> 00:29:37,000 让我们继续前进,并做到这一点。 548 00:29:37,000 --> 00:29:40,000 我会继续前进,在运行中输入GDB的提示符下, 549 00:29:40,000 --> 00:29:43,000 所以注意在屏幕的左下方,我输入的运行, 550 00:29:43,000 --> 00:29:45,000 和我已经打输入,和什么做呢? 551 00:29:45,000 --> 00:29:50,000 它的字面运行我的程序,但我并没有真正看到很多在这里 552 00:29:50,000 --> 00:29:55,000 因为我还没有告诉调试器 553 00:29:55,000 --> 00:29:57,000 暂停在一个特定的时刻。 554 00:29:57,000 --> 00:29:59,000 只需键入运行,运行该程序。 555 00:29:59,000 --> 00:30:01,000 我没有看到任何东西。我不能操纵它。 556 00:30:01,000 --> 00:30:03,000 >> 而是让我这样做。 557 00:30:03,000 --> 00:30:08,000 在此GDB提示符下,让我,而不是键入突破,进入。 558 00:30:08,000 --> 00:30:10,000 这不是我的意思是什么类型的。 559 00:30:10,000 --> 00:30:13,000 让我们,而不是主要键入休息。 560 00:30:13,000 --> 00:30:15,000 换句话说,我想设置一个断点, 561 00:30:15,000 --> 00:30:18,000 这是恰当地命名,是因为它会破坏或暂停 562 00:30:18,000 --> 00:30:21,000 执行你的程序在特定的地方。 563 00:30:21,000 --> 00:30:23,000 主要是我的函数的名称。 564 00:30:23,000 --> 00:30:25,000 请注意,GDB是非常聪明的。 565 00:30:25,000 --> 00:30:28,000 想通了,主要发生在大约在第18行开始 566 00:30:28,000 --> 00:30:32,000 的buggy3.c,然后注意到这里在左上角 567 00:30:32,000 --> 00:30:34,000 B +第18行是正确的旁边。 568 00:30:34,000 --> 00:30:38,000 那是在提醒我,我已经在第18行设置一个断点。 569 00:30:38,000 --> 00:30:42,000 这一次,当我键入run,我要运行我的程序 570 00:30:42,000 --> 00:30:45,000 直到它击中断点, 571 00:30:45,000 --> 00:30:48,000 这样的程序将暂停,我在第18行。 572 00:30:48,000 --> 00:30:50,000 在这里,我们去运行。 573 00:30:50,000 --> 00:30:53,000 什么也没有发生,但通知左下角 574 00:30:53,000 --> 00:30:58,000 启动程序,buggy3,断点1在主在buggy3.c第18行。 575 00:30:58,000 --> 00:31:00,000 我现在能做些什么呢? 576 00:31:00,000 --> 00:31:03,000 >> 请注意,我可以开始输入打印类的东西, 577 00:31:03,000 --> 00:31:08,000 不是printf,打印x,而现在很奇怪。 578 00:31:08,000 --> 00:31:11,000 1美元的仅仅是一个好奇心,我们会看到 579 00:31:11,000 --> 00:31:14,000 每次你打印的东西,你会得到一个新的美元价值。 580 00:31:14,000 --> 00:31:18,000 这是如此,你可以参考以前的值,以防万一, 581 00:31:18,000 --> 00:31:21,000 但现在打印告诉我的是,在这个故事中的点x的值 582 00:31:21,000 --> 00:31:26,000 显然是134514032。 583 00:31:26,000 --> 00:31:29,000 什么?在哪里,即使是从何而来呢? 584 00:31:29,000 --> 00:31:31,000 [听不见的学生] 585 00:31:31,000 --> 00:31:34,000 事实上,这就是我们要调用一个垃圾值,我们还没有谈到这一点, 586 00:31:34,000 --> 00:31:37,000 但原因,你初始化变量 587 00:31:37,000 --> 00:31:40,000 显然,让他们有一定的价值,你希望他们有。 588 00:31:40,000 --> 00:31:44,000 但问题是这样,就可以声明变量 589 00:31:44,000 --> 00:31:46,000 像我刚才在我的适马的例子 590 00:31:46,000 --> 00:31:48,000 实际上是给他们一个值。 591 00:31:48,000 --> 00:31:50,000 回想我做了什么,在这里西格玛。 592 00:31:50,000 --> 00:31:52,000 我宣布n,但是什么样的价值,我给它呢? 593 00:31:52,000 --> 00:31:56,000 没有,因为我知道,在接下来的几行 594 00:31:56,000 --> 00:31:59,000 调用getInt会照顾的问题,把里面的值的n。 595 00:31:59,000 --> 00:32:02,000 >> 但在这一点上在第11行的故事 596 00:32:02,000 --> 00:32:05,000 和线12和线13和第14行 597 00:32:05,000 --> 00:32:08,000 在那些几行n的值是什么? 598 00:32:08,000 --> 00:32:10,000 在C语言中,你只是不知道。 599 00:32:10,000 --> 00:32:14,000 这是一些垃圾的价值,有些完全是随机的数字 600 00:32:14,000 --> 00:32:17,000 剩下的基本上是从以前的一些功能 601 00:32:17,000 --> 00:32:21,000 已运行,这样你的程序运行 602 00:32:21,000 --> 00:32:24,000 记得函数获取函数,函数,函数。 603 00:32:24,000 --> 00:32:27,000 所有这些帧被放到内存中,然后这些函数的返回, 604 00:32:27,000 --> 00:32:31,000 就像我建议用橡皮擦最终被重复使用他们的记忆。 605 00:32:31,000 --> 00:32:37,000 好了,它只是恰巧在这个程序,这个变量x 606 00:32:37,000 --> 00:32:41,000 似乎已经包含了一些垃圾的价值,如134514032 607 00:32:41,000 --> 00:32:44,000 从以前的一些功能,而不是我写的。 608 00:32:44,000 --> 00:32:47,000 这可能是有效的操作系统的东西来, 609 00:32:47,000 --> 00:32:49,000 引擎盖下的一些功能。 610 00:32:49,000 --> 00:32:52,000 >> 好了,这很好,但现在,让我们进入到下一行。 611 00:32:52,000 --> 00:32:55,000 如果我在我的GDB提示符中键入“下一步”,我按下回车键, 612 00:32:55,000 --> 00:32:58,000 注意突出显示向下移动到第19行, 613 00:32:58,000 --> 00:33:01,000 但合乎逻辑的言下之意是,第18行 614 00:33:01,000 --> 00:33:06,000 现在已经执行完毕,所以如果我再输入“打印X” 615 00:33:06,000 --> 00:33:10,000 我现在应该看到,事实上,我做的。 616 00:33:10,000 --> 00:33:14,000 同样,美元的东西是一个GDB提醒你的方式 617 00:33:14,000 --> 00:33:17,000 打印的历史是什么,你已经完成了。 618 00:33:17,000 --> 00:33:21,000 现在让我和打印输出Y,而事实上,y是一些疯狂的价值,以及, 619 00:33:21,000 --> 00:33:24,000 但没有什么大不了的,因为在第19行中,我们将其分配给 620 00:33:24,000 --> 00:33:27,000 值2,所以让我再次键入“下一步”。 621 00:33:27,000 --> 00:33:29,000 现在,我们正上的printf线。 622 00:33:29,000 --> 00:33:31,000 让我做打印x。 623 00:33:31,000 --> 00:33:34,000 让我做印刷品Y。坦率地说,我有点累了印刷本。 624 00:33:34,000 --> 00:33:38,000 让我,而不是键入“显示x”和“显示Y” 625 00:33:38,000 --> 00:33:41,000 现在每次我在未来键入命令 626 00:33:41,000 --> 00:33:45,000 我会想起什么x和y,x和y,x和y是什么。 627 00:33:45,000 --> 00:33:48,000 >> 我还可以,顺便说一句,在“信息当地人类型。” 628 00:33:48,000 --> 00:33:50,000 信息是一种特殊的命令。 629 00:33:50,000 --> 00:33:52,000 当地人意味着它让我看到局部变量。 630 00:33:52,000 --> 00:33:55,000 以防万一我忘了这是一个疯狂的,复杂的功能 631 00:33:55,000 --> 00:33:57,000 我或其他人编写的信息当地人会告诉你 632 00:33:57,000 --> 00:34:00,000 什么是这里面的本地函数的所有局部变量 633 00:34:00,000 --> 00:34:03,000 如果你想闲逛,你可能会关心。 634 00:34:03,000 --> 00:34:07,000 现在,printf是执行,所以让我继续前进,只需键入“未来”。 635 00:34:07,000 --> 00:34:10,000 因为我们是在这样的环境中,我们实际上没有看到它 636 00:34:10,000 --> 00:34:14,000 执行下来,但要注意它变得有点错位。 637 00:34:14,000 --> 00:34:17,000 但是请注意,它的首要屏幕上出现, 638 00:34:17,000 --> 00:34:21,000 所以它不是一个完美的方案,但是这没关系,因为我可以随时闲逛 639 00:34:21,000 --> 00:34:23,000 如果我想使用打印。 640 00:34:23,000 --> 00:34:26,000 >> 让我再输入下,现在这里是最有趣的部分。 641 00:34:26,000 --> 00:34:29,000 在这一点上在故事y是2,x是1, 642 00:34:29,000 --> 00:34:32,000 的建议,并再次, 643 00:34:32,000 --> 00:34:35,000 这是自动显示的原因是因为我使用的命令 644 00:34:35,000 --> 00:34:40,000 显示x和显示Y,I型下的那一刻 645 00:34:40,000 --> 00:34:43,000 x和y在理论上应该成为交换。 646 00:34:43,000 --> 00:34:45,000 现在,我们已经知道这是不会的情况下, 647 00:34:45,000 --> 00:34:49,000 但我们会看到一个时刻,我们如何能更深入地找出原因,这是真的。 648 00:34:49,000 --> 00:34:54,000 下一步,不幸的是,Y仍然是2,x是1,我可以证实尽可能多的。 649 00:34:54,000 --> 00:34:56,000 打印x,印刷品Y。 650 00:34:56,000 --> 00:34:59,000 事实上,没有交换实际上已经发生了,所以让我们开始这个问题。 651 00:34:59,000 --> 00:35:01,000 显然,交换被打破了。 652 00:35:01,000 --> 00:35:04,000 的,而不是让我们再次键入“运行”。 653 00:35:04,000 --> 00:35:07,000 让我说是的,我要重新启动它从一开始,进入。 654 00:35:07,000 --> 00:35:09,000 >> 现在,我回来了在第18行。 655 00:35:09,000 --> 00:35:11,000 现在,注意到x和y的值再次是垃圾。 656 00:35:11,000 --> 00:35:15,000 下一步,下一步,下一步,下一步。 657 00:35:15,000 --> 00:35:17,000 如果我感到无聊,我也只需要输入n转到下一个。 658 00:35:17,000 --> 00:35:21,000 您可以缩写,以最短的字符序列。 659 00:35:21,000 --> 00:35:23,000 现在被破坏掉。 660 00:35:23,000 --> 00:35:25,000 我们来看看,而不是输入下, 661 00:35:25,000 --> 00:35:30,000 现在,我要输入步骤,加强,使我里面的这个函数 662 00:35:30,000 --> 00:35:33,000 这样我就可以穿过它,所以我打步骤,然后输入。 663 00:35:33,000 --> 00:35:37,000 注意突出跳下在我的程序中第36行。 664 00:35:37,000 --> 00:35:39,000 现在的局部变量是什么? 665 00:35:39,000 --> 00:35:41,000 信息本地人。 666 00:35:41,000 --> 00:35:43,000 没有,只是还没有,因为我们还没有得到该行, 667 00:35:43,000 --> 00:35:47,000 所以让我们继续前进,并说:“下一个。” 668 00:35:47,000 --> 00:35:50,000 现在,我们似乎,有tmp目录,打印TMP。 669 00:35:50,000 --> 00:35:52,000 垃圾的价值,对不对?我是这么认为的。 670 00:35:52,000 --> 00:35:55,000 如何打印,打印B,1和2吗? 671 00:35:55,000 --> 00:35:58,000 在某一时刻,只要我再输入下 672 00:35:58,000 --> 00:36:02,000 tmp是将要采取的值为1,希望, 673 00:36:02,000 --> 00:36:05,000 因为tmp目录将被分配的值。 674 00:36:05,000 --> 00:36:08,000 >> 现在,让我们做打印,页B, 675 00:36:08,000 --> 00:36:11,000 但现在打印tmp,以及它的确是1。 676 00:36:11,000 --> 00:36:14,000 让我做下一个。让我做下一个。 677 00:36:14,000 --> 00:36:16,000 我已经完成了交换功能。 678 00:36:16,000 --> 00:36:19,000 我还在里面,它在第40行,所以让我打印, 679 00:36:19,000 --> 00:36:22,000 打印B,我不关心tmp是什么。 680 00:36:22,000 --> 00:36:27,000 它看起来像掉期是正确的,当谈到交换a和b。 681 00:36:27,000 --> 00:36:31,000 但是,如果我现在键入下,我跳回到第25行, 682 00:36:31,000 --> 00:36:34,000 当然,如果我在x和印刷品Y型 683 00:36:34,000 --> 00:36:38,000 他们仍然是不变的,所以我们没有固定的问题。 684 00:36:38,000 --> 00:36:41,000 但诊断也许这GDB程序 685 00:36:41,000 --> 00:36:44,000 至少我们已经变得更近了一步的了解 686 00:36:44,000 --> 00:36:47,000 这是怎么回事错误,不乱抛垃圾,我们把一个printf的代码, 687 00:36:47,000 --> 00:36:50,000 输出,输出,然后运行一遍又一遍 688 00:36:50,000 --> 00:36:52,000 试图找出什么地方出了错。 689 00:36:52,000 --> 00:36:55,000 >> 我要继续前进并退出这完全退出。 690 00:36:55,000 --> 00:36:57,000 这是怎么回事,然后说,“要离开吗?”是。 691 00:36:57,000 --> 00:37:00,000 现在,我回到了我的正常提示,我使用GDB。 692 00:37:00,000 --> 00:37:03,000 顺便说一句,你不需要使用这个TUI标志。 693 00:37:03,000 --> 00:37:07,000 事实上,如果你忽略它,你基本上是在屏幕的下半部分。 694 00:37:07,000 --> 00:37:11,000 如果我然后键入突破主,然后运行 695 00:37:11,000 --> 00:37:15,000 我仍然可以运行我的程序,但它会做的是文本上 696 00:37:15,000 --> 00:37:18,000 你给我的当前行一次一个。 697 00:37:18,000 --> 00:37:21,000 TUI,文本用户界面, 698 00:37:21,000 --> 00:37:25,000 只能说明你的程序一次,这可能是有点概念上更容易。 699 00:37:25,000 --> 00:37:27,000 不过说实在的,我只是做下一个,下一个,下一个, 700 00:37:27,000 --> 00:37:30,000 我看到一个在一个时间线,如果我真的想看看会发生什么 701 00:37:30,000 --> 00:37:35,000 我可以输入列表,看到一大堆的相邻线路。 702 00:37:35,000 --> 00:37:39,000 >> 有一个视频,我们问过,你看问题集3 703 00:37:39,000 --> 00:37:43,000 内特覆盖一些GDB的复杂性, 704 00:37:43,000 --> 00:37:46,000 这是一个人的东西,说实话,你的一些不平凡的百分比 705 00:37:46,000 --> 00:37:49,000 再也不会去碰GDB,这将是一件坏事 706 00:37:49,000 --> 00:37:53,000 因为从字面上你会花更多的时间,这学期 707 00:37:53,000 --> 00:37:56,000 追错误,那么你如果你把在这半小时/小时 708 00:37:56,000 --> 00:38:00,000 本周和下周的学习,获得舒适的使用GDB。 709 00:38:00,000 --> 00:38:02,000 printf的是你的朋友。 710 00:38:02,000 --> 00:38:05,000 GDB现在应该是你的朋友。 711 00:38:05,000 --> 00:38:08,000 >> 对GDB的任何问题? 712 00:38:08,000 --> 00:38:12,000 这里有一个快速的一些最强大,最有用的命令列表。 713 00:38:12,000 --> 00:38:15,000 是啊。>>你可以打印一个字符串? 714 00:38:15,000 --> 00:38:17,000 你可以打印一个字符串?当然可以。 715 00:38:17,000 --> 00:38:19,000 它不具有只是整数。 716 00:38:19,000 --> 00:38:22,000 如果一个变量s是一个字符串类型的打印小号。 717 00:38:22,000 --> 00:38:24,000 它会告诉你是什么字符串变量。 718 00:38:24,000 --> 00:38:26,000 [听不见的学生] 719 00:38:26,000 --> 00:38:28,000 它会给你的地址和字符串本身。 720 00:38:28,000 --> 00:38:32,000 它会告诉你。 721 00:38:32,000 --> 00:38:34,000 最后一件事,只是因为这是好知道的太多。 722 00:38:34,000 --> 00:38:37,000 回溯和框架,让我潜入这是最后一次, 723 00:38:37,000 --> 00:38:39,000 GDB完全相同的程序。 724 00:38:39,000 --> 00:38:44,000 让我继续运行的文本用户界面版本, 725 00:38:44,000 --> 00:38:46,000 打破为主。 726 00:38:46,000 --> 00:38:49,000 让我继续前进,再次运行。我在这里。 727 00:38:49,000 --> 00:38:55,000 现在让我去下一个,下一个,下一个,下一个,下一个步骤中,输入。 728 00:38:55,000 --> 00:39:00,000 >> 现在假设我现在在交换故意的,但我很喜欢“妈的,什么是x的值吗?” 729 00:39:00,000 --> 00:39:02,000 我不能做X了。 730 00:39:02,000 --> 00:39:05,000 我不能做y,因为他们不在范围内。 731 00:39:05,000 --> 00:39:07,000 他们不是在上下文中,但没有问题。 732 00:39:07,000 --> 00:39:09,000 我可以输入回溯。 733 00:39:09,000 --> 00:39:13,000 这说明我已经执行了这个时间点的所有的功能。 734 00:39:13,000 --> 00:39:16,000 请注意,一个在底部,主,线与主 735 00:39:16,000 --> 00:39:18,000 这里是我们的图片的底部。 736 00:39:18,000 --> 00:39:22,000 事实上,交换与交换在它上面的内存是它上面的线, 737 00:39:22,000 --> 00:39:26,000 如果我想暂时回到主,我可以说,“框架”。 738 00:39:26,000 --> 00:39:30,000 几号?主要是帧#1。 739 00:39:30,000 --> 00:39:32,000 我要继续前进,并说:“第1帧”。 740 00:39:32,000 --> 00:39:36,000 >> 现在我的主,我可以打印x,我可以印刷品Y, 741 00:39:36,000 --> 00:39:40,000 但我无法打印或b。 742 00:39:40,000 --> 00:39:43,000 但我可以的,如果我说,“好吧,请等待一分钟。交换在哪里?” 743 00:39:43,000 --> 00:39:46,000 让我继续说:“第0帧。” 744 00:39:46,000 --> 00:39:48,000 现在我回来了,我想是的,和顺便说一句, 745 00:39:48,000 --> 00:39:52,000 也有其他命令一样,如果你真的感到无聊打字下一步,下一步,下一步,下一步, 746 00:39:52,000 --> 00:39:56,000 一般情况下,你可以说“下一个10的事情,”和,将逐步在未来10行。 747 00:39:56,000 --> 00:39:59,000 你也可以写“继续”时,你真的厌倦了单步运行它。 748 00:39:59,000 --> 00:40:05,000 继续运行你的程序没有中断,直到碰到另一个断点, 749 00:40:05,000 --> 00:40:07,000 无论是在一个循环或降低在你的程序中。 750 00:40:07,000 --> 00:40:11,000 >> 在这种情况下,我们继续到最后,程序正常退出。 751 00:40:11,000 --> 00:40:13,000 这是一种奇特的方式,劣质的过程。 752 00:40:13,000 --> 00:40:16,000 只要你的程序正常退出。 753 00:40:16,000 --> 00:40:24,000 更多的视频和调试会话来。 754 00:40:24,000 --> 00:40:26,000 这是一个很大。 755 00:40:26,000 --> 00:40:35,000 让我们把我们的5分钟的休息时间,在这里,我们将返回结构和文件。 756 00:40:35,000 --> 00:40:38,000 >> 如果你已经一头扎进这个星期的pset中 757 00:40:38,000 --> 00:40:41,000 你就会知道,我们使用的分布代码, 758 00:40:41,000 --> 00:40:45,000 为出发点,一些新的技术,我们为您提供的源代码。 759 00:40:45,000 --> 00:40:50,000 特别是,我们推出了一个新的关键字称为struct结构, 760 00:40:50,000 --> 00:40:53,000 这样我们就可以创建自定义的各种变量。 761 00:40:53,000 --> 00:40:57,000 我们还介绍了文件I / O,文件输入和输出的概念, 762 00:40:57,000 --> 00:41:00,000 这是使我们能够保存状态 763 00:41:00,000 --> 00:41:03,000 争夺董事会光盘上的文件 764 00:41:03,000 --> 00:41:06,000 ,教学研究员,我可以理解 765 00:41:06,000 --> 00:41:09,000 你的程序内部发生了什么事情,而无需手动播放 766 00:41:09,000 --> 00:41:11,000 几十场比赛的争夺。 767 00:41:11,000 --> 00:41:13,000 我们可以做更多automatedly的。 768 00:41:13,000 --> 00:41:18,000 >> 这个想法的结构解决了一个相当引人注目的问题。 769 00:41:18,000 --> 00:41:21,000 假设我们要实现的一些程序 770 00:41:21,000 --> 00:41:25,000 ,不知怎的,对学生的信息跟踪, 771 00:41:25,000 --> 00:41:28,000 和学生可能具有,例如,一个ID,一个名称 772 00:41:28,000 --> 00:41:31,000 和一所房子在哈佛这样的地方,所以这3个信息 773 00:41:31,000 --> 00:41:34,000 我们要保持周围,所以让我继续前进,开始在这里写了一个小程序, 774 00:41:34,000 --> 00:41:38,000 包括stdio.h中。 775 00:41:38,000 --> 00:41:42,000 让我包括cs50.h.的 776 00:41:42,000 --> 00:41:44,000 然后开始我的主要功能。 777 00:41:44,000 --> 00:41:46,000 我不会打扰任何命令行参数, 778 00:41:46,000 --> 00:41:49,000 在这里,我想有一个学生,所以我说 779 00:41:49,000 --> 00:41:54,000 一个学生都有一个名字,所以我会说“字符串名称。” 780 00:41:54,000 --> 00:41:59,000 然后我说一个学生,也有一个ID,所以int ID, 781 00:41:59,000 --> 00:42:03,000 学生有一所房子,所以我也说“字符串房子。” 782 00:42:03,000 --> 00:42:06,000 然后,我会为了这些更干净一点是这样的。 783 00:42:06,000 --> 00:42:11,000 好吧,现在我有3个变量代表一个学生,这样的学生。“ 784 00:42:11,000 --> 00:42:15,000 >> 现在我要来填充这些值,所以让我继续前进,这样说 785 00:42:15,000 --> 00:42:18,000 “ID = 123”。 786 00:42:18,000 --> 00:42:21,000 名称是会得到大卫。 787 00:42:21,000 --> 00:42:24,000 比方说,房子是会得到奥美, 788 00:42:24,000 --> 00:42:31,000 ,然后我要做的事情,随意如printf(“%s, 789 00:42:31,000 --> 00:42:37,000 的ID是%d,住在%s。 790 00:42:37,000 --> 00:42:41,000 现在,我要在这里堵塞,一前一后? 791 00:42:41,000 --> 00:42:47,000 姓名,身份证,房屋返回0。 792 00:42:47,000 --> 00:42:50,000 好吧,除非在此我搞砸了 793 00:42:50,000 --> 00:42:54,000 我认为我们有一个不错的方案,存储一个学生。 794 00:42:54,000 --> 00:42:57,000 当然,这不是那么有趣。如果我想有2名学生? 795 00:42:57,000 --> 00:42:59,000 这没什么大不了的。我可以支持2人。 796 00:42:59,000 --> 00:43:03,000 让我去,并强调这一点,去这里, 797 00:43:03,000 --> 00:43:09,000 我可以说“ID = 456”像罗布人住在华盛顿州Kirkland的人。 798 00:43:09,000 --> 00:43:12,000 >> 好了,等待,但我不能把这些同样的事情, 799 00:43:12,000 --> 00:43:15,000 它看起来像我要复制, 800 00:43:15,000 --> 00:43:19,000 所以让我说,这将是大卫的变量, 801 00:43:19,000 --> 00:43:23,000 并让我得到一些副本,这些罗布。 802 00:43:23,000 --> 00:43:27,000 我们会打电话给这些Rob的,但,这是行不通的,现在 803 00:43:27,000 --> 00:43:33,000 因为我已经等待,让我们改变了我的ID1,name1和house1。 804 00:43:33,000 --> 00:43:35,000 罗布将是2,2。 805 00:43:35,000 --> 00:43:42,000 我已经改变了这里,这里,这里,这里,这里,这里。 806 00:43:42,000 --> 00:43:45,000 等待,汤米?让我们再这样做。 807 00:43:45,000 --> 00:43:49,000 显然,如果你仍然认为这是一个很好的方式,这样做,不是的话, 808 00:43:49,000 --> 00:43:52,000 所以复制/粘贴坏。 809 00:43:52,000 --> 00:43:55,000 但是,我们解决了这一个星期前。 810 00:43:55,000 --> 00:43:59,000 >> 我们的解决方案时,我们希望有相同的数据类型的多个实例吗? 811 00:43:59,000 --> 00:44:01,000 [学生]一个数组。 812 00:44:01,000 --> 00:44:03,000 一个数组,所以让我尝试清理它。 813 00:44:03,000 --> 00:44:07,000 让我为自己出一些空间的顶部,而不是让我在这里做。 814 00:44:07,000 --> 00:44:12,000 我们会打电话给这些人,而不是我会说“诠释IDS,” 815 00:44:12,000 --> 00:44:14,000 我要支持我们现在。 816 00:44:14,000 --> 00:44:18,000 我会说“字符串名称”,我会支持我们, 817 00:44:18,000 --> 00:44:22,000 然后,我会说“字符串的房子,”我要支持我们。 818 00:44:22,000 --> 00:44:26,000 现在,在这里,而不是大卫得到他自己的局部变量 819 00:44:26,000 --> 00:44:28,000 我们可以摆脱这些。 820 00:44:28,000 --> 00:44:30,000 这感觉很好,我们正在清理这个。 821 00:44:30,000 --> 00:44:35,000 然后,我可以说大卫将是[0]和名称[0] 822 00:44:35,000 --> 00:44:38,000 房子[0]。 823 00:44:38,000 --> 00:44:41,000 然后抢,我们同样可以省了。 824 00:44:41,000 --> 00:44:46,000 让我们把这个在这里,所以他是怎么回事,随意入侵检测系统[1]。 825 00:44:46,000 --> 00:44:50,000 他的名字[1] 826 00:44:50,000 --> 00:44:53,000 然后最后,房屋[1]。 827 00:44:53,000 --> 00:44:57,000 >> 还是有点繁琐,现在我已经明白这一点, 828 00:44:57,000 --> 00:45:03,000 因此,让我们说:“名[0],ID [0],房屋[0] 829 00:45:03,000 --> 00:45:06,000 的复数此。 830 00:45:06,000 --> 00:45:09,000 入侵检测系统,入侵检测系统,入侵检测系统。 831 00:45:09,000 --> 00:45:12,000 再次,我这样做,如此反复,我已经诉诸再次复制/粘贴, 832 00:45:12,000 --> 00:45:14,000 所以赔率是有另一种解决方案。 833 00:45:14,000 --> 00:45:18,000 我也许可以清理,进一步加快循环或类似的东西, 834 00:45:18,000 --> 00:45:21,000 总之,这是好一点,但仍然感觉像 835 00:45:21,000 --> 00:45:24,000 我诉诸复制/粘贴,但即使这样,我要求, 836 00:45:24,000 --> 00:45:27,000 是不是真的从根本上正确的解决方案,因为 837 00:45:27,000 --> 00:45:29,000 如果某个时候,我们决定你知道吗? 838 00:45:29,000 --> 00:45:32,000 我们真的应该存储电子邮件地址为大卫和Rob 839 00:45:32,000 --> 00:45:34,000 每个人都在这个程序。 840 00:45:34,000 --> 00:45:36,000 我们也应当存储的电话号码。 841 00:45:36,000 --> 00:45:39,000 我们也应该储存紧急联络电话号码。 842 00:45:39,000 --> 00:45:41,000 我们有所有这些作品,我们要存储的数据, 843 00:45:41,000 --> 00:45:43,000 那么你如何去这样做呢? 844 00:45:43,000 --> 00:45:46,000 >> 声明另一个阵列的顶部,然后手动添加 845 00:45:46,000 --> 00:45:49,000 [0],[1]的电子邮件地址的电子邮件地址 846 00:45:49,000 --> 00:45:51,000 大卫和Rob等等。 847 00:45:51,000 --> 00:45:56,000 但真的只是一个假设这样的设计 848 00:45:56,000 --> 00:45:59,000 我使用的是荣誉系统知道 849 00:45:59,000 --> 00:46:03,000 [i]的每个的多个阵列 850 00:46:03,000 --> 00:46:06,000 恰好指的是同一个人, 851 00:46:06,000 --> 00:46:10,000 [0] IDS中的编号为123, 852 00:46:10,000 --> 00:46:13,000 我要去承担,名字[0] 853 00:46:13,000 --> 00:46:16,000 是同一个人的名字和房子[0] 854 00:46:16,000 --> 00:46:21,000 是同一个人的房子等等,我创造的所有的不同的阵列。 855 00:46:21,000 --> 00:46:24,000 但是请注意,有没有根本的联系 856 00:46:24,000 --> 00:46:27,000 除这3个信息,id,name和房子, 857 00:46:27,000 --> 00:46:32,000 即使我们正在努力模型,这个程序是实体,而不是数组。 858 00:46:32,000 --> 00:46:35,000 数组是这一纲领性的方式这样做。 859 00:46:35,000 --> 00:46:38,000 我们真正想要的模型在我们的节目是一个人 860 00:46:38,000 --> 00:46:41,000 像大卫一样,像Rob内,其中一个人 861 00:46:41,000 --> 00:46:46,000 或封装的名称和ID和一所房子。 862 00:46:46,000 --> 00:46:49,000 >> 我们可以以某种方式表达这种思想的封装 863 00:46:49,000 --> 00:46:52,000 由此一个人有一个ID,一个名称和一个房子 864 00:46:52,000 --> 00:46:55,000 而不是这个黑客真的,我们只是 865 00:46:55,000 --> 00:46:58,000 相信,支架的东西 866 00:46:58,000 --> 00:47:02,000 指的是同一人在这些不同的阵列的实体? 867 00:47:02,000 --> 00:47:04,000 事实上,我们可以做到这一点。 868 00:47:04,000 --> 00:47:08,000 让我去上面的主,现在,让我创建自己的数据类型 869 00:47:08,000 --> 00:47:10,000 确实是第一次。 870 00:47:10,000 --> 00:47:14,000 我们使用这种技术的争夺, 871 00:47:14,000 --> 00:47:17,000 但在这里,我要继续前进,并创建一个数据类型, 872 00:47:17,000 --> 00:47:19,000 你知道吗,我现在就打电话给学生或个人, 873 00:47:19,000 --> 00:47:23,000 我要使用typedef定义一个类型。 874 00:47:23,000 --> 00:47:25,000 我会说,这是一个结构, 875 00:47:25,000 --> 00:47:29,000 那么这个结构类型的学生,我们会说, 876 00:47:29,000 --> 00:47:31,000 即使这是一个对我来说有点过时了。 877 00:47:31,000 --> 00:47:33,000 我们会说:“int的ID。” 878 00:47:33,000 --> 00:47:35,000 我们会说:“字符串名称。” 879 00:47:35,000 --> 00:47:37,000 然后,我们会说:“的字符串房子,” 880 00:47:37,000 --> 00:47:40,000 所以现在年底的这几行代码 881 00:47:40,000 --> 00:47:45,000 我刚才教铛存在 882 00:47:45,000 --> 00:47:49,000 除了int类型的数据类型,除了字符串,除了增加一倍,除了花车。 883 00:47:49,000 --> 00:47:54,000 >> 11在时间线的这一刻,现在有一个新的数据类型,称为学生, 884 00:47:54,000 --> 00:47:58,000 现在我学生可以声明一个变量,任何地方,我想, 885 00:47:58,000 --> 00:48:01,000 所以让我向下滚动这里的人。 886 00:48:01,000 --> 00:48:05,000 现在我可以摆脱这种,我可以回去大卫在这里, 887 00:48:05,000 --> 00:48:10,000 和大卫,其实我可以说,大卫, 888 00:48:10,000 --> 00:48:13,000 我们可以从字面上命名变量照顾自己, 889 00:48:13,000 --> 00:48:16,000 将是类型的学生。 890 00:48:16,000 --> 00:48:18,000 这可能看起来有点怪,但是这还不是全部,不同的 891 00:48:18,000 --> 00:48:22,000 作为一个int或一个字符串或浮点数申报的东西。 892 00:48:22,000 --> 00:48:24,000 碰巧的是被称为学生的现在, 893 00:48:24,000 --> 00:48:28,000 如果我想这种结构把里面的东西 894 00:48:28,000 --> 00:48:31,000 我现在要使用新的语法,但它是非常简单的, 895 00:48:31,000 --> 00:48:39,000 david.id = 123,david.name =“大卫”在资本ð, 896 00:48:39,000 --> 00:48:42,000 david.house =“奥美” 897 00:48:42,000 --> 00:48:46,000 现在我可以摆脱这东西在这里。 898 00:48:46,000 --> 00:48:51,000 请注意,我们现在已经重新设计我们的计划确实是一个更好的方法 899 00:48:51,000 --> 00:48:54,000 现在,我们的节目反映了真实的世界。 900 00:48:54,000 --> 00:48:57,000 >> 有一个现实世界的概念,一个人或一个学生。 901 00:48:57,000 --> 00:49:02,000 在这里,我们有一个人或更具体的学生的C版本。 902 00:49:02,000 --> 00:49:05,000 里面的那个人是这些相关的特性, 903 00:49:05,000 --> 00:49:10,000 ID,名称和房子,所以罗布基本上变成同样的事情,在这里, 904 00:49:10,000 --> 00:49:14,000 让学生抢,现在rob.id的= 456, 905 00:49:14,000 --> 00:49:17,000 rob.name =“抢”。 906 00:49:17,000 --> 00:49:20,000 事实上,该变量被称为罗布是一种毫无意义的。 907 00:49:20,000 --> 00:49:22,000 我们可以把它叫做x或y或z。 908 00:49:22,000 --> 00:49:25,000 我们只是把它命名为抢在语义上是一致的, 909 00:49:25,000 --> 00:49:28,000 但真正的名字是里面的那场, 910 00:49:28,000 --> 00:49:30,000 所以现在我有这个。 911 00:49:30,000 --> 00:49:33,000 这也是不觉得自己是最优秀的设计,我已经硬编码的大卫。 912 00:49:33,000 --> 00:49:35,000 我硬编码的罗布。 913 00:49:35,000 --> 00:49:39,000 我还是要采取一些复制和粘贴的时候,我想新的变量。 914 00:49:39,000 --> 00:49:43,000 此外,我显然给每个变量的名称, 915 00:49:43,000 --> 00:49:46,000 即使我宁愿描述这些变量 916 00:49:46,000 --> 00:49:48,000  更一般的学生。 917 00:49:48,000 --> 00:49:52,000 >> 现在,我们可以合并的想法,一直致力于为我们的 918 00:49:52,000 --> 00:49:56,000 ,而是说:“你知道吗,给我一个变量所谓的学生, 919 00:49:56,000 --> 00:50:01,000 ,让我们有它的大小为3,“所以现在我可以进一步细化此, 920 00:50:01,000 --> 00:50:04,000 摆脱手动声明的大卫, 921 00:50:04,000 --> 00:50:08,000 相反,我可以说学生一样的东西[0]在这里。 922 00:50:08,000 --> 00:50:11,000 然后,我可以说,学生[0]在这里, 923 00:50:11,000 --> 00:50:14,000 学生[0]在这里,等等,我可以去转转 924 00:50:14,000 --> 00:50:16,000 和清理罗布。 925 00:50:16,000 --> 00:50:19,000 我也可以去,现在可能增加循环 926 00:50:19,000 --> 00:50:23,000 使用GetString和调用getInt从用户获取这些值。 927 00:50:23,000 --> 00:50:27,000 我可以加上一个常数,因为这是不好的做法 928 00:50:27,000 --> 00:50:29,000 硬编码的,有些像在这里任意数量 929 00:50:29,000 --> 00:50:33,000 ,然后只需记住,你应该不超过3名学生在。 930 00:50:33,000 --> 00:50:36,000 它可能是更好的在我的文件的顶部使用#define 931 00:50:36,000 --> 00:50:40,000 因素说了出来,的确,让我去和推广。 932 00:50:40,000 --> 00:50:43,000 >> 让我打开了一个例子,在今天的 933 00:50:43,000 --> 00:50:46,000 例子提前structs1。 934 00:50:46,000 --> 00:50:49,000 这是一个比较完整的程序,使用#定义在这里 935 00:50:49,000 --> 00:50:51,000 并说,我们要默认情况下,有3名学生。 936 00:50:51,000 --> 00:50:54,000 在这里,我声明一个类学生的价值, 937 00:50:54,000 --> 00:50:57,000 所以教室里的学生,现在我使用的是循环 938 00:50:57,000 --> 00:51:00,000 只是为了使代码更优雅的一点,填充类 939 00:51:00,000 --> 00:51:05,000 与用户的输入,所以循环从i = 0上的学生,它是3。 940 00:51:05,000 --> 00:51:07,000 然后,我提示用户在这个版本中 941 00:51:07,000 --> 00:51:10,000  什么是学生的ID,我得到它与调用getInt。 942 00:51:10,000 --> 00:51:13,000 什么是学生的名字,然后我得到它的GetString。 943 00:51:13,000 --> 00:51:15,000 学生的家是什么?我得到它的GetString。 944 00:51:15,000 --> 00:51:19,000 然后在底部在这里,我决定改变 945 00:51:19,000 --> 00:51:22,000 我如何打印这些和实际使用的循环, 946 00:51:22,000 --> 00:51:24,000 我是谁打印? 947 00:51:24,000 --> 00:51:27,000 根据我的评论我打印Mather中的任何人, 948 00:51:27,000 --> 00:51:30,000 这就是它所以罗布和Tommy等等,其实汤米的Mather中。 949 00:51:30,000 --> 00:51:34,000 汤米和大卫将被打印在这种情况下,这是怎么工作的? 950 00:51:34,000 --> 00:51:40,000 我们还没有看到这个功能,但猜测这是什么做的。 951 00:51:40,000 --> 00:51:42,000 比较字符串。 952 00:51:42,000 --> 00:51:45,000 >> 如何比较字符串,因为事实证明,这是一个有点非明显 953 00:51:45,000 --> 00:51:49,000 如果返回0,表示的字符串是相等的。 954 00:51:49,000 --> 00:51:53,000 如果返回-1,这意味着人来之前,其他的字母顺序, 955 00:51:53,000 --> 00:51:57,000 如果返回+1,这意味着其他的字来按字母顺序 956 00:51:57,000 --> 00:52:00,000 前,你可以看看网上的手册页 957 00:52:00,000 --> 00:52:04,000 它说,看究竟哪一种方式是,但是这一切现在正在做的是 958 00:52:04,000 --> 00:52:09,000 如果[i]的房子是等于“奥美” 959 00:52:09,000 --> 00:52:13,000 然后继续前进,打印出来,并在奥美也是如此。 960 00:52:13,000 --> 00:52:16,000 但在这里我们还没有看到过的东西,我们会回到这个。 961 00:52:16,000 --> 00:52:21,000 我不记得曾经在我的程序中做到这一点。 962 00:52:21,000 --> 00:52:24,000 免费显然是指内存,释放内存, 963 00:52:24,000 --> 00:52:31,000 但什么记忆,我明显地释放在这个循环的底部,这个程序吗? 964 00:52:31,000 --> 00:52:34,000 它看起来像我释放一个人的名字 965 00:52:34,000 --> 00:52:37,000 和一个人的房子,但为什么会这样? 966 00:52:37,000 --> 00:52:41,000 >> 原来,这几个星期,你已经使用GetString 967 00:52:41,000 --> 00:52:45,000 我们已经被引入到你的程序中的每一个错误。 968 00:52:45,000 --> 00:52:51,000 GetString的设计分配内存,因此它可以返回一个字符串, 969 00:52:51,000 --> 00:52:55,000 像大卫一样,罗布,和你就可以做任何你想要的 970 00:52:55,000 --> 00:52:59,000 以该字符串在你的程序中,因为我们已经为您保留内存。 971 00:52:59,000 --> 00:53:02,000 问题是每到这个时候,你需要调用getString 972 00:53:02,000 --> 00:53:05,000 GetString的作者,​​我们已经要求操作系统 973 00:53:05,000 --> 00:53:07,000 给我们一个位RAM的字符串。 974 00:53:07,000 --> 00:53:09,000 给我们一个位的RAM,这一个字符串。 975 00:53:09,000 --> 00:53:11,000 给我们一些更多的RAM,这一个字符串。 976 00:53:11,000 --> 00:53:13,000 你,程序员,从来没有做什么 977 00:53:13,000 --> 00:53:15,000 给我们,恢复记忆, 978 00:53:15,000 --> 00:53:17,000 所以这几个星期,你写的所有程序 979 00:53:17,000 --> 00:53:20,000 有什么所谓的内存的飞跃,让他们继续使用 980 00:53:20,000 --> 00:53:24,000 越来越多的内存每次调用GetString,这很好。 981 00:53:24,000 --> 00:53:27,000 我们刻意做的第一周,因为它是不是很有趣 982 00:53:27,000 --> 00:53:29,000 有担心的字符串是来自哪里。 983 00:53:29,000 --> 00:53:34,000 所有你想要的是这个词抢回来当用户键入它。 984 00:53:34,000 --> 00:53:38,000 >> 但是向前发展,我们现在必须开始对这个变得越来越复杂。 985 00:53:38,000 --> 00:53:42,000 任何时候,我们分配内存,我们最终把它。 986 00:53:42,000 --> 00:53:45,000 否则,在现实世界中,在您的Mac或PC,你可能偶尔有经验丰富的 987 00:53:45,000 --> 00:53:50,000 在您的计算机可能烂尾最终的症状 988 00:53:50,000 --> 00:53:54,000 或愚蠢的纺纱沙滩球只是占用计算机的 989 00:53:54,000 --> 00:53:56,000 全部精力,你不能做的事情。 990 00:53:56,000 --> 00:54:00,000 这可以解释为任意数量的错误,但在这些可能的错误 991 00:54:00,000 --> 00:54:03,000 事情称为内存泄漏,有人是谁写的一块软件 992 00:54:03,000 --> 00:54:07,000 你不记得,以便释放内存 993 00:54:07,000 --> 00:54:10,000 他或她问的操作系统, 994 00:54:10,000 --> 00:54:14,000 不使用GetString,因为这是一个CS50的事情,但使用类似的功能 995 00:54:14,000 --> 00:54:16,000 问操作系统的内存。 996 00:54:16,000 --> 00:54:19,000 如果你或他们搞砸了,从来没有真正返回该内存 997 00:54:19,000 --> 00:54:24,000 一个程序,可以减缓放缓和减慢的症状, 998 00:54:24,000 --> 00:54:26,000 除非你记得打电话免费。 999 00:54:26,000 --> 00:54:28,000 >> 我们会回来的时候,为什么你会打电话免费, 1000 00:54:28,000 --> 00:54:32,000 但让我们继续前进的好措施,并尝试运行特定的程序。 1001 00:54:32,000 --> 00:54:35,000 这被称为structs1,请输入。 1002 00:54:35,000 --> 00:54:40,000 让我继续运行structs1的,123,大卫·马瑟 1003 00:54:40,000 --> 00:54:47,000 456,789,罗布·柯克兰, 1004 00:54:47,000 --> 00:54:50,000 汤米·马瑟,我们看到大卫的Mather中,汤米Mather中。 1005 00:54:50,000 --> 00:54:53,000 这仅仅是一个小的完整性检查程序的工作。 1006 00:54:53,000 --> 00:54:56,000 现在,不幸的是,这个方案是一个有点沮丧, 1007 00:54:56,000 --> 00:55:00,000 我做过的一切工作,我输入了9种不同的字符串,点击进入, 1008 00:55:00,000 --> 00:55:04,000 被告知是谁在奥美,但很明显,我知道是谁在奥美已经定了,因为我输入的。 1009 00:55:04,000 --> 00:55:07,000 至少这将是很好,如果这个计划更像是一个数据库 1010 00:55:07,000 --> 00:55:10,000 它实际上还记得我所输入的 1011 00:55:10,000 --> 00:55:12,000 所以我永远不会再有输入这些学生记录。 1012 00:55:12,000 --> 00:55:15,000 也许这是像registrarial系统。 1013 00:55:15,000 --> 00:55:21,000 >> 为此,我们可以使用这种技术被称为文件I / O,文件输入和输出, 1014 00:55:21,000 --> 00:55:24,000 一个非常通用的方法,说任何时候你想要读取文件或写入文件 1015 00:55:24,000 --> 00:55:26,000 一组特定的功能,你可以做到这一点。 1016 00:55:26,000 --> 00:55:29,000 让我继续并打开这个例子structs2.c, 1017 00:55:29,000 --> 00:55:33,000 这几乎是相同的,但让我们来看看它现在所做的。 1018 00:55:33,000 --> 00:55:36,000 在该文件的顶部,我宣布一个班的学生。 1019 00:55:36,000 --> 00:55:38,000 我然后填充类用户的输入, 1020 00:55:38,000 --> 00:55:41,000 所以这些代码行之前是完全一样的。 1021 00:55:41,000 --> 00:55:45,000 然后,如果我向下滚动,在这里我打印大家谁是Mather中任意像以前一样, 1022 00:55:45,000 --> 00:55:47,000 但是,这是一个有趣的新功能。 1023 00:55:47,000 --> 00:55:51,000 这两行代码是新的,他们在这里介绍一些, 1024 00:55:51,000 --> 00:55:55,000 FILE,全部大写,并且它有*在这里也。 1025 00:55:55,000 --> 00:55:58,000 让我搬过来,*在这里。 1026 00:55:58,000 --> 00:56:00,000 >> 这个功能,我们还没有看到之前,FOPEN, 1027 00:56:00,000 --> 00:56:03,000 但它意味着打开文件,让我们翻阅这些, 1028 00:56:03,000 --> 00:56:05,000 这是我们会回来的东西在未来的pset, 1029 00:56:05,000 --> 00:56:10,000 但此行基本上是在这里打开一个名为“数据库, 1030 00:56:10,000 --> 00:56:13,000 具体地说,它以这样一种方式,它可以做它打开? 1031 00:56:13,000 --> 00:56:15,000 [听不见的学生] 1032 00:56:15,000 --> 00:56:19,000 对,所以“W”只是意味着它告诉操作系统 1033 00:56:19,000 --> 00:56:21,000 以这样的方式,我可以写它,打开此文件。 1034 00:56:21,000 --> 00:56:23,000 我不想读它。我不想只是来看看。 1035 00:56:23,000 --> 00:56:26,000 我想改变它,添加的东西可能, 1036 00:56:26,000 --> 00:56:28,000 和文件将被称为数据库。 1037 00:56:28,000 --> 00:56:30,000 这可能是什么。 1038 00:56:30,000 --> 00:56:32,000 这可能是database.txt。这可能是分贝。 1039 00:56:32,000 --> 00:56:37,000 如foo这可能是一个词,但我随意选择命名的文件数据库。 1040 00:56:37,000 --> 00:56:42,000 这是一个小的完整性检查,我们会回来的很详细随着时间的推移, 1041 00:56:42,000 --> 00:56:47,000 如果fp文件指针,不等于NULL,这意味着一切都很好。 1042 00:56:47,000 --> 00:56:51,000 >> 长话短说,像fopen的功能有时会失败。 1043 00:56:51,000 --> 00:56:53,000 可能是文件不存在。也许你的磁盘空间。 1044 00:56:53,000 --> 00:56:55,000 也许你没有该文件夹的权限, 1045 00:56:55,000 --> 00:56:58,000 因此,如果FOPEN返回null的东西糟糕的事情发生。 1046 00:56:58,000 --> 00:57:02,000 相反,如果FOPEN没有返回null一切都很好 1047 00:57:02,000 --> 00:57:04,000 我就可以开始写这个文件。 1048 00:57:04,000 --> 00:57:06,000 这里有一个新的伎俩。 1049 00:57:06,000 --> 00:57:08,000 这是一个for循环遍历每个学生, 1050 00:57:08,000 --> 00:57:10,000 这看起来如此的相似,我们做了什么之前, 1051 00:57:10,000 --> 00:57:15,000 但这个函数是一个表姐的printf称为fprintf文件输出, 1052 00:57:15,000 --> 00:57:18,000 并注意在只有2种方式是不同的。 1053 00:57:18,000 --> 00:57:20,000 一,它开始用f代替p, 1054 00:57:20,000 --> 00:57:23,000 但后来它的第一个参数显然是什么? 1055 00:57:23,000 --> 00:57:25,000 [学生]文件。这是一个文件。 1056 00:57:25,000 --> 00:57:30,000 这件事称为FP,我们将最终梳理出一个文件指针是什么, 1057 00:57:30,000 --> 00:57:35,000 但现在FP仅仅代表我已经打开的文件, 1058 00:57:35,000 --> 00:57:41,000 fprintf这里说的文件打印用户的ID,而不是屏幕。 1059 00:57:41,000 --> 00:57:44,000 打印用户的名称的文件,而不是在屏幕上, 1060 00:57:44,000 --> 00:57:47,000 房子的文件,而不是在屏幕上,然后在这里,很明显, 1061 00:57:47,000 --> 00:57:50,000 关闭该文件,然后在这里释放内存。 1062 00:57:50,000 --> 00:57:53,000 >> 这个版本2和版本1之间的唯一区别 1063 00:57:53,000 --> 00:57:58,000 是fopen和引进此文件* 1064 00:57:58,000 --> 00:58:01,000 这个概念fprintf,让我们看看最终的结果是什么。 1065 00:58:01,000 --> 00:58:03,000 让我进入我的终端窗口。 1066 00:58:03,000 --> 00:58:06,000 让我跑structs2,进入。 1067 00:58:06,000 --> 00:58:09,000 看起来一切都很好。让我们重新运行structs2。 1068 00:58:09,000 --> 00:58:15,000 123,456,罗布·柯克兰,大卫·马瑟, 1069 00:58:15,000 --> 00:58:19,000 789,汤米·马瑟进入。 1070 00:58:19,000 --> 00:58:23,000 看起来像它的表现是相同的,但如果我现在做的LS 1071 00:58:23,000 --> 00:58:28,000 注意到什么文件是在这里,在我所有的代码,数据库, 1072 00:58:28,000 --> 00:58:32,000 让我们打开的是,gedit的数据库,看看。 1073 00:58:32,000 --> 00:58:34,000 这不是最性感的文件格式。 1074 00:58:34,000 --> 00:58:38,000 这真的是每行,每行一条数据线, 1075 00:58:38,000 --> 00:58:42,000 但那些你们谁使用Excel或CSV文件,逗号分隔值, 1076 00:58:42,000 --> 00:58:47,000 当然,我可以用fprintf,而不是可能做这样的事情 1077 00:58:47,000 --> 00:58:50,000 这样我就可以创建一个Excel文件,相当于 1078 00:58:50,000 --> 00:58:53,000 分离用逗号,不只是新的生产线。 1079 00:58:53,000 --> 00:58:56,000 >> 在这种情况下,如果我,而不是使用逗号,而不是新的生产线 1080 00:58:56,000 --> 00:59:01,000 我可以从字面上如果我在Excel中打开该数据库文件,而不是看起来像这样。 1081 00:59:01,000 --> 00:59:03,000 总之,现在我们有能力写入文件 1082 00:59:03,000 --> 00:59:07,000 我们现在可以开始持久化数据,保持光盘上 1083 00:59:07,000 --> 00:59:10,000 这样我们就可以保持信息的周围一遍又一遍。 1084 00:59:10,000 --> 00:59:14,000 注意其他的东西,现在有点熟悉的一对夫妇。 1085 00:59:14,000 --> 00:59:16,000 在这个C文件的顶部,我们有一个typedef 1086 00:59:16,000 --> 00:59:21,000 因为我们想创建一个数据类型,它表示一个字, 1087 00:59:21,000 --> 00:59:25,000 所以这种类型被称为字,和内部的这种结构 1088 00:59:25,000 --> 00:59:27,000 这是一个小票友。 1089 00:59:27,000 --> 00:59:30,000 为什么一个字组成的,显然是一个数组? 1090 00:59:30,000 --> 00:59:33,000 什么是一个词,仅仅凭直觉? 1091 00:59:33,000 --> 00:59:35,000 >> 这是一个字符数组。 1092 00:59:35,000 --> 00:59:37,000 这是一个字符序列,背靠背。 1093 00:59:37,000 --> 00:59:41,000 全部大写的字母恰好是我们武断地说,最大长度 1094 00:59:41,000 --> 00:59:44,000 任何字在字典中,我们使用的争夺。 1095 00:59:44,000 --> 00:59:46,000 为什么我有一个+1? 1096 00:59:46,000 --> 00:59:48,000 空字符。 1097 00:59:48,000 --> 00:59:51,000 记得当我们做了Bananagrams的例子,我们需要一个特殊的值 1098 00:59:51,000 --> 00:59:55,000 的词语的结尾处,以便跟踪 1099 00:59:55,000 --> 00:59:59,000 在的话实际上结束的情况下,作为问题集规范说 1100 00:59:59,000 --> 01:00:03,000 在这里,我们正在与一个给定的单词一个布尔值, 1101 01:00:03,000 --> 01:00:05,000 一个标志,可以这么说,真或假。 1102 01:00:05,000 --> 01:00:09,000 你有没有发现这个词,因为我们意识到 1103 01:00:09,000 --> 01:00:13,000 我们真正需要的一种方式记忆不仅是一个字是在争夺 1104 01:00:13,000 --> 01:00:15,000 但是否你的人,已经找到了 1105 01:00:15,000 --> 01:00:20,000 所以,如果你发现这个词“:”你不能只键入,进入,进入,进入 1106 01:00:20,000 --> 01:00:23,000 并得到3分,3分,3分,3分。 1107 01:00:23,000 --> 01:00:26,000 我们希望能够黑名单这个词通过设置一个布尔值, 1108 01:00:26,000 --> 01:00:29,000 为true,如果你已经发现了,所以这就是为什么我们 1109 01:00:29,000 --> 01:00:31,000 封装在该结构中。 1110 01:00:31,000 --> 01:00:35,000 >> 现在,在这里争夺,这种结构称为字典。 1111 01:00:35,000 --> 01:00:39,000 缺少这里是字的typedef,因为在这种情况下 1112 01:00:39,000 --> 01:00:43,000 我们需要封装的一本字典的想法, 1113 01:00:43,000 --> 01:00:46,000 和一本字典包含了一大堆的话, 1114 01:00:46,000 --> 01:00:49,000 这个数组所暗示的,和那些话是多少呢? 1115 01:00:49,000 --> 01:00:51,000 好吧,不管说这个变量的大小。 1116 01:00:51,000 --> 01:00:53,000 但我们只需要一个字典。 1117 01:00:53,000 --> 01:00:55,000 我们并不需要的数据类型称为字典。 1118 01:00:55,000 --> 01:00:58,000 我们只需要其中的一个,所以在C 1119 01:00:58,000 --> 01:01:03,000 如果你不说的typedef,你刚才说的结构,然后在大括号中 1120 01:01:03,000 --> 01:01:05,000 你把你的变量,然后你把这个名字。 1121 01:01:05,000 --> 01:01:09,000 这是声明一个变量称为字典 1122 01:01:09,000 --> 01:01:11,000 像这样的。 1123 01:01:11,000 --> 01:01:16,000 与此相反,这些行调用Word创建一个可重复使用的数据结构 1124 01:01:16,000 --> 01:01:19,000 您可以创建多个副本,就像我们创建 1125 01:01:19,000 --> 01:01:22,000 学生的多个副本。 1126 01:01:22,000 --> 01:01:24,000 >> 这是什么最终让我们做什么? 1127 01:01:24,000 --> 01:01:30,000 让我回去,比方说,一个简单的例子,从简单的时代, 1128 01:01:30,000 --> 01:01:34,000 让我开了,让我们说,compare1.c。 1129 01:01:34,000 --> 01:01:38,000 的问题,在这里实际上是剥开 1130 01:01:38,000 --> 01:01:41,000 层的一个字符串,并开始起飞训练车轮 1131 01:01:41,000 --> 01:01:44,000 因为它把一个字符串的所有时间 1132 01:01:44,000 --> 01:01:47,000 我们承诺在第1周真的只是一个昵称, 1133 01:01:47,000 --> 01:01:51,000 CS50库的东西,看起来多了几分神秘的代名词, 1134 01:01:51,000 --> 01:01:53,000 是char *,我们已经看到了这颗恒星。 1135 01:01:53,000 --> 01:01:55,000 我们看到它在文件中。 1136 01:01:55,000 --> 01:01:59,000 >> 现在,让我们看到为什么我们一直躲在这个细节有一段时间了。 1137 01:01:59,000 --> 01:02:02,000 这里是一个名为compare1.c, 1138 01:02:02,000 --> 01:02:07,000 它显然要求用户为2个字符串,s和t, 1139 01:02:07,000 --> 01:02:11,000 然后,它试图比较这些字符串平等的第26行, 1140 01:02:11,000 --> 01:02:14,000 如果他们是平等的说,“你输入同样的事情。” 1141 01:02:14,000 --> 01:02:17,000 如果他们不相等,它说,“您输入不同的事情。” 1142 01:02:17,000 --> 01:02:19,000 让我继续运行这个程序。 1143 01:02:19,000 --> 01:02:23,000 让我进入我的源目录,做一个比较1。编译没问题。 1144 01:02:23,000 --> 01:02:25,000 让我运行比较。 1145 01:02:25,000 --> 01:02:27,000 我会放大,进入。 1146 01:02:27,000 --> 01:02:29,000 说些什么。 HELLO。 1147 01:02:29,000 --> 01:02:32,000 我会说些什么了。 HELLO。 1148 01:02:32,000 --> 01:02:34,000 我绝对没有输入不同的东西。 1149 01:02:34,000 --> 01:02:37,000 >> 让我再试一次。 BYE BYE。 1150 01:02:37,000 --> 01:02:40,000 绝对没有什么不同,所以在这里发生了什么事? 1151 01:02:40,000 --> 01:02:44,000 那么,什么是真正被比较的第26行吗? 1152 01:02:44,000 --> 01:02:46,000 [听不见的学生] 1153 01:02:46,000 --> 01:02:49,000 是的,所以它变成了一个字符串,数据类型,是一种善意的谎言。 1154 01:02:49,000 --> 01:02:53,000 一个字符串,是一个char *,但什么是一个char *? 1155 01:02:53,000 --> 01:02:56,000 ,正如他们所说的,是一个char *指针, 1156 01:02:56,000 --> 01:03:00,000 和一个指针是一个有效的地址, 1157 01:03:00,000 --> 01:03:05,000 一笔在内存中的位置,如果你恰好有输入一个字,如HELLO, 1158 01:03:05,000 --> 01:03:08,000 回忆起过去的讨论中的字符串 1159 01:03:08,000 --> 01:03:16,000 之类的词,这是HELLO。 1160 01:03:16,000 --> 01:03:19,000 请记住,一个词可以表示喜欢HELLO 1161 01:03:19,000 --> 01:03:22,000 作为一个字符数组,这样 1162 01:03:22,000 --> 01:03:25,000 然后用一个特殊字符结束时称为空字符, 1163 01:03:25,000 --> 01:03:27,000 \表示。 1164 01:03:27,000 --> 01:03:29,000 实际上是一个字符串是什么? 1165 01:03:29,000 --> 01:03:32,000 请注意,这是多的内存块, 1166 01:03:32,000 --> 01:03:36,000 而事实上,它的结束是唯一的已知的,一旦你通过整个字符串 1167 01:03:36,000 --> 01:03:38,000 寻找特殊的NULL字符。 1168 01:03:38,000 --> 01:03:41,000 但是,如果这是一个从我的电脑的内存中的内存块, 1169 01:03:41,000 --> 01:03:44,000 让我们武断地说,这个字符串只是很幸运, 1170 01:03:44,000 --> 01:03:47,000 它被认为是放置在开始的时候,我的电脑的RAM。 1171 01:03:47,000 --> 01:03:54,000 这是字节0,1,2,3,4,5,6 ... 1172 01:03:54,000 --> 01:04:02,000 >> 当我说类似的GetString和我做字符串s = GetString的 1173 01:04:02,000 --> 01:04:04,000 什么是真正的回来了吗? 1174 01:04:04,000 --> 01:04:08,000 为这些过去的几个星期,真的被储存在s 1175 01:04:08,000 --> 01:04:13,000 是不是这个字符串本身,而是在这种情况下,被存储的是 1176 01:04:13,000 --> 01:04:18,000 因为GetString的确实数0 1177 01:04:18,000 --> 01:04:20,000 它是物理上不返回一个字符串。 1178 01:04:20,000 --> 01:04:22,000 甚至没有真正概念上的意义。 1179 01:04:22,000 --> 01:04:24,000 它的回报率是多少。 1180 01:04:24,000 --> 01:04:28,000 这个数字是在内存中的地址, 1181 01:04:28,000 --> 01:04:32,000 字符串s,然后,如果我们剥开这层,字符串并不真正存在。 1182 01:04:32,000 --> 01:04:35,000 这只是一个简化的CS50库中。 1183 01:04:35,000 --> 01:04:38,000 >> 这真的是所谓的char *。 1184 01:04:38,000 --> 01:04:41,000 字符是有道理的,因为什么是一个词,像HELLO? 1185 01:04:41,000 --> 01:04:44,000 嗯,这是一系列的字符,字符系列。 1186 01:04:44,000 --> 01:04:47,000 字符*表示一个字符的地址, 1187 01:04:47,000 --> 01:04:50,000 所以这是什么意思返回一个字符串? 1188 01:04:50,000 --> 01:04:53,000 一个不错的,简单的方法,返回一个字符串, 1189 01:04:53,000 --> 01:04:57,000 而不是试图找出如何我返回到5或6个不同的字节 1190 01:04:57,000 --> 01:05:01,000 让我回到哪个字节的地址? 1191 01:05:01,000 --> 01:05:03,000 第一个。 1192 01:05:03,000 --> 01:05:06,000 换句话说,让我给你一个字符在内存中的地址。 1193 01:05:06,000 --> 01:05:10,000 这就是字符“*”代表一个单一的字符在内存中的地址。 1194 01:05:10,000 --> 01:05:12,000 调用该变量s。 1195 01:05:12,000 --> 01:05:15,000 存放在那个特定的地址,我随意说的是0, 1196 01:05:15,000 --> 01:05:19,000 只是为了让事情简单,但在现实中,它通常是一个比较大的数字。 1197 01:05:19,000 --> 01:05:21,000 >> 等待一分钟。 1198 01:05:21,000 --> 01:05:23,000 如果你只给我的第一个字符的地址,我怎么知道的地址是什么 1199 01:05:23,000 --> 01:05:25,000 第二个字符,第三,第四和第五? 1200 01:05:25,000 --> 01:05:27,000 [听不见的学生] 1201 01:05:27,000 --> 01:05:31,000 你只知道结尾的字符串的方法是通过这个方便的窍门, 1202 01:05:31,000 --> 01:05:35,000 因此,当你使用的东西像printf,printf的变相作为它的参数, 1203 01:05:35,000 --> 01:05:39,000 还记得我们用%s占位符,然后你传递 1204 01:05:39,000 --> 01:05:41,000 变量的存储字符串。 1205 01:05:41,000 --> 01:05:47,000 你真正传递的是该字符串的第一个字符的地址。 1206 01:05:47,000 --> 01:05:50,000 的printf然后使用for循环或while循环在收到该地址, 1207 01:05:50,000 --> 01:05:53,000 例如,0,所以让我现在这样做, 1208 01:05:53,000 --> 01:06:02,000 输出(“%s \ n”); 1209 01:06:02,000 --> 01:06:07,000 当我调用printf(“%s \ n”);我真正提供输出与 1210 01:06:07,000 --> 01:06:13,000 在s中的第一个字符的地址,在这种任意的情况下,这是H。 1211 01:06:13,000 --> 01:06:16,000 >> printf的知道如何显示在屏幕上,究竟是什么? 1212 01:06:16,000 --> 01:06:19,000 的人谁执行printf的实现了一个while循环或循环 1213 01:06:19,000 --> 01:06:23,000 说这个字符等于空字符? 1214 01:06:23,000 --> 01:06:25,000 如果没有,打印。这个怎么样? 1215 01:06:25,000 --> 01:06:28,000 如果不能打印,打印出来,打印出来,打印出来。 1216 01:06:28,000 --> 01:06:32,000 哦,这是特殊的。停止打印,并返回给用户。 1217 01:06:32,000 --> 01:06:35,000 这是字面上所有的引擎盖下发生的, 1218 01:06:35,000 --> 01:06:38,000 这是一个很大消化的第一天,一类, 1219 01:06:38,000 --> 01:06:43,000 但现在它是真正了解一切的基石 1220 01:06:43,000 --> 01:06:46,000 已经持续我们的电脑的内存内的, 1221 01:06:46,000 --> 01:06:49,000 ,最终,我们会逗除了一点点帮助 1222 01:06:49,000 --> 01:06:51,000 我们的一个朋友在斯坦福大学。 1223 01:06:51,000 --> 01:06:56,000 >> 在斯坦福大学的教授尼克Parlante已经这样做了精彩的视频序列 1224 01:06:56,000 --> 01:06:58,000 从各种不同的语言,介绍 1225 01:06:58,000 --> 01:07:00,000 这个小的黏土动画人物Binky。 1226 01:07:00,000 --> 01:07:03,000 你的声音,听到在短短的几秒钟先睹为快 1227 01:07:03,000 --> 01:07:05,000 是斯坦福大学教授,你要 1228 01:07:05,000 --> 01:07:07,000 现在只有5或6秒的这一权利, 1229 01:07:07,000 --> 01:07:09,000 但是这是说明我们将结束今天 1230 01:07:09,000 --> 01:07:11,000 (星期三)开始。 1231 01:07:11,000 --> 01:07:15,000 我给你宾基,预览的指针乐趣。 1232 01:07:15,000 --> 01:07:18,000 [♪音乐♪]教授Parlante]嘿,宾基。 1233 01:07:18,000 --> 01:07:21,000 唤醒。它的时间的指针乐趣。 1234 01:07:21,000 --> 01:07:24,000 [宾基]那是什么?了解指针吗? 1235 01:07:24,000 --> 01:07:26,000 哦,好极了! 1236 01:07:26,000 --> 01:07:29,000 >> 我们将看到你在周三。 1237 01:07:29,000 --> 01:07:32,000 [CS50.TV]