1 00:00:00,000 --> 00:00:03,000 [Powered by Google Translate] [评论] [测验] 2 00:00:03,000 --> 00:00:05,000 >> [亚力克西斯·罗斯,汤米MacWilliam,卢卡斯·弗雷塔斯,王阳乐] [哈佛大学] 3 00:00:05,000 --> 00:00:08,000 >> 这是CS50。[CS50.TV] 4 00:00:08,000 --> 00:00:10,000 >> 嘿,大家好。 5 00:00:10,000 --> 00:00:15,000 欢迎测验0,这是本周三举行的审查会议。 6 00:00:15,000 --> 00:00:19,000 我们要做的今晚,我和其他3个转录因子, 7 00:00:19,000 --> 00:00:24,000 和我们一起去了什么,我们做的过程中,到目前为止,通过审查。 8 00:00:24,000 --> 00:00:27,000 它不会是100%全面,但它应该给你一个更好的主意 9 00:00:27,000 --> 00:00:31,000 你已经有什么,你仍然需要研究(星期三)前。 10 00:00:31,000 --> 00:00:34,000 而且感觉我们一起去提高你的手的问题, 11 00:00:34,000 --> 00:00:38,000 但请记住,我们还会有一点点的时间结束时, 12 00:00:38,000 --> 00:00:41,000 如果我们通过几分钟业余做一般的问题, 13 00:00:41,000 --> 00:00:47,000 所以记住这一点,所以我们要开始在0周开始。 14 00:00:47,000 --> 00:00:50,000 >> [问答共0] [第0] [亚力克西斯·罗斯]但在此之前,让我们谈论 15 00:00:50,000 --> 00:00:53,000 物流的测验。 16 00:00:53,000 --> 00:00:55,000 >> [物流] [测验发生在10/10(星期三)代替演讲] 17 00:00:55,000 --> 00:00:57,000 >> (见的详细信息http://cdn.cs50.net/2012/fall/quizzes/0/about0.pdf)]这是10月10日(星期三)。 18 00:00:57,000 --> 00:01:00,000 >> 这是本周三,如果你去到这个URL, 19 00:01:00,000 --> 00:01:03,000 这也是从CS50.net的访问的链接 20 00:01:03,000 --> 00:01:06,000 去哪里的基础上,你可以看到信息 21 00:01:06,000 --> 00:01:10,000 您的姓氏或所属学校以及 22 00:01:10,000 --> 00:01:14,000 它讲述了什么测验将涵盖和类型的问题,你会得到。 23 00:01:14,000 --> 00:01:19,000 请记住,你也有机会审查测验部分, 24 00:01:19,000 --> 00:01:21,000 所以你的的TFS应超过一些实际问题, 25 00:01:21,000 --> 00:01:29,000 这是另一个很好的机会看到你仍然需要学习测验。 26 00:01:29,000 --> 00:01:32,000 让我们从一开始位'N'字节。 27 00:01:32,000 --> 00:01:35,000 请记住一个位是0或1, 28 00:01:35,000 --> 00:01:38,000 和一个字节是8的那些位的集合。 29 00:01:38,000 --> 00:01:42,000 让我们来看看位在此集合在这里。 30 00:01:42,000 --> 00:01:44,000 我们应该能够找出有多少位。 31 00:01:44,000 --> 00:01:48,000 如果我们指望有8人,8个0或1个单位。 32 00:01:48,000 --> 00:01:51,000 而且,由于有8位,这是1个字节, 33 00:01:51,000 --> 00:01:53,000 让我们把它转换为十六进制。 34 00:01:53,000 --> 00:01:58,000 十六进制的基数为16,这是很容易转换 35 00:01:58,000 --> 00:02:01,000 一个二进制数,这是这是一个十六进制数。 36 00:02:01,000 --> 00:02:04,000 我们要做的就是我们期待在4组, 37 00:02:04,000 --> 00:02:07,000 我们将其转换为相应的十六进制数字。 38 00:02:07,000 --> 00:02:11,000 我们从最右边的4组,所以0011。 39 00:02:11,000 --> 00:02:16,000 这将是一个1和一个2,这样在一起,使得3。 40 00:02:16,000 --> 00:02:19,000 然后让我们来看看其他4块。 41 00:02:19,000 --> 00:02:24,000 1101年。这将是一个1,一个4,一个8。 42 00:02:24,000 --> 00:02:28,000 在一起,将是13,这使得D。 43 00:02:28,000 --> 00:02:32,000 我们会记住,在十六进制中,我们不只是从0到9。 44 00:02:32,000 --> 00:02:36,000 我们去到F 0,所以在9,10对应到A, 45 00:02:36,000 --> 00:02:40,000 11到B,等,其中F是15。 46 00:02:40,000 --> 00:02:44,000 其中,图13是一个D, 47 00:02:44,000 --> 00:02:49,000 所以将其转换为十进制,我们所做的一切是我们实际上 48 00:02:49,000 --> 00:02:52,000 对待每一个位置为2的幂。 49 00:02:52,000 --> 00:02:58,000 这是一个1,一个2,零4秒,零8秒,一个16,等等, 50 00:02:58,000 --> 00:03:03,000 这是一个有点难以计算在你的脑袋,但如果我们去到下一张幻灯片 51 00:03:03,000 --> 00:03:05,000 我们可以看到这个问题的答案。 52 00:03:05,000 --> 00:03:09,000 >> 从本质上讲,我们要跨越右到左, 53 00:03:09,000 --> 00:03:14,000 ,我们将每个数字所对应的功率为2。 54 00:03:14,000 --> 00:03:19,000 请记住,十六进制表示,这些数字以0x开始 55 00:03:19,000 --> 00:03:23,000 因此,我们不要混淆一个十进制数。 56 00:03:23,000 --> 00:03:29,000 继续,这是一个ASCII表, 57 00:03:29,000 --> 00:03:35,000 我们使用ASCII是从字符映射到的数值。 58 00:03:35,000 --> 00:03:39,000 请记住,在密码学的pset,我们广泛使用的ASCII表 59 00:03:39,000 --> 00:03:43,000 为了使用密码学的各种方法, 60 00:03:43,000 --> 00:03:47,000 凯撒和维琼内尔的密码,不同的字母转换 61 00:03:47,000 --> 00:03:52,000 在一个字符串中,根据由用户给定的关键。 62 00:03:52,000 --> 00:03:56,000 让我们来看看在一点点的ASCII数学。 63 00:03:56,000 --> 00:04:02,000 寻找在“P”以字符的形式,将是Q,+ 1, 64 00:04:02,000 --> 00:04:07,000 记得,'5'≠5。 65 00:04:07,000 --> 00:04:10,000 我们究竟如何转换之间的2种形式? 66 00:04:10,000 --> 00:04:13,000 它实际上不是太硬。 67 00:04:13,000 --> 00:04:16,000 为了让我们减去'0' 68 00:04:16,000 --> 00:04:20,000 因为有5个地方之间的'0'和'5'。 69 00:04:20,000 --> 00:04:23,000 为了走另外一条路,我们只是添加了0, 70 00:04:23,000 --> 00:04:25,000 所以这有点像普通的算术。 71 00:04:25,000 --> 00:04:29,000 请记住,有些事情时,周围的引号字符 72 00:04:29,000 --> 00:04:37,000 ,从而对应于ASCII码表中的一个值。 73 00:04:37,000 --> 00:04:40,000 移动到更一般的计算机科学课题。 74 00:04:40,000 --> 00:04:43,000 我们了解到的算法是什么,以及我们如何使用编程 75 00:04:43,000 --> 00:04:45,000 实现算法。 76 00:04:45,000 --> 00:04:48,000 算法的一些例子是很简单的东西如 77 00:04:48,000 --> 00:04:51,000 检查是否一个数是偶数还是奇数。 78 00:04:51,000 --> 00:04:54,000 为此,还记得我们国防部的数字2,检查如果结果是0。 79 00:04:54,000 --> 00:04:57,000 如果是这样,它甚至。如果没有,这是奇怪的。 80 00:04:57,000 --> 00:04:59,000 这是一个非常基本的算法的一个例子。 81 00:04:59,000 --> 00:05:02,000 >> 一点点的一个更棘手的是二进制搜索, 82 00:05:02,000 --> 00:05:05,000 后来我们就去了审查会议。 83 00:05:05,000 --> 00:05:09,000 编程是长远来说,我们使用的算法 84 00:05:09,000 --> 00:05:15,000 和将其转换为代码的计算机可读取。 85 00:05:15,000 --> 00:05:20,000 2实例编程是零起步, 86 00:05:20,000 --> 00:05:22,000 这是我们在0周。 87 00:05:22,000 --> 00:05:25,000 即使我们没有实际键入的代码,它是一​​种实施 88 00:05:25,000 --> 00:05:29,000 算法,这是印刷数字1到10, 89 00:05:29,000 --> 00:05:32,000 在这里,我们做同样的在C编程语言。 90 00:05:32,000 --> 00:05:41,000 这些功能相同,只是在不同的语言或语法编写的。 91 00:05:41,000 --> 00:05:44,000 然后,我们了解的布尔表达式, 92 00:05:44,000 --> 00:05:48,000 和一个布尔值,或真或假的, 93 00:05:48,000 --> 00:05:51,000 这里常常布尔表达式 94 00:05:51,000 --> 00:05:55,000 里面去的条件下,所以如果(x≤5), 95 00:05:55,000 --> 00:06:00,000 好了,我们已经设置X = 5,所以这个条件会评估为true。 96 00:06:00,000 --> 00:06:03,000 如果这是真的,无论代码是下面的条件 97 00:06:03,000 --> 00:06:08,000 要由计算机进行评价,使字符串要打印 98 00:06:08,000 --> 00:06:12,000 到标准输出,和工作条件 99 00:06:12,000 --> 00:06:16,000 是指无论是在括号内的if语句。 100 00:06:16,000 --> 00:06:20,000 记住所有的运营商。 101 00:06:20,000 --> 00:06:26,000 记住它的&&和| |,当我们试图结合2个或更多的条件, 102 00:06:26,000 --> 00:06:30,000 ==不检查,是否事情都是平等的。 103 00:06:30,000 --> 00:06:36,000 请记住,=是赋值,而==是一个布尔运算符。 104 00:06:36,000 --> 00:06:41,000 ≤,≥,然后在最后2是不言自明的。 105 00:06:41,000 --> 00:06:45,000 这里的布尔逻辑的一般审查。 106 00:06:45,000 --> 00:06:48,000 和布尔表达式在循环中也是很重要的, 107 00:06:48,000 --> 00:06:50,000 现在我们就去了。 108 00:06:50,000 --> 00:06:56,000 我们学会了3种类型的循环迄今为止,CS50,同时,做,而。 109 00:06:56,000 --> 00:06:59,000 重要的是要知道,对于大多数用途 110 00:06:59,000 --> 00:07:02,000 我们实际上可以使用任何类型的循环 111 00:07:02,000 --> 00:07:06,000 有一定的目的或共同的模式 112 00:07:06,000 --> 00:07:09,000 在编程中特别呼吁这些循环 113 00:07:09,000 --> 00:07:13,000 ,使它成为最有效或最优雅的代码以这种方式。 114 00:07:13,000 --> 00:07:18,000 让我们在这些循环往往是最常见的。 115 00:07:18,000 --> 00:07:21,000 >> 在循环中,我们已经知道我们要重复多少次。 116 00:07:21,000 --> 00:07:24,000 这就是我们提出的条件中。 117 00:07:24,000 --> 00:07:28,000 对于,= 0,<10,例如。 118 00:07:28,000 --> 00:07:31,000 我们已经知道,我们想要做的东西10倍。 119 00:07:31,000 --> 00:07:34,000 现在,一个while循环中,我们一般不必然 120 00:07:34,000 --> 00:07:36,000 我们要知道有多少次的循环运行。 121 00:07:36,000 --> 00:07:39,000 但我们知道某种条件下,我们希望它是 122 00:07:39,000 --> 00:07:41,000 始终是真实的,永远是虚假的。 123 00:07:41,000 --> 00:07:44,000 例如,虽然被设定。 124 00:07:44,000 --> 00:07:46,000 比方说,这是一个布尔变量。 125 00:07:46,000 --> 00:07:48,000 虽然这是真的,我们要评估的代码, 126 00:07:48,000 --> 00:07:52,000 有那么一点点更多的可扩展性,多一点点普遍比一个for循环, 127 00:07:52,000 --> 00:07:55,000 但任何的for循环也可以转换为一个while循环。 128 00:07:55,000 --> 00:08:00,000 最后,执行while循环,这可能是最棘手的理解, 129 00:08:00,000 --> 00:08:04,000 经常使用,当我们要评估的代码 130 00:08:04,000 --> 00:08:06,000 之前我们第一次检查的条件。 131 00:08:06,000 --> 00:08:09,000 一个常见的​​用例的do while循环 132 00:08:09,000 --> 00:08:12,000 当你想获取用户输入的,你知道你要问的用户 133 00:08:12,000 --> 00:08:15,000 输入至少一次,但如果他们不给你良好的输入 134 00:08:15,000 --> 00:08:18,000 你要不断地问他们,直到他们给你良好的输入。 135 00:08:18,000 --> 00:08:21,000 这是最常见的使用whil​​e循环, 136 00:08:21,000 --> 00:08:23,000 让我们来看看在这些循环的实际结构。 137 00:08:23,000 --> 00:08:27,000 他们通常总是按照这些模式。 138 00:08:27,000 --> 00:08:30,000 >> 在fo​​r循环内,你有3个组成部分: 139 00:08:30,000 --> 00:08:35,000 初始化,通常的东西,如int i = 0,其中i是计数器, 140 00:08:35,000 --> 00:08:40,000 条件,在这里我们想说的运行循环,只要这种情况下仍持有, 141 00:08:40,000 --> 00:08:44,000 像我<10,然后在最后,更新,这是我们增加 142 00:08:44,000 --> 00:08:47,000 在循环中的每个点的计数器变量。 143 00:08:47,000 --> 00:08:50,000 看到有一个共同的东西就是我+ +, 144 00:08:50,000 --> 00:08:52,000 这意味着每次递增i。 145 00:08:52,000 --> 00:08:55,000 你也可以做类似的东西我+ = 2, 146 00:08:55,000 --> 00:08:58,000 这意味着加2我每次去通过循环。 147 00:08:58,000 --> 00:09:03,000 然后这样做只是指实际运行循环的一部分的任何代码。 148 00:09:03,000 --> 00:09:09,000 一个while循环,这个时候,我们其实有外循环的初始化, 149 00:09:09,000 --> 00:09:12,000 例如,让我们说,我们正在试图做的,因为我刚才所描述的相同类型的循环。 150 00:09:12,000 --> 00:09:16,000 我们会说INT I = 0,在循环开始前。 151 00:09:16,000 --> 00:09:20,000 然后,我们可以这样说,而我做到这一点, 152 00:09:20,000 --> 00:09:22,000 所以相同的代码块之前, 153 00:09:22,000 --> 00:09:26,000 而这一次的更新部分的代码,例如,我+ +, 154 00:09:26,000 --> 00:09:29,000 其实里面的循环。 155 00:09:29,000 --> 00:09:33,000 最后,对于一个这样做的同时,它类似于while循环, 156 00:09:33,000 --> 00:09:36,000 但我们必须记住,代码将评估一次 157 00:09:36,000 --> 00:09:40,000 前检查条件,所以它使很多更有意义 158 00:09:40,000 --> 00:09:44,000 如果你看它在从上到下的顺序。 159 00:09:44,000 --> 00:09:49,000 在while循环中的代码进行评估之前,你甚至看while条件, 160 00:09:49,000 --> 00:09:55,000 而一个while循环,它会首先检查。 161 00:09:55,000 --> 00:09:59,000 报表和变量。 162 00:09:59,000 --> 00:10:04,000 当我们要创建一个新的变量,我们首先要对其进行初始化。 163 00:10:04,000 --> 00:10:07,000 >> 例如,int酒吧初始化变量的酒吧, 164 00:10:07,000 --> 00:10:10,000 但它并没有给它一个值,所以现在栏的值是什么? 165 00:10:10,000 --> 00:10:12,000 我们不知道。 166 00:10:12,000 --> 00:10:14,000 这可能是以前存储在内存中有一些垃圾的价值, 167 00:10:14,000 --> 00:10:16,000 我们不想使用该变量 168 00:10:16,000 --> 00:10:19,000 直到我们真正给它一个值, 169 00:10:19,000 --> 00:10:21,000 因此,我们在这里声明。 170 00:10:21,000 --> 00:10:24,000 然后,我们把它初始化为42。 171 00:10:24,000 --> 00:10:28,000 现在,当然,我们知道这是可以做到一条线,酒吧= 42。 172 00:10:28,000 --> 00:10:30,000 但仅仅是明确的多个步骤,是怎么回事, 173 00:10:30,000 --> 00:10:34,000 声明和初始化分别在这里发生。 174 00:10:34,000 --> 00:10:38,000 它发生在一个步骤,下一个,巴兹=酒吧+ 1, 175 00:10:38,000 --> 00:10:44,000 这以下声明,递增的的巴兹,所以在这个代码块的结束 176 00:10:44,000 --> 00:10:48,000 如果我们要打印的价值巴兹这将是44 177 00:10:48,000 --> 00:10:52,000 因为我们声明并把它初始化为1>酒吧, 178 00:10:52,000 --> 00:10:58,000 然后我们增加一次+ +。 179 00:10:58,000 --> 00:11:02,000 我们去了这个漂亮的简要,但它有一个大致的 180 00:11:02,000 --> 00:11:04,000 了解线程和事件是什么。 181 00:11:04,000 --> 00:11:06,000 我们主要是在刮, 182 00:11:06,000 --> 00:11:09,000 所以你可以把多个线程的代码序列 183 00:11:09,000 --> 00:11:11,000 在同一时间运行。 184 00:11:11,000 --> 00:11:14,000 实际上,它可能是运行在相同的时间, 185 00:11:14,000 --> 00:11:17,000 但形式的抽象,我们可以认为它以这种方式。 186 00:11:17,000 --> 00:11:20,000 >> 从无到有,例如,我们有多个精灵。 187 00:11:20,000 --> 00:11:22,000 它可以在同一时间执行不同的代码。 188 00:11:22,000 --> 00:11:26,000 人们可以一边走一边说的东西 189 00:11:26,000 --> 00:11:29,000 在一个不同的,在屏幕的一部分。 190 00:11:29,000 --> 00:11:34,000 事件是另一种方式分离出来的逻辑 191 00:11:34,000 --> 00:11:37,000 不同元素之间,你的代码, 192 00:11:37,000 --> 00:11:40,000 在Scratch中,我们能够模拟活动,利用广播, 193 00:11:40,000 --> 00:11:43,000 这实际上是当我收到,而不是当我听到, 194 00:11:43,000 --> 00:11:47,000 但实质上,它是一个传递信息的方法 195 00:11:47,000 --> 00:11:49,000 从一个精灵到另一个地方。 196 00:11:49,000 --> 00:11:52,000 例如,您可能要传输游戏, 197 00:11:52,000 --> 00:11:56,000 另一个精灵,当比赛结束, 198 00:11:56,000 --> 00:11:58,000 它以某种方式回应。 199 00:11:58,000 --> 00:12:03,000 这是一个重要的编程模型,以了解。 200 00:12:03,000 --> 00:12:07,000 刚去超过基本的周0,我们已经讨论了这么远, 201 00:12:07,000 --> 00:12:10,000 让我们来看看这个简单的C程序。 202 00:12:10,000 --> 00:12:14,000 文字可能是从这里开始的一点点小,但我会去非常快的。 203 00:12:14,000 --> 00:12:20,000 我们包括2头文件的顶部,cs50.h的和stdio.h中。 204 00:12:20,000 --> 00:12:23,000 然后,我们定义一个常数,称为限制为100。 205 00:12:23,000 --> 00:12:26,000 然后,我们执行我们的主要功能。 206 00:12:26,000 --> 00:12:29,000 由于我们没有使用命令行参数,在这里,我们需要把作废 207 00:12:29,000 --> 00:12:32,000 作为主要的参数。 208 00:12:32,000 --> 00:12:38,000 我们看到上述主要的诠释。这是返回类型,因此返回0,在底部。 209 00:12:38,000 --> 00:12:41,000 我们使用的是CS50库函数得到诠释 210 00:12:41,000 --> 00:12:45,000 要求用户输入,我们将其存储在这个变量x, 211 00:12:45,000 --> 00:12:51,000 因此,我们宣布上述X,和我们对它进行初始化,其中x =调用getInt。 212 00:12:51,000 --> 00:12:53,000 >> 然后我们检查,看是否用户给了我们很好的输入。 213 00:12:53,000 --> 00:12:59,000 如果我们要≥LIMIT返回一个错误代码1和打印错误消息。 214 00:12:59,000 --> 00:13:02,000 最后,如​​果用户已经给了我们很好的输入 215 00:13:02,000 --> 00:13:08,000 我们要正视的数量和打印出来,结果。 216 00:13:08,000 --> 00:13:11,000 只是为了确保这些全部命中回家 217 00:13:11,000 --> 00:13:17,000 你可以看到这里的代码的不同部分的标签。 218 00:13:17,000 --> 00:13:19,000 我提到不变,头文件。 219 00:13:19,000 --> 00:13:21,000 哦,诠释x。请一定要记住,这是一个局部变量。 220 00:13:21,000 --> 00:13:24,000 对比从一个全局变量,我们将讨论 221 00:13:24,000 --> 00:13:27,000 一点点后,在审查会议, 222 00:13:27,000 --> 00:13:30,000 和我们调用库函数printf, 223 00:13:30,000 --> 00:13:34,000 因此,如果我们没有包含stdio.h头文件 224 00:13:34,000 --> 00:13:37,000 我们将无法调用printf。 225 00:13:37,000 --> 00:13:42,000 我相信,进行了切断箭头指向的%d, 226 00:13:42,000 --> 00:13:45,000 这是在printf的格式化字符串。 227 00:13:45,000 --> 00:13:52,000 它说一个数字,第%d打印出这个变量。 228 00:13:52,000 --> 00:13:58,000 这是它第0周。 229 00:13:58,000 --> 00:14:06,000 现在,卢卡斯继续下去。 230 00:14:06,000 --> 00:14:08,000 嘿,伙计们。我的名字是卢卡斯。 231 00:14:08,000 --> 00:14:10,000 我是一个大二学生在校园里,奥美最好的房子, 232 00:14:10,000 --> 00:14:14,000 我要谈一点,约1周和2.1周。 233 00:14:14,000 --> 00:14:16,000 [1周和2.1周] [卢卡斯·弗雷塔斯] 234 00:14:16,000 --> 00:14:19,000 Lexi的说,当我们开始从头开始你的代码翻译到C 235 00:14:19,000 --> 00:14:23,000 ,我们注意到的事情之一是,你不能只是 236 00:14:23,000 --> 00:14:26,000 写你的代码,并运行它使用了一个绿色的标志。 237 00:14:26,000 --> 00:14:30,000 其实,你必须使用一些步骤,以使你的C程序 238 00:14:30,000 --> 00:14:33,000 成为一个可执行文件。 239 00:14:33,000 --> 00:14:36,000 基本上你做了什么时,你所编写的程序是, 240 00:14:36,000 --> 00:14:40,000 你翻译成一种语言,编译器能够理解你的想法, 241 00:14:40,000 --> 00:14:44,000 所以,当你正在编写一个程序,在C 242 00:14:44,000 --> 00:14:47,000 你在做什么,实际上是写东西,你的编译器是怎么回事了解, 243 00:14:47,000 --> 00:14:50,000 那么编译器会翻译的代码 244 00:14:50,000 --> 00:14:53,000 到的东西,你的电脑就会明白。 245 00:14:53,000 --> 00:14:55,000 >> 的事情,您的计算机实际上是非常愚蠢的。 246 00:14:55,000 --> 00:14:57,000 你的电脑只能理解“0”和“1, 247 00:14:57,000 --> 00:15:01,000 所以实际上在第一台计算机的人通常编程 248 00:15:01,000 --> 00:15:04,000 用“0”和“1秒,但现在不是了,感谢上帝。 249 00:15:04,000 --> 00:15:07,000 我们没有记忆0和1的序列 250 00:15:07,000 --> 00:15:10,000 for循环或一个while循环等。 251 00:15:10,000 --> 00:15:13,000 这就是为什么我们有一个编译器。 252 00:15:13,000 --> 00:15:17,000 编译器只是它基本上是翻译的C代码, 253 00:15:17,000 --> 00:15:21,000 在我们的例子中,您的计算机就会明白的语言, 254 00:15:21,000 --> 00:15:25,000 这是目标代码,我们正在使用的编译器, 255 00:15:25,000 --> 00:15:30,000 被称为铛,所以这实际上是铛的符号。 256 00:15:30,000 --> 00:15:33,000 当你有你的程序,你必须做两件事情。 257 00:15:33,000 --> 00:15:37,000 首先,你必须编译程序,然后你运行你的程序。 258 00:15:37,000 --> 00:15:41,000 编译你的程序,你有很多的选择这样做。 259 00:15:41,000 --> 00:15:44,000 第一个是做铛program.c 260 00:15:44,000 --> 00:15:47,000 在该程序是你的程序的名称。 261 00:15:47,000 --> 00:15:51,000 在这种情况下,你可以看到,他们只是说“嘿,编译我的程序。” 262 00:15:51,000 --> 00:15:56,000 你不是说:“我想我的程序”或其他任何名称。 263 00:15:56,000 --> 00:15:58,000 >> 第二个选项是给你的程序的名称。 264 00:15:58,000 --> 00:16:02,000 你可以说铛-O和你想要的名称 265 00:16:02,000 --> 00:16:06,000 可执行文件被命名为,然后program.c。 266 00:16:06,000 --> 00:16:11,000 而且你还可以做程序,以及如何在第2例 267 00:16:11,000 --> 00:16:15,000 我把C,我只有在第三个节目吗? 268 00:16:15,000 --> 00:16:18,000 是啊,你不应该付诸表决。C时使用。 269 00:16:18,000 --> 00:16:22,000 否则,编译器实际上是要骂你的。 270 00:16:22,000 --> 00:16:24,000 而且,我不知道,如果你们还记得, 271 00:16:24,000 --> 00:16:29,000 但很多时候,我们也使用lcs50或-LM。 272 00:16:29,000 --> 00:16:31,000 这就是所谓的链接。 273 00:16:31,000 --> 00:16:35,000 它只是告诉编译器,你将使用这些库就在那里, 274 00:16:35,000 --> 00:16:39,000 所以如果你想使用cs50.h,你必须输入 275 00:16:39,000 --> 00:16:43,000 铛program.c,lcs50。 276 00:16:43,000 --> 00:16:45,000 如果你不这样做,编译器不会知道 277 00:16:45,000 --> 00:16:50,000 你使用了这些功能cs50.h. 278 00:16:50,000 --> 00:16:52,000 当你要运行你的程序,你有2个选择。 279 00:16:52,000 --> 00:16:57,000 如果你没有铛program.c你没有给你的程序的名称。 280 00:16:57,000 --> 00:17:01,000 您必须运行使用。/ a.out的。 281 00:17:01,000 --> 00:17:06,000 a.out是一个标准的名称,铛使您的程序,如果你不给它一个名字。 282 00:17:06,000 --> 00:17:11,000 否则,你要做的/计划,如果你在你的程序出了名的, 283 00:17:11,000 --> 00:17:15,000 ,如果你还做程序的名称,程序会得到 284 00:17:15,000 --> 00:17:23,000 已经进行编程的C文件相同的名称。 285 00:17:23,000 --> 00:17:26,000 然后,我们谈到数据类型和数据。 286 00:17:26,000 --> 00:17:31,000 >> 数据类型基本上是同样的事情,他们使用的小盒子 287 00:17:31,000 --> 00:17:35,000 存储值,所以数据类型实际上是一样的小宠物。 288 00:17:35,000 --> 00:17:39,000 他们有各种规模和类型。 289 00:17:39,000 --> 00:17:43,000 我不知道这个比喻是有道理的。 290 00:17:43,000 --> 00:17:46,000 数据的大小实际上是依赖于机器的体系架构。 291 00:17:46,000 --> 00:17:49,000 ,我在这里要告诉所有的数据大小 292 00:17:49,000 --> 00:17:53,000 实际上是一个32位的机器,这是我们的设备的情况下, 293 00:17:53,000 --> 00:17:56,000 但如果你是真正的编码您的Mac或Windows 294 00:17:56,000 --> 00:17:59,000 可能你有一个64位的机器, 295 00:17:59,000 --> 00:18:03,000 所以请记住,数据的大小,我要在这里展示 296 00:18:03,000 --> 00:18:06,000 是为32位的机器上。 297 00:18:06,000 --> 00:18:08,000 第一个,我们看到的是一个int, 298 00:18:08,000 --> 00:18:10,000 这是非常简单的。 299 00:18:10,000 --> 00:18:13,000 您可以使用int来存储一个整数。 300 00:18:13,000 --> 00:18:16,000 我们也看到了字符,字符。 301 00:18:16,000 --> 00:18:20,000 如果你想使用一个字母或一个小符号,你可能会使用一个char。 302 00:18:20,000 --> 00:18:26,000 一个char 1个字节,这意味着8位,如乐喜说。 303 00:18:26,000 --> 00:18:31,000 基本上我们有一个ASCII表有256个 304 00:18:31,000 --> 00:18:34,000 可能的0和1的组合, 305 00:18:34,000 --> 00:18:37,000 然后当你输入一个字符,它的翻译 306 00:18:37,000 --> 00:18:44,000 的字符输入你一个数字,你有ASCII表中,如乐喜说。 307 00:18:44,000 --> 00:18:48,000 我们也有浮动,我们用它来存储的十进制数。 308 00:18:48,000 --> 00:18:53,000 例如,如果你想选择3.14,你要使用浮动 309 00:18:53,000 --> 00:18:55,000 或双具有更高的精度。 310 00:18:55,000 --> 00:18:57,000 一个浮动有4个字节。 311 00:18:57,000 --> 00:19:01,000 双有8个字节,所以,唯一的区别是精度。 312 00:19:01,000 --> 00:19:04,000 我们也有很长的,用于整数, 313 00:19:04,000 --> 00:19:09,000 你可以看到一个int和一个长为一个32位的机器具有相同的大小, 314 00:19:09,000 --> 00:19:13,000 所以它不会真正有意义的使用在一个32位的机器。 315 00:19:13,000 --> 00:19:17,000 >> 但是,如果你使用的是Mac和64位的机器,实际上是一个长有大小8, 316 00:19:17,000 --> 00:19:19,000 所以它确实依赖于体系结构。 317 00:19:19,000 --> 00:19:22,000 对于32位的机器,它没有意义的真正使用长。 318 00:19:22,000 --> 00:19:25,000 再长长,另一方面,有8个字节, 319 00:19:25,000 --> 00:19:30,000 所以这是非常好的,如果你想有一个较长的整数。 320 00:19:30,000 --> 00:19:34,000 最后,我们有字符串,它实际上是一个char *, 321 00:19:34,000 --> 00:19:37,000 这是一个指向字符。 322 00:19:37,000 --> 00:19:40,000 这是很容易想到的字符串的长度将是 323 00:19:40,000 --> 00:19:42,000 的字符数,你必须有, 324 00:19:42,000 --> 00:19:45,000 但实际上本身的char * 325 00:19:45,000 --> 00:19:49,000 有一个指针到一个字符,这是4个字节的大小。 326 00:19:49,000 --> 00:19:52,000 一个char *的大小为4个字节。 327 00:19:52,000 --> 00:19:56,000 这不要紧,如果你有一个小单词或一个字母或任何东西。 328 00:19:56,000 --> 00:19:58,000 这将是4个字节。 329 00:19:58,000 --> 00:20:01,000 我们也学到了一点关于铸造, 330 00:20:01,000 --> 00:20:04,000 所以,你可以看到,如果你有,例如,一个程序,说: 331 00:20:04,000 --> 00:20:08,000 INT X = 3,然后输出(“%d”,X / 2) 332 00:20:08,000 --> 00:20:12,000 你们知道它会在屏幕上打印吗? 333 00:20:12,000 --> 00:20:14,000 >> 有人吗?>> [学生] 2。 334 00:20:14,000 --> 00:20:16,000 1 >> 1,是的。 335 00:20:16,000 --> 00:20:20,000 当你做3/2 1.5, 336 00:20:20,000 --> 00:20:24,000 但由于我们使用的是一个整数,它会忽略的小数部分, 337 00:20:24,000 --> 00:20:26,000 你将有1。 338 00:20:26,000 --> 00:20:29,000 如果你不希望发生这种情况你可以做什么,例如, 339 00:20:29,000 --> 00:20:33,000 声明持股量Y = X。 340 00:20:33,000 --> 00:20:40,000 则X为3现在要在y是3.000。 341 00:20:40,000 --> 00:20:44,000 然后你就可以打印的Y / 2。 342 00:20:44,000 --> 00:20:50,000 其实,我应该有一个2。那边。 343 00:20:50,000 --> 00:20:55,000 它会做3.00/2.00, 344 00:20:55,000 --> 00:20:58,000 你会得到1.5。 345 00:20:58,000 --> 00:21:06,000 我们有这个.2 f只要求2的小数部分的十进制单位。 346 00:21:06,000 --> 00:21:12,000 如果你有0.3 f,它实际上有1.500。 347 00:21:12,000 --> 00:21:16,000 如果它是2的为1.50。 348 00:21:16,000 --> 00:21:18,000 我们也有这样的情况在这里。 349 00:21:18,000 --> 00:21:22,000 如果你这样做持股量X = 3.14,那么你的printf x 350 00:21:22,000 --> 00:21:24,000 你将得到3.14。 351 00:21:24,000 --> 00:21:29,000 如果你做x = x的整数, 352 00:21:29,000 --> 00:21:34,000 这意味着把X作为一个int,则在打印x现在 353 00:21:34,000 --> 00:21:36,000 你将不得不3.00。 354 00:21:36,000 --> 00:21:38,000 这是否有意义吗? 355 00:21:38,000 --> 00:21:41,000 因为你第一次治疗x为整数,所以你忽略的小数部分, 356 00:21:41,000 --> 00:21:45,000 然后你印刷。 357 00:21:45,000 --> 00:21:47,000 最后,你也可以做到这一点, 358 00:21:47,000 --> 00:21:52,000 X = 65,那么你声明一个char C = X, 359 00:21:52,000 --> 00:21:56,000 然后,如果你打印的C,你实际上是在将要得到的 360 00:21:56,000 --> 00:21:59,000 A,所以基本上你在这里做什么 361 00:21:59,000 --> 00:22:02,000 的整数转换成字符, 362 00:22:02,000 --> 00:22:05,000 就像ASCII表。 363 00:22:05,000 --> 00:22:08,000 我们还谈到数学运算符。 364 00:22:08,000 --> 00:22:14,000 他们中的大多数都非常简单,+, - ,*,/, 365 00:22:14,000 --> 00:22:20,000 我们谈到的mod,这是一个部门,剩下的2个号码。 366 00:22:20,000 --> 00:22:23,000 如果你有10%3,例如, 367 00:22:23,000 --> 00:22:27,000 这意味着10除以3,其余的是什么? 368 00:22:27,000 --> 00:22:30,000 这将是1,所以它实际上是非常有用的了很多的节目。 369 00:22:30,000 --> 00:22:38,000 对于维琼内尔和凯撒,我敢肯定,如果大家都使用MOD。 370 00:22:38,000 --> 00:22:43,000 关于数学运算符时,必须非常小心,将*和/。 371 00:22:43,000 --> 00:22:48,000 >> 例如,如果你这样做(3/2)* 2,你会得到吗? 372 00:22:48,000 --> 00:22:50,000 [学生] 2。 373 00:22:50,000 --> 00:22:54,000 呀,2,因为二分之三是要为1.5, 374 00:22:54,000 --> 00:22:57,000 但因为你是做2个整数之间的操作 375 00:22:57,000 --> 00:22:59,000 其实你只是要考虑, 376 00:22:59,000 --> 00:23:03,000 1 * 2,然后将是2,所以要非常非常小心 377 00:23:03,000 --> 00:23:07,000 做数学运算时,整数,因为 378 00:23:07,000 --> 00:23:12,000 你可能会得到2 = 3,在这种情况下。 379 00:23:12,000 --> 00:23:14,000 也非常小心的优先级。 380 00:23:14,000 --> 00:23:21,000 通常,你应该使用括号,要确保你知道你在做什么。 381 00:23:21,000 --> 00:23:27,000 一些有用的快捷键,当然,一个是我+ +或i + = 1 382 00:23:27,000 --> 00:23:30,000 或使用+ =。 383 00:23:30,000 --> 00:23:34,000 这是同样的事情,做I = I + 1。 384 00:23:34,000 --> 00:23:39,000 你也可以做我 - 我 - = 1, 385 00:23:39,000 --> 00:23:42,000 这是同样的事情I = -1, 386 00:23:42,000 --> 00:23:46,000 东西你们使用了很多在for循环中,至少。 387 00:23:46,000 --> 00:23:52,000 此外,*,* =,如果你这样做了,例如,如果你使用, 388 00:23:52,000 --> 00:23:57,000 *的话说,I = I * 2 = 2是同样的事情, 389 00:23:57,000 --> 00:23:59,000 同样的事情为师。 390 00:23:59,000 --> 00:24:08,000 如果你做的I / = 2,I = I / 2,这是同样的事情。 391 00:24:08,000 --> 00:24:10,000 >> 现在功能。 392 00:24:10,000 --> 00:24:13,000 你们的经验教训,其功能是一个很好的策略,以节省代码 393 00:24:13,000 --> 00:24:16,000 而你编程,所以如果你要执行相同的任务 394 00:24:16,000 --> 00:24:20,000 在代码中一遍又一遍,可能您要使用的功能 395 00:24:20,000 --> 00:24:25,000 只是让你不必一遍又一遍的复制和粘贴代码。 396 00:24:25,000 --> 00:24:28,000 其实,主要是一个函数,当我告诉你一个函数的格式 397 00:24:28,000 --> 00:24:32,000 你会看到,这是很明显的。 398 00:24:32,000 --> 00:24:35,000 我们还可以使用一些库的功能, 399 00:24:35,000 --> 00:24:39,000 例如,printf,进球,这是从CS50库, 400 00:24:39,000 --> 00:24:43,000 和其他功能,如TOUPPER。 401 00:24:43,000 --> 00:24:46,000 所有这些功能实际上是实现其他图书馆, 402 00:24:46,000 --> 00:24:49,000 当你把这些系绳文件的开始你的程序 403 00:24:49,000 --> 00:24:53,000 你说可以请你给我的代码为这些功能 404 00:24:53,000 --> 00:24:57,000 所以我没有实现他们自己吗? 405 00:24:57,000 --> 00:25:00,000 你也可以编写自己的函数,因此,当你开始编程 406 00:25:00,000 --> 00:25:04,000 你会意识到,图书馆不具有的所有功能,你需要的。 407 00:25:04,000 --> 00:25:10,000 例如,我们在过去的pset,写,画,加密和查找, 408 00:25:10,000 --> 00:25:13,000 这是非常,非常重要的是要能写功能 409 00:25:13,000 --> 00:25:17,000 因为他们是有用的,我们使用他们所有的时间编程, 410 00:25:17,000 --> 00:25:19,000 这样可以节省大量的代码。 411 00:25:19,000 --> 00:25:21,000 函数的格式是这一个。 412 00:25:21,000 --> 00:25:24,000 我们开始返回类型。返回类型是什么? 413 00:25:24,000 --> 00:25:27,000 这只是当你的函数会返回。 414 00:25:27,000 --> 00:25:29,000 如果你有一个函数,例如,阶乘, 415 00:25:29,000 --> 00:25:31,000 是要计算的阶乘的整数, 416 00:25:31,000 --> 00:25:34,000 可能它会返回一个整数。 417 00:25:34,000 --> 00:25:37,000 然后返回类型为int。 418 00:25:37,000 --> 00:25:41,000 的printf实际上有一个返回类型为void 419 00:25:41,000 --> 00:25:43,000 因为你不返回任何东西。 420 00:25:43,000 --> 00:25:45,000 你只是在屏幕上打印的东西 421 00:25:45,000 --> 00:25:48,000 和退出的功能之后。 422 00:25:48,000 --> 00:25:51,000 然后,你的功能,你可以选择的名称。 423 00:25:51,000 --> 00:25:55,000 您应该有点合理,如不选择一个名称,如某某 424 00:25:55,000 --> 00:25:58,000 或像X2F。 425 00:25:58,000 --> 00:26:02,000 尝试弥补的名称是有道理的。 426 00:26:02,000 --> 00:26:04,000 >> 例如,如果它的因子,说阶乘的。 427 00:26:04,000 --> 00:26:08,000 如果要画的东西,它是一个函数,将它命名画。 428 00:26:08,000 --> 00:26:11,000 然后我们有参数,也被称为参数, 429 00:26:11,000 --> 00:26:14,000 这是像你的函数所需要的资源, 430 00:26:14,000 --> 00:26:17,000 从你的代码来执行其任务。 431 00:26:17,000 --> 00:26:20,000 如果你要计算一个数的阶乘 432 00:26:20,000 --> 00:26:23,000 可能你需要有一个数字来计算阶乘。 433 00:26:23,000 --> 00:26:27,000 的论点,你将有一个是这个数字本身。 434 00:26:27,000 --> 00:26:31,000 那么它会做一些事情,结束时,返回的值 435 00:26:31,000 --> 00:26:35,000 除非它是一个void函数。 436 00:26:35,000 --> 00:26:37,000 让我们看一个例子。 437 00:26:37,000 --> 00:26:40,000 如果我想编写一个函数,总结一个整数数组中的所有数字, 438 00:26:40,000 --> 00:26:43,000 首先,返回类型为int 439 00:26:43,000 --> 00:26:46,000 因为我有一个整数数组。 440 00:26:46,000 --> 00:26:51,000 然后,我要的功能名称,如sumArray, 441 00:26:51,000 --> 00:26:54,000 然后是怎么回事本身采取的阵列,为int NUMS, 442 00:26:54,000 --> 00:26:58,000 然后长度的数组,所以我知道我有多少个数字来概括。 443 00:26:58,000 --> 00:27:02,000 然后,我要初始化的变量称为总和,例如,为0, 444 00:27:02,000 --> 00:27:08,000 每次我看到一个数组中的元素,我把它添加到总和,所以我做了一个for循环。 445 00:27:08,000 --> 00:27:15,000 就像乐喜说,你INT I = 0,I <长度和i + +。 446 00:27:15,000 --> 00:27:20,000 数组中的每一个元素,我所做的次数总和+ = [I], 447 00:27:20,000 --> 00:27:24,000 然后我又回到了一笔,所以这是很简单的,这样可以节省大量的代码 448 00:27:24,000 --> 00:27:28,000 如果您使用此功能了很多次。 449 00:27:28,000 --> 00:27:32,000 然后,我们看看条件。 450 00:27:32,000 --> 00:27:38,000 我们有,否则,否则,如果。 451 00:27:38,000 --> 00:27:42,000 让我们来看看者的区别是什么。 452 00:27:42,000 --> 00:27:45,000 看一看在这些代码。它们之间的区别是什么? 453 00:27:45,000 --> 00:27:49,000 第一个基本的代码要你告诉 454 00:27:49,000 --> 00:27:51,000 一个数是否为+, - ,或0。 455 00:27:51,000 --> 00:27:55,000 第一个说,如果> 0,则它的正面。 456 00:27:55,000 --> 00:28:00,000 如果它是= 0,那么它是0,并且,如果是<0,那么它的负。 457 00:28:00,000 --> 00:28:04,000 >> 和其他人正在做的,如果,否则,如果,否则。 458 00:28:04,000 --> 00:28:07,000 两者之间的区别是,这实际上是将 459 00:28:07,000 --> 00:28:13,000 如果> 0,<0或= 0三次, 460 00:28:13,000 --> 00:28:17,000 所以,如果你有2号,例如,它会到这里来,并说 461 00:28:17,000 --> 00:28:21,000 如果(X> 0),它会说“是”,所以我打印阳性。 462 00:28:21,000 --> 00:28:25,000 但是,即使我知道,这是> 0,它不会是0或<0 463 00:28:25,000 --> 00:28:29,000 我仍然会做的是0,<0, 464 00:28:29,000 --> 00:28:33,000 所以实际上,我要进去,如果我没有到 465 00:28:33,000 --> 00:28:38,000 因为我已经知道,它不是要满足这些条件。 466 00:28:38,000 --> 00:28:41,000 我可以使用,否则的话,else语句。 467 00:28:41,000 --> 00:28:45,000 它基本上是说,如果X = 0我打印的积极。 468 00:28:45,000 --> 00:28:48,000 如果不是的话,我也对此进行测试。 469 00:28:48,000 --> 00:28:51,000 如果这是我要做到这一点。 470 00:28:51,000 --> 00:28:54,000 基本上,如果我有X = 2,你会说 471 00:28:54,000 --> 00:28:57,000 如果(X> 0),是的,打印本。 472 00:28:57,000 --> 00:29:00,000 现在,我知道,这是> 0,它满足了第一,如果 473 00:29:00,000 --> 00:29:02,000 我什至不运行此代码。 474 00:29:02,000 --> 00:29:09,000 的代码运行速度更快,实际上,3倍的速度,如果你用这个。 475 00:29:09,000 --> 00:29:11,000 我们还了解到,和(或)。 476 00:29:11,000 --> 00:29:15,000 我不会去,因为亚力克西斯已经谈到他们。 477 00:29:15,000 --> 00:29:17,000 这只是&&和| |运算符。 478 00:29:17,000 --> 00:29:21,000 >> 我唯一​​会说的时候要小心,有3个条件。 479 00:29:21,000 --> 00:29:24,000 使用括号,因为当你有一个条件,这是非常令人困惑的 480 00:29:24,000 --> 00:29:27,000 和其他的一个或另一个。 481 00:29:27,000 --> 00:29:30,000 使用括号只是为了确保你的条件是有意义的 482 00:29:30,000 --> 00:29:34,000 因为在这种情况下,例如,你可以想像, 483 00:29:34,000 --> 00:29:38,000 它可以是第一个条件和一个或另一个 484 00:29:38,000 --> 00:29:41,000 或2中所组合的条件和 485 00:29:41,000 --> 00:29:45,000 或第三人,所以,只是小心些而已。 486 00:29:45,000 --> 00:29:48,000 最后,我们谈到了开关。 487 00:29:48,000 --> 00:29:53,000 交换机是非常有用的,当你有一个变量。 488 00:29:53,000 --> 00:29:55,000 比方说,你有一个变量如:n 489 00:29:55,000 --> 00:29:59,000 这些情况下,可以是0,1,或2,并且对于每个 490 00:29:59,000 --> 00:30:01,000 你要去执行一项任务。 491 00:30:01,000 --> 00:30:04,000 你可以说开关的变量,它表明, 492 00:30:04,000 --> 00:30:08,000 像值1的值,然后是我要做到这一点, 493 00:30:08,000 --> 00:30:12,000 然后我打破,这意味着在任何其他情况下,我不会看 494 00:30:12,000 --> 00:30:15,000 因为我们已经满足这种情况下, 495 00:30:15,000 --> 00:30:20,000 然后value2和等等,我也可以有一个默认的开关。 496 00:30:20,000 --> 00:30:24,000 这意味着,如果它不能满足的情况下,我 497 00:30:24,000 --> 00:30:29,000 我做别的事情,但是这是可选的。 498 00:30:29,000 --> 00:30:36,000 这一切对我来说。现在,让我们汤米。 499 00:30:36,000 --> 00:30:41,000 好吧,这将是第3周上下。 500 00:30:41,000 --> 00:30:45,000 这些都是一些我们的主题将涵盖,密码,范围,数组,等等。 501 00:30:45,000 --> 00:30:49,000 一个快字上的密码。我们不会敲定这个家。 502 00:30:49,000 --> 00:30:52,000 >> 我们这样做的pset 2,但测验,请确保您知道其中的差别 503 00:30:52,000 --> 00:30:54,000 之间的凯撒密码和维琼内尔的密码, 504 00:30:54,000 --> 00:30:57,000 如何这些密码的工作是什么样子的加密 505 00:30:57,000 --> 00:30:59,000 和解密使用这些密码的文本。 506 00:30:59,000 --> 00:31:03,000 请记住,简单的恺撒密码的每个字符的旋转相同的量, 507 00:31:03,000 --> 00:31:06,000 确保您MOD由数个英文字母。 508 00:31:06,000 --> 00:31:09,000 和维琼内尔密码,在另一方面,每个字符旋转 509 00:31:09,000 --> 00:31:12,000 不同的金额,而不是说 510 00:31:12,000 --> 00:31:15,000 每一个字符3维琼内尔旋转,旋转每个字符 511 00:31:15,000 --> 00:31:17,000 由不同的金额,根据一些关键字 512 00:31:17,000 --> 00:31:20,000 中的关键字,其中每个字母代表了一些不同的量 513 00:31:20,000 --> 00:31:26,000 旋转清晰的文本。 514 00:31:26,000 --> 00:31:28,000 让我们先说说变量的作用域。 515 00:31:28,000 --> 00:31:30,000 有2种不同类型的变量。 516 00:31:30,000 --> 00:31:33,000 我们有局部变量,而这些将要定义的 517 00:31:33,000 --> 00:31:36,000 外的主要或以外的任何函数或块, 518 00:31:36,000 --> 00:31:39,000 和这些将在你的程序中的任何地方访问。 519 00:31:39,000 --> 00:31:41,000 如果你有一个函数,在该函数中是一个while循环 520 00:31:41,000 --> 00:31:44,000 大的全局变量的访问无处不在。 521 00:31:44,000 --> 00:31:48,000 ,另一方面,是一个局部变量的作用域的地方,它被定义。 522 00:31:48,000 --> 00:31:53,000 >> 如果你有一个函数,例如,我们有这个函数g, 523 00:31:53,000 --> 00:31:56,000 和内部的g是一个变量,在这里称为y, 524 00:31:56,000 --> 00:31:58,000 这意味着,这是一个局部变量。 525 00:31:58,000 --> 00:32:00,000 即使这个变量被称为y 526 00:32:00,000 --> 00:32:03,000 这个变量是所谓的Y这两个函数 527 00:32:03,000 --> 00:32:06,000 不知道对方的局部变量。 528 00:32:06,000 --> 00:32:10,000 另一方面,在这里,我们说X = 5, 529 00:32:10,000 --> 00:32:12,000 这范围以外的任何函数。 530 00:32:12,000 --> 00:32:16,000 它的主要范围以外的,所以这是一个全局变量。 531 00:32:16,000 --> 00:32:20,000 这意味着,这些功能里面,当我说X - 或x + + 532 00:32:20,000 --> 00:32:26,000 我访问相同的x,,这y和这家Y是不同的变量。 533 00:32:26,000 --> 00:32:30,000 这是一个全局变量和局部变量之间的差异。 534 00:32:30,000 --> 00:32:33,000 就设计而言,有时,它可能是一个更好的主意 535 00:32:33,000 --> 00:32:37,000 保持局部变量时,你可能可以 536 00:32:37,000 --> 00:32:39,000 因为有一堆全局变量可以得到真正的混乱。 537 00:32:39,000 --> 00:32:42,000 如果你有一堆的功能,所有的修改同样的事情, 538 00:32:42,000 --> 00:32:45,000 你可能会忘记此功能,如果不慎修改, 539 00:32:45,000 --> 00:32:47,000 这功能不知道这一点, 540 00:32:47,000 --> 00:32:50,000 它变得相当混乱,因为你得到更多的代码。 541 00:32:50,000 --> 00:32:53,000 保持局部变量时,你可能可以 542 00:32:53,000 --> 00:32:56,000 是刚刚好的设计。 543 00:32:56,000 --> 00:33:00,000 阵列,请记住,仅仅是同一类型的元素的列表。 544 00:33:00,000 --> 00:33:04,000 里面的CI不能有一个列表,如1,2.0,你好。 545 00:33:04,000 --> 00:33:06,000 我们不能做到这一点。 546 00:33:06,000 --> 00:33:11,000 >> 当在C我们声明一个数组的所有元素必须是相同的类型。 547 00:33:11,000 --> 00:33:14,000 在这里,我有3个整数的数组。 548 00:33:14,000 --> 00:33:18,000 在这里,我有数组的长度,但如果我只是在此语法声明 549 00:33:18,000 --> 00:33:21,000 我指定所有的元素都是我并没有从技术上需要这个3。 550 00:33:21,000 --> 00:33:25,000 编译器足够聪明,找出数组应为多大。 551 00:33:25,000 --> 00:33:28,000 现在,当我想获取或设置一个数组的值 552 00:33:28,000 --> 00:33:30,000 这是的语法来做到这一点。 553 00:33:30,000 --> 00:33:33,000 这实际上修改的第二个元素的数组,因为记得, 554 00:33:33,000 --> 00:33:36,000 编号从0开始,而不是1。 555 00:33:36,000 --> 00:33:42,000 如果我想读取该值,我可以这样说X =数组[1]。 556 00:33:42,000 --> 00:33:44,000 或者,如果我想设置该值,如我在这里做什么, 557 00:33:44,000 --> 00:33:47,000 我可以说,数组[1] = 4。 558 00:33:47,000 --> 00:33:50,000 这通过其索引访问元素 559 00:33:50,000 --> 00:33:52,000 或他们的位置,他们是在数组中, 560 00:33:52,000 --> 00:33:57,000 从0开始,上市。 561 00:33:57,000 --> 00:34:00,000 我们也可以有数组的数组 562 00:34:00,000 --> 00:34:03,000 这就是所谓的多维数组。 563 00:34:03,000 --> 00:34:05,000 当我们有一个多维数组 564 00:34:05,000 --> 00:34:07,000 这意味着我们可以有类似的行和列, 565 00:34:07,000 --> 00:34:11,000 而这仅仅是一个可视化的思考方式。 566 00:34:11,000 --> 00:34:14,000 当我有一个多维数组,这意味着我要开始需要 567 00:34:14,000 --> 00:34:17,000 超过1指数,因为如果我有一个网格 568 00:34:17,000 --> 00:34:19,000 只是说你在哪个行并没有给我们一个数字。 569 00:34:19,000 --> 00:34:22,000 这真的只是给我们一个数字列表。 570 00:34:22,000 --> 00:34:25,000 比方说,我有这样的阵列。 571 00:34:25,000 --> 00:34:30,000 我有一个数组称为网格,和我说这是2行3列, 572 00:34:30,000 --> 00:34:32,000 所以这是一个可视化的方式。 573 00:34:32,000 --> 00:34:37,000 当我说我想要得到的元素[1] [2] 574 00:34:37,000 --> 00:34:41,000 这意味着,因为这些是第一,然后列行 575 00:34:41,000 --> 00:34:44,000 我要跳转到第1行,因为我说了一句。 576 00:34:44,000 --> 00:34:49,000 >> 然后我到这里来,到第2列,我要得到的值是6。 577 00:34:49,000 --> 00:34:51,000 有意义吗? 578 00:34:51,000 --> 00:34:55,000 多维数组,请记住,在技术上是一个数组的数组。 579 00:34:55,000 --> 00:34:57,000 我们可以有数组的数组的数组。 580 00:34:57,000 --> 00:35:00,000 我们可以继续下去,但一个真正的方式来思考 581 00:35:00,000 --> 00:35:03,000 这是怎么被解雇,这是怎么回事,是形象化 582 00:35:03,000 --> 00:35:09,000 在这样的一个网格。 583 00:35:09,000 --> 00:35:12,000 当我们通过阵列的功能,他们会表现 584 00:35:12,000 --> 00:35:16,000 当我们通过定期的变量功能有点不同 585 00:35:16,000 --> 00:35:18,000 像传递一个int或float。 586 00:35:18,000 --> 00:35:21,000 当我们传递了一个int或char或任何其他数据类型 587 00:35:21,000 --> 00:35:24,000 我们刚接过来一看,如果修改 588 00:35:24,000 --> 00:35:28,000 该变量的值的变化不会传播 589 00:35:28,000 --> 00:35:32,000 到调用函数。 590 00:35:32,000 --> 00:35:35,000 有了一个数组,在另一方面,这将发生。 591 00:35:35,000 --> 00:35:39,000 如果我通过在阵列中的一些功能,该功能改变的一些内容, 592 00:35:39,000 --> 00:35:43,000 我回来的时候调用它的函数 593 00:35:43,000 --> 00:35:47,000 我的数组是不同的,为的词汇 594 00:35:47,000 --> 00:35:50,000 是数组是通过引用传递,我们将在后面看到。 595 00:35:50,000 --> 00:35:53,000 这是关系到如何指针的工作,而这些基本数据类型, 596 00:35:53,000 --> 00:35:55,000 另一方面,通过值传递。 597 00:35:55,000 --> 00:35:59,000 >> 我们可以认为那是一些变量的副本,然后通过在副本中。 598 00:35:59,000 --> 00:36:01,000 不要紧,我们做什么与该变量。 599 00:36:01,000 --> 00:36:06,000 调用函数将不知道它被改变了。 600 00:36:06,000 --> 00:36:10,000 数组是在这方面,不同的只是一点点。 601 00:36:10,000 --> 00:36:13,000 例如,正如我们刚才看到的,主要是简单的功能 602 00:36:13,000 --> 00:36:15,000 可以在两个参数。 603 00:36:15,000 --> 00:36:20,000 第一个参数的主要功能是ARGC,或参数的个数, 604 00:36:20,000 --> 00:36:23,000 第二个参数被称为ARGV, 605 00:36:23,000 --> 00:36:27,000 这些参数的实际值。 606 00:36:27,000 --> 00:36:30,000 比方说,我有一个程序叫this.c, 607 00:36:30,000 --> 00:36:34,000 和我说这一点,我要在命令行中运行此。 608 00:36:34,000 --> 00:36:38,000 现在在某些参数传递到我的计划,称这 609 00:36:38,000 --> 00:36:42,000 我可以这样说,/这是CS 50。 610 00:36:42,000 --> 00:36:45,000 这是我们想象的大卫每天都在做终端。 611 00:36:45,000 --> 00:36:48,000 但是,现在该程序的主函数内的 612 00:36:48,000 --> 00:36:52,000 这些值,因此argc是4。 613 00:36:52,000 --> 00:36:56,000 这可能是有点混乱,因为我们真的只有通过在CS 50。 614 00:36:56,000 --> 00:36:58,000 这是只有3个。 615 00:36:58,000 --> 00:37:02,000 但请记住,第一个元素的argv的第一个参数 616 00:37:02,000 --> 00:37:05,000 是函数本身的名称。 617 00:37:05,000 --> 00:37:07,190 因此,这意味着我们有4个东西在这里, 618 00:37:07,190 --> 00:37:10,530 及第一要素将是/这。 619 00:37:10,530 --> 00:37:12,970 这将被表示为一个字符串。 620 00:37:12,970 --> 00:37:18,590 那么剩下的元素是我们的程序名后键入。 621 00:37:18,590 --> 00:37:22,720 因此,正如顺便说一句,因为我们在pset中2中所看到的, 622 00:37:22,720 --> 00:37:28,780 记住该字符串50≠50的整数。 623 00:37:28,780 --> 00:37:32,520 因此,我们不能说些什么,“X = ARGV 3。 624 00:37:32,520 --> 00:37:36,470 >> 这只是不会是有道理的,因为这是一个字符串,这是一个整数。 625 00:37:36,470 --> 00:37:38,510 所以,如果你要转换之间的2,请记住,我们要 626 00:37:38,510 --> 00:37:40,810 有这种神奇的功能,称为ATOI。 627 00:37:40,810 --> 00:37:46,270 这需要一个字符串并返回该字符串表示的整数内。 628 00:37:46,270 --> 00:37:48,360 所以这是一个容易犯的错误的测验, 629 00:37:48,360 --> 00:37:51,590 只是在想,这会自动将正确的类型。 630 00:37:51,590 --> 00:37:53,860 但我们知道,这将永远是字符串 631 00:37:53,860 --> 00:38:00,920 即使只包含字符串的整数或一个字符或一个浮子。 632 00:38:00,920 --> 00:38:03,380 所以,现在让我们来谈谈运行时间。 633 00:38:03,380 --> 00:38:06,700 当我们做这些疯狂的事情,所有这些算法, 634 00:38:06,700 --> 00:38:11,580 它变得非常有用的,要问的问题,“他们需要多长时间?” 635 00:38:11,580 --> 00:38:15,500 我们表示,所谓的渐近符号。 636 00:38:15,500 --> 00:38:18,430 因此,这意味着 - 好,让我们说,我们给我们的算法 637 00:38:18,430 --> 00:38:20,840 一些真的,真的,真的很大的投入。 638 00:38:20,840 --> 00:38:23,840 我们要问的问题,“如何是将要采取的吗? 639 00:38:23,840 --> 00:38:26,370 多少个步骤将需要运行我们的算法 640 00:38:26,370 --> 00:38:29,980 作为输入的函数的大小?“ 641 00:38:29,980 --> 00:38:33,080 因此,第一种方式我们可以形容运行时间是大澳 642 00:38:33,080 --> 00:38:35,380 这是我们的最坏情况下的运行时间。 643 00:38:35,380 --> 00:38:38,590 因此,如果我们要对数组进行排序,我们给我们的算法的一个数组 644 00:38:38,590 --> 00:38:41,000 时,应在升序降序排列, 645 00:38:41,000 --> 00:38:43,130 那将是最坏的情况。 646 00:38:43,130 --> 00:38:49,800 这是我们的最大长度的时间,我们的算法将采取的上限。 647 00:38:49,800 --> 00:38:54,740 在另一方面,本Ω是要描述的最佳情况下的运行时间。 648 00:38:54,740 --> 00:38:58,210 因此,如果我们给一个已排序的数组排序算法, 649 00:38:58,210 --> 00:39:00,940 排序需要多长时间? 650 00:39:00,940 --> 00:39:06,610 而这一点,然后,描述了一个运行时间的上下限。 651 00:39:06,610 --> 00:39:10,980 因此,这里有一些话,介绍一些常见的运行时间。 652 00:39:10,980 --> 00:39:13,120 这些是按升序排列。 653 00:39:13,120 --> 00:39:16,060 我们有最快的运行时间不变。 654 00:39:16,060 --> 00:39:19,800 >> 这意味着,无论有多少个元素,我们给我们的算法, 655 00:39:19,800 --> 00:39:22,280 不管有多大,我们的阵列,整理 656 00:39:22,280 --> 00:39:26,510 或做我们正在做的阵列将始终以相同的时间。 657 00:39:26,510 --> 00:39:30,270 因此,我们可以表示,只需用1,这是一个常数。 658 00:39:30,270 --> 00:39:32,410 我们也期待在数运行时间。 659 00:39:32,410 --> 00:39:34,800 因此,类似二进制搜索是对数, 660 00:39:34,800 --> 00:39:37,140 我们削减了问题的一半,每次 661 00:39:37,140 --> 00:39:40,970 然后事情就从那里获得更高的。 662 00:39:40,970 --> 00:39:43,580 如果你正在编写一个O任何阶乘的算法, 663 00:39:43,580 --> 00:39:47,850 你可能不应该认为这是你的日常工作​​。 664 00:39:47,850 --> 00:39:53,910 当我们比较的运行时间,重要的是要记住这些东西。 665 00:39:53,910 --> 00:39:57,760 所以,如果我有一个算法是O(N),而其他人 666 00:39:57,760 --> 00:40:03,590 有一个度为O(2n)的算法,这其实是渐近等价。 667 00:40:03,590 --> 00:40:06,590 因此,如果我们想象Ň像一百十亿元是一个很大的数字: 668 00:40:06,590 --> 00:40:13,090 所以,当我们比较一百十亿元的东西像一百十亿元+ 3, 669 00:40:13,090 --> 00:40:17,640 突然,3并没有真正使一个很大的区别了。 670 00:40:17,640 --> 00:40:20,980 这就是为什么我们要开始考虑这些事情是相等的。 671 00:40:20,980 --> 00:40:24,220 因此,这些常量在这里的事情,比如,有这2个,或加入3, 672 00:40:24,220 --> 00:40:27,180 这些仅仅是常数,而这些会下降。 673 00:40:27,180 --> 00:40:32,480 所以这就是为什么这些运行时间是相同的,说他们是O(n)的所有3。 674 00:40:32,480 --> 00:40:37,490 同样,如果我们有2个运行时间,比方说为O(n 3 + 2N²),我们可以添加 675 00:40:37,490 --> 00:40:42,070 + N,+ 7,然后我们有另一种运行时,只是Ø(N³)。 676 00:40:42,070 --> 00:40:46,290 再次,这些是相同的东西,因为这些 - 这些是不一样的。 677 00:40:46,290 --> 00:40:49,840 这是同样的事情,对不起。因此,这些都是一样的,因为 678 00:40:49,840 --> 00:40:53,090 这n³将主宰这个2N²。 679 00:40:53,090 --> 00:40:59,130 >> 什么是不一样的事情是,如果我们的运行时间,如O(N³)和O(N 2) 680 00:40:59,130 --> 00:41:02,820 因为这n³是远远大于这n 2。 681 00:41:02,820 --> 00:41:05,470 因此,如果我们的指数,突然开始啦, 682 00:41:05,470 --> 00:41:08,280 但是,当我们只是处理因素,因为我们是在这里, 683 00:41:08,280 --> 00:41:12,810 那么它不会的问题,因为他们只是要辍学。 684 00:41:12,810 --> 00:41:16,760 让我们来看看到目前为止,我们已经看到的一些算法 685 00:41:16,760 --> 00:41:19,260 并谈谈它们的运行时间。 686 00:41:19,260 --> 00:41:23,850 第一种方法寻找一些在列表中,我们所看到的,是线性搜索。 687 00:41:23,850 --> 00:41:26,950 而实施的是超级简单的线性搜索。 688 00:41:26,950 --> 00:41:30,490 我们只是有一个列表,我们要看看在列表中的每一个元素 689 00:41:30,490 --> 00:41:34,260 直到我们找到的数量,我们要寻找的。 690 00:41:34,260 --> 00:41:38,370 因此,这意味着,在最坏的情况下,这为O(n)。 691 00:41:38,370 --> 00:41:40,860 和这里,最坏的情况下可能是,如果该元素是 692 00:41:40,860 --> 00:41:45,710 最后一个元素,然后使用线性搜索,我们来看看在每一个元素 693 00:41:45,710 --> 00:41:50,180 直到我们得到的最后一个知道,它实际上是在列表中。 694 00:41:50,180 --> 00:41:52,910 我们不能就这样放弃半说,“这是可能不存在。” 695 00:41:52,910 --> 00:41:55,980 我们来看看整个事情的线性搜索。 696 00:41:55,980 --> 00:41:59,090 最好情况下的运行时间,在另一方面,是恒定的 697 00:41:59,090 --> 00:42:04,200 因为在最好的情况下,我们要寻找的元素是列表中的第一个。 698 00:42:04,200 --> 00:42:08,930 所以,我们要花费1步,不管有多大的列表 699 00:42:08,930 --> 00:42:12,140 如果我们要找的第一个元素,每一次。 700 00:42:12,140 --> 00:42:15,390 >> 因此,当您搜索时,请记住,它不要求我们的列表进行排序。 701 00:42:15,390 --> 00:42:19,430 因为我们只是去看看,每一个元素,它其实并不重要 702 00:42:19,430 --> 00:42:23,560 什么样的顺序,这些元素所在 703 00:42:23,560 --> 00:42:28,110 一个更聪明的搜索算法是类似二进制搜索。 704 00:42:28,110 --> 00:42:31,500 记住,是当你要执行的二进制搜索 705 00:42:31,500 --> 00:42:34,320 在中间的列表中继续寻找。 706 00:42:34,320 --> 00:42:38,000 因为我们正在寻找的中间,我们需要对列表进行排序 707 00:42:38,000 --> 00:42:40,580 否则,我们不知道在哪里,中间是,我们来看看以上 708 00:42:40,580 --> 00:42:44,480 整个列表中找到它,然后在这一点上,我们只是在浪费时间。 709 00:42:44,480 --> 00:42:48,480 因此,如果我们有一个排序的列表中,我们发现中间,我们要比较的中间 710 00:42:48,480 --> 00:42:51,590 的元素,我们要寻找的。 711 00:42:51,590 --> 00:42:54,640 如果是太高,那么我们就可以忘记的右半边 712 00:42:54,640 --> 00:42:57,810 因为我们知道,如果我们的元素已经过高 713 00:42:57,810 --> 00:43:01,080 和一切该元素的权利甚至更高, 714 00:43:01,080 --> 00:43:02,760 那么我们就需要看看那里了。 715 00:43:02,760 --> 00:43:05,430 凡在另一方面,如果我们的元素是太低, 716 00:43:05,430 --> 00:43:08,700 我们知道一切该元素的左侧还太低, 717 00:43:08,700 --> 00:43:11,390 所以它不是真正意义,看看有,。 718 00:43:11,390 --> 00:43:15,760 通过这种方式,每一步,每一次我们看的列表中点, 719 00:43:15,760 --> 00:43:19,060 我们要削减一半,因为我们的问题,我们突然知道 720 00:43:19,060 --> 00:43:23,040 一大堆的数字,不能是一个我们要找的。 721 00:43:23,040 --> 00:43:26,950 >> 在伪代码,这将是这个样子, 722 00:43:26,950 --> 00:43:30,990 而且,因为我们切割的列表中每一次的一半, 723 00:43:30,990 --> 00:43:34,920 我们的最坏情况下的运行时间从线性到对数的跳跃。 724 00:43:34,920 --> 00:43:39,260 因此,我们突然有记录的步骤,以便找到列表中的元素。 725 00:43:39,260 --> 00:43:42,460 最好的情况下的运行时间,不过,仍然是不变的 726 00:43:42,460 --> 00:43:45,180 因为现在,让我们只想说,我们正在寻找的元素是 727 00:43:45,180 --> 00:43:48,380 原始列表总是精确中间。 728 00:43:48,380 --> 00:43:52,080 因此,我们可以成长为大,因为我们希望我们的名单,但如果我们要寻找的是在中间元素, 729 00:43:52,080 --> 00:43:54,910 那么我们要花费1步。 730 00:43:54,910 --> 00:44:00,920 所以这就是为什么我们是O(log n)的Ω(1)或恒定。 731 00:44:00,920 --> 00:44:04,510 让我们实际运行在此列表中的二进制搜索。 732 00:44:04,510 --> 00:44:08,020 因此,让我们说,我们正在寻找的元素164。 733 00:44:08,020 --> 00:44:11,650 我们要做的第一件事是找到这个列表的中点。 734 00:44:11,650 --> 00:44:15,060 它只是发生的中点是要倒在这两个数字之间, 735 00:44:15,060 --> 00:44:18,960 所以我们就武断地说,每次2号的中点之间, 736 00:44:18,960 --> 00:44:21,150 让我们圆了。 737 00:44:21,150 --> 00:44:24,330 我们只需要确保我们这样做的每一个步骤的方式。 738 00:44:24,330 --> 00:44:29,040 因此,我们要圆了,和我们说,161是我们的名单中。 739 00:44:29,040 --> 00:44:34,640 因此,161 <164,和161的每一个元素的左侧 740 00:44:34,640 --> 00:44:39,120 <164,所以我们不知道它会帮助我们在所有 741 00:44:39,120 --> 00:44:42,690 开始寻找的元素,因为在这里我们不能有。 742 00:44:42,690 --> 00:44:47,060 所以,我们可以做的是,我们只是忘了,整个左半边的列表, 743 00:44:47,060 --> 00:44:51,700 现在只考虑从右边的161起。 744 00:44:51,700 --> 00:44:54,050 >> 所以,再一次,这是中点;让我们圆了。 745 00:44:54,050 --> 00:44:56,260 现在175是太大了。 746 00:44:56,260 --> 00:44:59,180 因此,我们知道它不会帮助我们期待在这里或在这里, 747 00:44:59,180 --> 00:45:06,610 因此,我们就可以扔一边去,和我们最终会达到了164个。 748 00:45:06,610 --> 00:45:10,560 二进制搜索的任何问题? 749 00:45:10,560 --> 00:45:14,180 让我们从搜索通过一个已经排序的列表 750 00:45:14,180 --> 00:45:17,660 实际以任何顺序的号码列表 751 00:45:17,660 --> 00:45:20,960 该列表以升序排列。 752 00:45:20,960 --> 00:45:24,060 我们看到在第一种算法被称为冒泡排序。 753 00:45:24,060 --> 00:45:27,300 这将是比较简单的,我们看到的算法。 754 00:45:27,300 --> 00:45:32,970 冒泡排序法说,当任意2个元素列表内的地方, 755 00:45:32,970 --> 00:45:36,500 这意味着有一个更高的编号,以左侧的一个较小的数字, 756 00:45:36,500 --> 00:45:40,190 然后,我们将交换他们,因为这意味着,该清单将是 757 00:45:40,190 --> 00:45:42,860 “更多排序”比以前。 758 00:45:42,860 --> 00:45:45,180 我们只是打算再继续这个过程中,一次又一次地 759 00:45:45,180 --> 00:45:52,100 直到最后元素的的种泡到正确的位置,我们有一个排序的列表。 760 00:45:52,100 --> 00:45:57,230 >> 这是怎么回事运行时间为O(N²)。为什么呢? 761 00:45:57,230 --> 00:46:00,370 好了,因为在最坏的情况下,我们采取的每一个元素,并 762 00:46:00,370 --> 00:46:04,570 我们要结束了列表中的所有其他元素进行比较。 763 00:46:04,570 --> 00:46:08,030 但是,在最好的情况下,我们有一个已排序的列表中,冒泡排序 764 00:46:08,030 --> 00:46:12,230 只通过一次去,说:“不,我没有做任何掉期,所以我所做的一切。” 765 00:46:12,230 --> 00:46:17,410 因此,我们有最好的情况Ω(n)的运行时间。 766 00:46:17,410 --> 00:46:20,680 让我们来运行冒泡排序的列表。 767 00:46:20,680 --> 00:46:23,560 首先,让我们看一些伪真的很快。 768 00:46:23,560 --> 00:46:28,160 我们想说,我们要跟踪的,在每一次迭代的循环, 769 00:46:28,160 --> 00:46:32,190 跟踪与否,我们改变的任何元素。 770 00:46:32,190 --> 00:46:37,610 如此的原因是,我们要停下来的时候,我们没有交换任何元素。 771 00:46:37,610 --> 00:46:41,980 因此,在我们的循环的开始,我们还没有交换任何东西,所以我们会说这是假的。 772 00:46:41,980 --> 00:46:47,170 现在,我们要去列表,并比较i个元素的元素i + 1 773 00:46:47,170 --> 00:46:50,310 如果是的情况下,有一个更大的编号,以左侧的一个较小的数字, 774 00:46:50,310 --> 00:46:52,310 然后,我们只是来交换他们。 775 00:46:52,310 --> 00:46:54,490 >> 然后,我们要记住,我们交换元素。 776 00:46:54,490 --> 00:46:58,900 这意味着,我们需要在列表中至少1个或更多的时间去 777 00:46:58,900 --> 00:47:02,160 因为我们停止的条件,其中已排序的整个列表时, 778 00:47:02,160 --> 00:47:04,890 这意味着我们还没有作出任何掉期。 779 00:47:04,890 --> 00:47:09,960 所以这就是为什么我们的条件,在这里是“,而一些元素已被调换。 780 00:47:09,960 --> 00:47:13,720 所以,现在就让我们看一看在此名单上的运行。 781 00:47:13,720 --> 00:47:16,640 我的名单5,0,1,6,4。 782 00:47:16,640 --> 00:47:19,850 要开始冒泡排序的方式在左侧,和它的比较 783 00:47:19,850 --> 00:47:24,700 的第i个元素,所以0到i + 1,它是元件1。 784 00:47:24,700 --> 00:47:29,020 它说,5> 0,但现在是向左, 785 00:47:29,020 --> 00:47:32,500 所以我需要换5和0。 786 00:47:32,500 --> 00:47:35,470 当我换,我突然得到这个不同的列表。 787 00:47:35,470 --> 00:47:38,260 5> 1,所以我们要来交换他们。 788 00:47:38,260 --> 00:47:42,160 5是6,所以我们不需要在这里做任何事情。 789 00:47:42,160 --> 00:47:46,690 但6> 4,所以我们需要交换。 790 00:47:46,690 --> 00:47:49,740 同样,我们需要贯穿整个名单,最终发现 791 00:47:49,740 --> 00:47:52,330 这些是为了,我们交换, 792 00:47:52,330 --> 00:47:57,120 在这一点上,我们需要更多的时间运行在列表中 793 00:47:57,120 --> 00:48:05,390 以确保一切都在它的顺序,并在这一点上冒泡排序已经完成。 794 00:48:05,390 --> 00:48:10,720 采取一些元素,不同的算法和排序,选择排序。 795 00:48:10,720 --> 00:48:15,740 选择排序背后的想法是,我们要建立一个排序的列表部分 796 00:48:15,740 --> 00:48:18,150 在一个时间的1个元素。 797 00:48:18,150 --> 00:48:23,170 >> 而要做到这一点的方式,我们是通过建立列表中的左部。 798 00:48:23,170 --> 00:48:27,510 基本上,每 - 每一步,我们将要采取的最小元素,我们已经离开 799 00:48:27,510 --> 00:48:32,310 尚未排序,我们将它移动到该排序段。 800 00:48:32,310 --> 00:48:35,850 这意味着我们需要不断发现的最小的未分类的元素 801 00:48:35,850 --> 00:48:40,720 然后,最小的元素交换的任何一种 802 00:48:40,720 --> 00:48:45,090 最左边的元素进行排序。 803 00:48:45,090 --> 00:48:50,890 运行时间为O(N 2),因为在最坏的情况下 804 00:48:50,890 --> 00:48:55,070 我们需要比较每一个元素的所有其他元素。 805 00:48:55,070 --> 00:48:59,250 因为我们说,如果我们在左半边的列表,我们需要 806 00:48:59,250 --> 00:49:02,970 整个右段去寻找最小的元素。 807 00:49:02,970 --> 00:49:05,430 然后,再次,我们需要去整个右段和 808 00:49:05,430 --> 00:49:08,210 继续一遍又一遍,再次。 809 00:49:08,210 --> 00:49:11,350 这为n²。我们将需要一个for循环内的另一个循环 810 00:49:11,350 --> 00:49:13,350 这表明N²。 811 00:49:13,350 --> 00:49:16,530 在最好的情况下思想,让我们说,我们给它一个已排序的列表; 812 00:49:16,530 --> 00:49:19,270 我们其实并不比n²做的更好。 813 00:49:19,270 --> 00:49:21,730 由于选择排序有没有办法知道 814 00:49:21,730 --> 00:49:25,540 最小的元素只是我正好要寻找的。 815 00:49:25,540 --> 00:49:28,970 它仍然需要确保,这实际上是最低的。 816 00:49:28,970 --> 00:49:31,670 >> 只有这样,才能确保它的最低限度,使用这种算法, 817 00:49:31,670 --> 00:49:34,640 再看看每一个元素。 818 00:49:34,640 --> 00:49:38,420 所以,真的,如果你给它 - 如果你给一个已排序的列表中选择排序, 819 00:49:38,420 --> 00:49:42,720 它不会做任何比给它一个列表,该列表还没有排序。 820 00:49:42,720 --> 00:49:46,320 顺便说一下,如果真的发生的情况下,有什么是O(的东西) 821 00:49:46,320 --> 00:49:50,640 及的欧米茄的东西,我们只是说,它是θ的东西更简洁。 822 00:49:50,640 --> 00:49:52,760 所以,如果你看到在任何地方,这是什么,仅仅表示。 823 00:49:52,760 --> 00:49:57,580 >> 如果事情是THETA的n²,它既是大O(N 2)和Ω(N ​​2)。 824 00:49:57,580 --> 00:49:59,790 因此,最好的情况和最坏的情况下,它不会有所作为, 825 00:49:59,790 --> 00:50:04,400 该算法是每次都做同样的事情。 826 00:50:04,400 --> 00:50:06,610 因此,这是选择排序的伪代码可能看起来像。 827 00:50:06,610 --> 00:50:10,630 基本上,我们会说,我想遍历列表 828 00:50:10,630 --> 00:50:15,180 由左到右,并在每个迭代循环,我要移动 829 00:50:15,180 --> 00:50:19,780 到这部分的列表中最小的元素。 830 00:50:19,780 --> 00:50:23,260 有一次我移动的东西,我从来没有需要再看看该元素。 831 00:50:23,260 --> 00:50:28,600 因为只要我换的左部的列表中的一个元素,它的排序 832 00:50:28,600 --> 00:50:32,600 因为我们正在做的一切都在按升序排列使用最小值。 833 00:50:32,600 --> 00:50:38,740 所以我们说,好了,我们在i位置上,我们需要的所有元素 834 00:50:38,740 --> 00:50:42,260 i的右边的,以便找到最低。 835 00:50:42,260 --> 00:50:46,150 因此,这意味着,我们想看看从i + 1到列​​表末尾。 836 00:50:46,150 --> 00:50:51,610 而现在,如果我们目前正在观察的元素是低于我们的最低到目前为止, 837 00:50:51,610 --> 00:50:54,190 请记得,我们开始只是最小关断 838 00:50:54,190 --> 00:50:57,020 任何元素,我们目前在我假设这是最低的。 839 00:50:57,020 --> 00:51:00,270 如果我找到比这更小的元素,然后我会说,好吧, 840 00:51:00,270 --> 00:51:02,700 好了,我已经找到了新的最低。 841 00:51:02,700 --> 00:51:06,080 我要记住,最低为。 842 00:51:06,080 --> 00:51:09,560 >> 所以,现在,我已经经历了一次该权利未分类的分类, 843 00:51:09,560 --> 00:51:16,690 我可以说,我要交换的最小元素的位置i的元素是。 844 00:51:16,690 --> 00:51:21,100 这是要建立我的清单,我的排序部分,由左到右的名单, 845 00:51:21,100 --> 00:51:25,190 我们永远不需要看一个元素,再一次在该部分。 846 00:51:25,190 --> 00:51:27,930 一旦我们交换了。 847 00:51:27,930 --> 00:51:30,260 因此,让我们在此列表中选择排序的运行。 848 00:51:30,260 --> 00:51:38,220 这里的蓝色元件将是在i,和红色的元件将是最小元素。 849 00:51:38,220 --> 00:51:41,570 所以,我开始一路在左侧的列表,所以在5。 850 00:51:41,570 --> 00:51:44,610 现在,我们需要找到最小的未分类的元素。 851 00:51:44,610 --> 00:51:49,480 所以我们说0,所以0是我的新的最低。 852 00:51:49,480 --> 00:51:53,820 >> 但我不能停止,因为即使我们能够识别出0是最小的, 853 00:51:53,820 --> 00:51:59,390 我们需要运行通过列表以确保所有其它元素。 854 00:51:59,390 --> 00:52:01,760 因此,1是更大的,6是更大的,是更大的。 855 00:52:01,760 --> 00:52:05,850 这意味着,在所有这些元素后,我已经决定0是最小的。 856 00:52:05,850 --> 00:52:09,800 所以,我要交换5和0。 857 00:52:09,800 --> 00:52:15,480 一旦我换,我会得到一个新的列表,我知道,我从来没有需要再次看,0 858 00:52:15,480 --> 00:52:19,380 因为一旦我交换吧,我已经整理它,我们就大功告成了。 859 00:52:19,380 --> 00:52:22,730 现在,碰巧的是​​,蓝色的元素又是5, 860 00:52:22,730 --> 00:52:26,030 我们需要在1%,6和4,确定1 861 00:52:26,030 --> 00:52:31,520 是最小最小的元素,所以我们交换1和5。 862 00:52:31,520 --> 00:52:36,890 同样,我们需要看看 - 比较5〜6和4, 863 00:52:36,890 --> 00:52:39,830 我们交换4和5,最后,比较 864 00:52:39,830 --> 00:52:45,740 这2个数字,并交换它们,直到我们得到我们的排序列表。 865 00:52:45,740 --> 00:52:49,730 选择排序的任何问题吗? 866 00:52:49,730 --> 00:52:56,420 好吧。让我们继续上次的话题,那就是递归。 867 00:52:56,420 --> 00:52:59,810 >> 递归,请记住,这是真的荟萃东西的功能 868 00:52:59,810 --> 00:53:02,740 反复调用自身。 869 00:53:02,740 --> 00:53:05,620 因此,在某些时候,而我们的机能的反复调用本身, 870 00:53:05,620 --> 00:53:10,100 需要有一些点,我们不再称自己。 871 00:53:10,100 --> 00:53:13,670 因为如果我们不这样做,那么我们只是要继续这样下去,永远, 872 00:53:13,670 --> 00:53:16,660 我们的计划是不会终止。 873 00:53:16,660 --> 00:53:19,200 我们将这种情况的基本情况。 874 00:53:19,200 --> 00:53:22,570 说,而不是再次调用一个函数的基本情况, 875 00:53:22,570 --> 00:53:25,330 我只是返回一些值。 876 00:53:25,330 --> 00:53:28,080 因此,一旦我们返回一个值,我们称自己已经停止了, 877 00:53:28,080 --> 00:53:32,550 至今,我们已经取得了其余的电话也可以返回。 878 00:53:32,550 --> 00:53:36,050 的碱情况下,与此相反的是递归的情况下。 879 00:53:36,050 --> 00:53:39,050 这是当我们想要拨打另一个电话的功能,我们目前所处的 880 00:53:39,050 --> 00:53:44,690 虽然并非始终如此,我们可能要使用不同的参数。 881 00:53:44,690 --> 00:53:48,940 >> 所以,如果我们有一个称为F的函数,且f称为1个参数, 882 00:53:48,940 --> 00:53:52,010 ,我们只是调用f(1),F(1),F(1),和它碰巧的是, 883 00:53:52,010 --> 00:53:56,510 参数1分为递归的情况下,我们仍然永远不会停止。 884 00:53:56,510 --> 00:54:01,620 即使我们有一个基础的情况下,我们需要确保,最终我们要达到这一基本情况。 885 00:54:01,620 --> 00:54:04,250 我们不只是保持在这个递归的情况下。 886 00:54:04,250 --> 00:54:09,870 通常情况下,当我们调用自己的时候,我们可能有不同的观点。 887 00:54:09,870 --> 00:54:12,700 这是一个非常简单的递归函数。 888 00:54:12,700 --> 00:54:15,090 因此,这将计算出一个数的阶乘。 889 00:54:15,090 --> 00:54:17,790 在这里往上顶,我们有我们的基本情况。 890 00:54:17,790 --> 00:54:22,330 的情况下,N≤1,我们不会再次打电话因子。 891 00:54:22,330 --> 00:54:26,490 我们要停止,我们只是将返回一定的价值。 892 00:54:26,490 --> 00:54:30,170 如果这是不正确的,那么我们要达到我们的递归的情况。 893 00:54:30,170 --> 00:54:33,550 请注意,在这里,我们不只是调用的阶乘(N),因为那将是非常有用的。 894 00:54:33,550 --> 00:54:36,810 我们会打电话给别的东西的阶乘。 895 00:54:36,810 --> 00:54:40,850 >> 所以你可以看到,最终,如果我们通过一个阶乘(5)的东西, 896 00:54:40,850 --> 00:54:45,900 我们要调用阶乘(4)等,最终我们要达到这一基本情况。 897 00:54:45,900 --> 00:54:51,730 因此,这看起来不错。让我们看看会发生什么,当我们真正运行这个。 898 00:54:51,730 --> 00:54:57,840 这是堆栈,让我们说,主要是要调用这个函数的参数(4)。 899 00:54:57,840 --> 00:55:02,200 因此,一旦的阶乘看到和= 4,阶乘将调用本身。 900 00:55:02,200 --> 00:55:05,010 现在,突然之间,我们的阶乘(3)。 901 00:55:05,010 --> 00:55:10,780 因此,这些功能都将继续保持增长,直到最终,我们打我们的基本情况。 902 00:55:10,780 --> 00:55:17,830 在这一点上,这是,则返回值返回(nx的的返回值), 903 00:55:17,830 --> 00:55:21,290 的返回值,这是NX的返回值。 904 00:55:21,290 --> 00:55:23,290 最后,我们需要打一些数字。 905 00:55:23,290 --> 00:55:26,560 我们在上方在这里,说返回1。 906 00:55:26,560 --> 00:55:30,650 这意味着,一旦我们回到这个数字,我们可以弹出堆栈。 907 00:55:30,650 --> 00:55:36,570 因此,这阶乘(1)就完成了。 908 00:55:36,570 --> 00:55:41,190 1时返回时,这个阶乘(1)返回,返回1。 909 00:55:41,190 --> 00:55:46,910 返回值,请记住,这是NX的返回值。 910 00:55:46,910 --> 00:55:50,720 突然,这家伙知道,我想回到2。 911 00:55:50,720 --> 00:55:55,910 >> 所以请记住,返回值,这是NX的返回值。 912 00:55:55,910 --> 00:56:01,160 所以,现在我们可以说,3×2,最后,在这里,我们可以说, 913 00:56:01,160 --> 00:56:04,010 这将是4×3×2。 914 00:56:04,010 --> 00:56:09,570 而一旦这种回报,我们得到一个整数内的主要。 915 00:56:09,570 --> 00:56:15,460 递归有任何疑问? 916 00:56:15,460 --> 00:56:17,090 好的。因此,有更多的时间回答大家的提问结束时, 917 00:56:17,090 --> 00:56:23,360 但现在约瑟夫将支付余下的主题。 918 00:56:23,360 --> 00:56:25,590 >> 王阳乐]。所以,现在,我们已经谈到递归, 919 00:56:25,590 --> 00:56:27,840 让我们来谈谈合并排序是一点点。 920 00:56:27,840 --> 00:56:31,740 合并排序是基本的数字排序的列表的另一种方式。 921 00:56:31,740 --> 00:56:36,430 它的工作原理是,归并排序,你有一个列表,我们要做的是 922 00:56:36,430 --> 00:56:39,120 我们说,让我们将其划分为两半。 923 00:56:39,120 --> 00:56:42,750 我们将首先运行再次合并排序的左半边, 924 00:56:42,750 --> 00:56:45,040 然后我们会遇到合并排序的右半​​, 925 00:56:45,040 --> 00:56:50,240 这给了我们两半进行排序,和现在我们要结合这些半在一起。 926 00:56:50,240 --> 00:56:55,010 这是一个有点难以看到没有一个例子,所以我们走走过场,看看会发生什么。 927 00:56:55,010 --> 00:56:59,590 所以,你开始这个列表中,我们把它分为两半。 928 00:56:59,590 --> 00:57:02,300 我们经营的第一个合并排序的左半边。 929 00:57:02,300 --> 00:57:06,660 所以这是左前卫,和现在我们再通过这个列表 930 00:57:06,660 --> 00:57:09,800 被传递到合并排序,然后我们看, 931 00:57:09,800 --> 00:57:13,270 在此列表的左侧,我们运行它的合并排序。 932 00:57:13,270 --> 00:57:15,880 现在,我们得到了2号的列表, 933 00:57:15,880 --> 00:57:19,010 现在的左半边长仅1元,我们不能 934 00:57:19,010 --> 00:57:23,380 分裂一个列表,其中只有1成半的元素,所以我们只是说,一旦我们有50个, 935 00:57:23,380 --> 00:57:26,400 这仅仅是1元,它已经排序。 936 00:57:26,400 --> 00:57:29,860 >> 一旦我们完成了,我们可以看到,我们可以 937 00:57:29,860 --> 00:57:32,230 移动至右半此列表, 938 00:57:32,230 --> 00:57:36,480 3排序,所以现在这个列表进行排序的两半 939 00:57:36,480 --> 00:57:39,080 我们可以将这些数字重新走到一起。 940 00:57:39,080 --> 00:57:45,320 因此,我们期待在50和3,三是小于50,所以它在第一,然后50用武之地。 941 00:57:45,320 --> 00:57:49,340 现在,这样做了,我们回去这是正确的一半,列表和排序。 942 00:57:49,340 --> 00:57:52,440 42是它自己的号码,所以它已经排序。 943 00:57:52,440 --> 00:57:57,850 所以,现在我们比较这些2和图3是小于42,因此,被放在第一, 944 00:57:57,850 --> 00:58:02,340 现年42岁的被提出,和50被放进去。 945 00:58:02,340 --> 00:58:07,220 现在,排序,我们去所有的方式回到顶端,1337年和15。 946 00:58:07,220 --> 00:58:14,560 好吧,我们现在看这个名单的左半边; 1337本身,所以它的排序,并同15。 947 00:58:14,560 --> 00:58:19,020 所以,现在我们结合这2个数字进行排序,原单,15 <1337, 948 00:58:19,020 --> 00:58:23,060 所以在第一位,然后是1337去英寸 949 00:58:23,060 --> 00:58:26,640 现在我们整理的两半原始列表的顶部。 950 00:58:26,640 --> 00:58:30,440 所有我们需要做的是结合这些。 951 00:58:30,440 --> 00:58:36,890 我们期待在该列表中的第2号,3 <15,所以先进行排序的数组。 952 00:58:36,890 --> 00:58:44,460 15 <42,所以它去了。现在,42 <1337,去英寸 953 00:58:44,460 --> 00:58:51,010 50 <1337,所以去英寸注意到了我们仅仅花了2个号码,这个列表。 954 00:58:51,010 --> 00:58:53,640 所以,我们不能简单地交替之间的列表。 955 00:58:53,640 --> 00:58:56,050 我们只是在寻找一开始,我们正在采取元素 956 00:58:56,050 --> 00:59:00,270 这是更小的,然后把它到我们的数组。 957 00:59:00,270 --> 00:59:04,080 现在,我们已经合并了所有的一半就完成了。 958 00:59:04,080 --> 00:59:07,780 >> 有任何疑问,归并排序?是吗? 959 00:59:07,780 --> 00:59:14,190 [学生]:如果它分裂成不同的群体,为什么他们不只是分裂一次 960 00:59:14,190 --> 00:59:19,970 你有3个和2组中的吗? [其他问题不知所云] 961 00:59:19,970 --> 00:59:24,940 原因 - 所以,问题是,为什么我们不能只是把它们合并的第一步后,我们有吗? 962 00:59:24,940 --> 00:59:29,530 我们之所以能做到这一点,双方在最左边的元素, 963 00:59:29,530 --> 00:59:33,040 然后采取较小的一个,并把它放在,是因为我们知道,这些 964 00:59:33,040 --> 00:59:35,290 个人的名单中排序的订单。 965 00:59:35,290 --> 00:59:37,290 所以,如果我在最左边的元素的两个部分, 966 00:59:37,290 --> 00:59:40,490 我知道他们将这些列表中的最小元素。 967 00:59:40,490 --> 00:59:43,930 所以,我可以把它们放到这个大名单的最小元素点。 968 00:59:43,930 --> 00:59:47,810 另一方面,如果在第二个层次那边,我看这2列出了 969 00:59:47,810 --> 00:59:51,640 50,3,42,1337和15,这些都是没有排序。 970 00:59:51,640 --> 00:59:55,770 所以,如果我在50和1337,我要放50到我的清单。 971 00:59:55,770 --> 01:00:00,130 但是,这并不真正有意义,因为是最小的元素的所有这些。 972 01:00:00,130 --> 01:00:04,390 所以我们可以做到这一点结合步骤的唯一原因是因为我们的名单已经排序。 973 01:00:04,390 --> 01:00:07,010 这就是为什么我们得到了所有的方式向底部 974 01:00:07,010 --> 01:00:09,800 因为当我们只是一个单一的号码,你知道,一个单一的数字 975 01:00:09,800 --> 01:00:14,120 在其本身已经是一个排序的列表。 976 01:00:14,120 --> 01:00:19,360 >> 有什么问题吗?不是吗? 977 01:00:19,360 --> 01:00:24,260 复杂性?好了,你可以看到,在每一步的最终数字, 978 01:00:24,260 --> 01:00:27,590 我们可以将一个列表中的一半log N次, 979 01:00:27,590 --> 01:00:31,700 这是我们得到这个N X日志n的复杂性。 980 01:00:31,700 --> 01:00:34,940 你会看到最好的情况下,归并排序是n日志n,它只是恰巧 981 01:00:34,940 --> 01:00:39,340 最坏的情况下,或Ω那边的,也是n日志n。 982 01:00:39,340 --> 01:00:42,480 要记住的东西。 983 01:00:42,480 --> 01:00:45,750 移动,让我们去到一些超级基本的文件I / O。 984 01:00:45,750 --> 01:00:48,830 如果你看,你会发现我们在争夺某种系统 985 01:00:48,830 --> 01:00:51,270 在那里你可以写入到日志文件中,如果你读通过的代码。 986 01:00:51,270 --> 01:00:53,730 让我们来看看你怎么可能做到这一点。 987 01:00:53,730 --> 01:00:57,450 好了,我们有fprintf,你能想到的只是输出, 988 01:00:57,450 --> 01:01:01,720 只是打印到一个文件中,而不是,因此在开始时的f。 989 01:01:01,720 --> 01:01:07,570 这种代码在这里,它是什么,你可能已经看到在争夺, 990 01:01:07,570 --> 01:01:12,310 它通过你的二维数组打印出来行由行的数字是什么。 991 01:01:12,310 --> 01:01:17,850 在这种情况下,输出打印到您的终端或我们所说的标准输出部分。 992 01:01:17,850 --> 01:01:22,170 >> 而现在,在这种情况下,我们要做的是与fprintf的printf取代, 993 01:01:22,170 --> 01:01:26,770 告诉您要打印的文件,在这种情况下,它只是它打印输出到该文件 994 01:01:26,770 --> 01:01:32,230 而不是把它打印出来到你的终端。 995 01:01:32,230 --> 01:01:36,500 好了,那么这引出了一个问题:我们从哪里得到这类型的文件,对不对? 996 01:01:36,500 --> 01:01:39,840 我们通过在这fprintf机能的,但我们不知道它是从哪里来的。 997 01:01:39,840 --> 01:01:43,980 好了,早在代码中,我们有什么是在这里,这个代码块 998 01:01:43,980 --> 01:01:48,340 基本上说,打开该文件要求log.txt中。 999 01:01:48,340 --> 01:01:53,220 我们做什么后,我们必须确保该文件实际上是打开成功。 1000 01:01:53,220 --> 01:01:57,070 因此,它可能会失败的原因有多种,你没有足够的空间在您的计算机上,例如。 1001 01:01:57,070 --> 01:01:59,790 因此,它始终是重要的,之前你做任何操作的文件 1002 01:01:59,790 --> 01:02:03,300 我们检查该文件是否被成功打开。 1003 01:02:03,300 --> 01:02:09,330 那么,什么是一个,这是一个争论的FOPEN,好了,我们可以打开一个文件,在许多方面。 1004 01:02:09,330 --> 01:02:13,510 我们可以做的是,我们可以通过它瓦特,这意味着覆盖的文件,如果它退出了, 1005 01:02:13,510 --> 01:02:18,070 我们可以通过一个一个,这是他们附加的文件,而不是覆盖它, 1006 01:02:18,070 --> 01:02:22,730 或者我们可以指定R,这意味着,让我们打开的文件为只读。 1007 01:02:22,730 --> 01:02:24,890 因此,如果程序试图进行任何更改的文件, 1008 01:02:24,890 --> 01:02:30,140 骂他们,不要让他们这样做。 1009 01:02:30,140 --> 01:02:33,320 最后,一​​旦我们完成的文件,完成执行操作就可以了, 1010 01:02:33,320 --> 01:02:35,860 我们需要确保我们关闭文件。 1011 01:02:35,860 --> 01:02:38,830 因此,在你的程序,你要通过他们再次 1012 01:02:38,830 --> 01:02:42,120 您打开这个文件,只是将其关闭。 1013 01:02:42,120 --> 01:02:44,650 因此,这是重要的事情,你必须确保你做。 1014 01:02:44,650 --> 01:02:47,180 所以请记住,你可以打开一个文件,然后就可以写入到文件中, 1015 01:02:47,180 --> 01:02:51,270 操作中的文件,但你必须在年底关闭该文件。 1016 01:02:51,270 --> 01:02:53,270 >> 任何问题,基本的文件I / O?是吗? 1017 01:02:53,270 --> 01:02:58,050 [学生提问,不知所云] 1018 01:02:58,050 --> 01:03:02,480 就在这里。现在的问题是,这log.txt文件出现在哪里? 1019 01:03:02,480 --> 01:03:07,890 好吧,如果你只要给它log.txt中,它会创建在同一目录下的可执行文件。 1020 01:03:07,890 --> 01:03:10,500 所以,如果让隐私无处藏 - >> [学生提问,不知所云] 1021 01:03:10,500 --> 01:03:18,830 是。在同一个文件夹中,或在同一个目录下,如你所说的话。 1022 01:03:18,830 --> 01:03:21,400 现在,内存,堆栈和堆。 1023 01:03:21,400 --> 01:03:23,400 因此,如何在计算机的内存吗? 1024 01:03:23,400 --> 01:03:26,270 那么,你可以想像内存块的排序。 1025 01:03:26,270 --> 01:03:30,260 而在内存中,我们有什么所谓的堆卡在那里,栈,在那里。 1026 01:03:30,260 --> 01:03:34,480 和堆向下增长的堆栈是向上增长的。 1027 01:03:34,480 --> 01:03:38,620 因此,作为托米提到的 - 哦,好了,我们这些其他4段,我会在第二 - 1028 01:03:38,620 --> 01:03:42,890 汤米刚才说,你知道他的功能是如何称呼自己和称呼对方? 1029 01:03:42,890 --> 01:03:44,930 他们建立这种堆栈帧。 1030 01:03:44,930 --> 01:03:47,360 那么,如果主调用f​​oo,foo的被放在堆栈中。 1031 01:03:47,360 --> 01:03:52,430 foo调用了酒吧,酒吧将在堆栈上,并因此获得在堆栈中。 1032 01:03:52,430 --> 01:03:57,040 当他们返回,他们各拿采取的堆栈。 1033 01:03:57,040 --> 01:04:00,140 什么这些地方,保持记忆的? 1034 01:04:00,140 --> 01:04:03,110 那么,顶部,这是文本段包含程序本身。 1035 01:04:03,110 --> 01:04:06,390 的存在,所以本机代码,一旦你编译的程序。 1036 01:04:06,390 --> 01:04:08,520 其次,任何初始化的全局变量。 1037 01:04:08,520 --> 01:04:12,660 >> 所以,你必须在你的程序中的全局变量,和你说的一样,A = 5, 1038 01:04:12,660 --> 01:04:15,260 得到段,下, 1039 01:04:15,260 --> 01:04:18,990 您有任何未初始化的全局数据,它只是诠释一个, 1040 01:04:18,990 --> 01:04:20,990 但你不说,它等于任何东西。 1041 01:04:20,990 --> 01:04:23,870 实现这些都是全局变量,所以他们在外面的主。 1042 01:04:23,870 --> 01:04:28,560 因此,这意味着任何的已宣告但不会被初始化的全局变量。 1043 01:04:28,560 --> 01:04:32,310 那么,是什么在堆吗?分配的内存使用malloc,我们将在一点点。 1044 01:04:32,310 --> 01:04:35,990 最后,与堆栈您有任何局部变量 1045 01:04:35,990 --> 01:04:39,950 任何功能,你可以调用他们的任何参数。 1046 01:04:39,950 --> 01:04:43,720 的最后一件事,你不真正了解的环境变量做什么, 1047 01:04:43,720 --> 01:04:46,700 但只要你运行的程序,有一些相关的,如 1048 01:04:46,700 --> 01:04:49,550 这是用户名的人谁跑的程序。 1049 01:04:49,550 --> 01:04:51,550 这就是将要排序的底部。 1050 01:04:51,550 --> 01:04:54,540 的内存地址,这是十六进制值, 1051 01:04:54,540 --> 01:04:58,170 值的顶部从0开始,和他们走一路下滑到了谷底。 1052 01:04:58,170 --> 01:05:00,440 在这种情况下,如果你在32位系统上, 1053 01:05:00,440 --> 01:05:05,390 在底部的地址将是0x开头,然后自动对焦,因为这是32位, 1054 01:05:05,390 --> 01:05:10,890 它是8个字节,并且在这种情况下,8个字节对应于8个十六进制数字。 1055 01:05:10,890 --> 01:05:20,110 所以,在这里你将有一样,0xFFFFFF具有,和在那里,你将有0。 1056 01:05:20,110 --> 01:05:23,660 那么,什么是指针?你们有些人可能不涉及这部分之前。 1057 01:05:23,660 --> 01:05:26,660 但我们没有去,所以在课堂上的指针只是一个数据类型 1058 01:05:26,660 --> 01:05:34,030 店,而不是某种类型的值,如50,它存储在内存中的某个位置的地址。 1059 01:05:34,030 --> 01:05:36,020 这样的记忆[不知所云]。 1060 01:05:36,020 --> 01:05:41,120 因此,在这种情况下,我们所拥有的,我们有一个指针,指向一个整数或一个int *, 1061 01:05:41,120 --> 01:05:46,210 它包含这个十六进制的0xDEADBEEF地址。 1062 01:05:46,210 --> 01:05:50,880 >> 那么,我们有什么,现在,该指针指向在内存中的某个位置, 1063 01:05:50,880 --> 01:05:56,020 这只是一个,值50是在此内存位置。 1064 01:05:56,020 --> 01:06:01,810 在32位系统中,所有32位系统上,指针占用32位或4个字节。 1065 01:06:01,810 --> 01:06:06,020 但是,例如,在64位系统中,指针是64位。 1066 01:06:06,020 --> 01:06:08,040 所以,你要记住的东西。 1067 01:06:08,040 --> 01:06:12,310 因此,在结束位系统,指针是结束位长。 1068 01:06:12,310 --> 01:06:17,320 指针是一种难以消化的,没有多余的东西, 1069 01:06:17,320 --> 01:06:20,300 所以,让我们通过一个例子来动态内存分配。 1070 01:06:20,300 --> 01:06:25,130 动态内存分配为你做,或者我们调用malloc, 1071 01:06:25,130 --> 01:06:29,280 它可以让你分配某种形式的设置之外的数据。 1072 01:06:29,280 --> 01:06:31,830 因此,此数据是一种程序的持续时间更永久的。 1073 01:06:31,830 --> 01:06:36,430 因为你知道,如果你里面的一个函数,该函数返回x声明, 1074 01:06:36,430 --> 01:06:40,910 你不再需要访问的数据存储在x。 1075 01:06:40,910 --> 01:06:44,420 让我们做什么指针,是他们让我们存储记忆体或存储值 1076 01:06:44,420 --> 01:06:46,840 在不同的内存段,即堆。 1077 01:06:46,840 --> 01:06:49,340 现在,一旦我们返回的功能,只要我们有一个指针 1078 01:06:49,340 --> 01:06:54,960 内存中该位置,那么我们能做些什么,我们就可以看的值。 1079 01:06:54,960 --> 01:06:58,020 让我们看一个例子:这是我们的内存布局。 1080 01:06:58,020 --> 01:07:00,050 我们有这个功能,主要。 1081 01:07:00,050 --> 01:07:06,870 它所做的是 - 好了,就这么简单,对不对? - 诠释第X = 5,这只是一个变量在堆栈中的主。 1082 01:07:06,870 --> 01:07:12,450 >> 另一方面,现在我们宣派指针调用函数giveMeThreeInts。 1083 01:07:12,450 --> 01:07:16,800 所以现在我们进入这个功能,我们创建了一个新的堆栈帧。 1084 01:07:16,800 --> 01:07:20,440 然而,在这个堆栈帧中,我们声明int *温度, 1085 01:07:20,440 --> 01:07:23,210 这对我们的mallocs 3个整数。 1086 01:07:23,210 --> 01:07:25,880 因此,大小的int会给我们带来多少字节,int是, 1087 01:07:25,880 --> 01:07:29,620 和malloc为我们提供了多少字节的空间在堆中。 1088 01:07:29,620 --> 01:07:32,890 因此,在这种情况下,我们已经建立了足够的空间,3个整数, 1089 01:07:32,890 --> 01:07:36,830 和堆在那里,这就是为什么我画更高。 1090 01:07:36,830 --> 01:07:42,900 一旦我们完成了,我们回来在这里,你只需要3个int返回, 1091 01:07:42,900 --> 01:07:47,000 ,它返回的地址,在这种情况下,内存是的。 1092 01:07:47,000 --> 01:07:51,250 我们设置指针开关,在那里,我们只是一个指针。 1093 01:07:51,250 --> 01:07:54,550 但该函数返回被堆积在这里消失。 1094 01:07:54,550 --> 01:07:59,250 因此,临时消失,但我们仍然保持的地址在哪里 1095 01:07:59,250 --> 01:08:01,850 这3个整数内的电源。 1096 01:08:01,850 --> 01:08:06,180 因此,在这组中,指针的范围,为本地的堆叠框架, 1097 01:08:06,180 --> 01:08:09,860 但他们指的是在堆中的内存。 1098 01:08:09,860 --> 01:08:12,190 >> 这是否有意义吗? 1099 01:08:12,190 --> 01:08:14,960 [学生]:你能重复一次吗? >> [约瑟夫]是的。 1100 01:08:14,960 --> 01:08:20,270 所以,如果我回去只是一点点,你会看到该临时分配 1101 01:08:20,270 --> 01:08:23,500 一些内存的堆在那里。 1102 01:08:23,500 --> 01:08:28,680 所以,此功能时,giveMeThreeInts收益,该协议栈在这里会消失。 1103 01:08:28,680 --> 01:08:35,819 而与它的任何变量,在这种情况下,该指针被分配在层叠帧。 1104 01:08:35,819 --> 01:08:39,649 这是怎么回事消失,但由于我们返回临时 1105 01:08:39,649 --> 01:08:46,330 我们设定指针= temp中,指针现在指向相同的内存位置温度。 1106 01:08:46,330 --> 01:08:50,370 所以,现在,即使我们失去了温度,即本地指针, 1107 01:08:50,370 --> 01:08:59,109 我们仍保留什么该变量的指针指向内部的内存地址。 1108 01:08:59,109 --> 01:09:03,740 有问题吗?这可以是种一个令人困惑的话题,如果你还没有看过它在部分。 1109 01:09:03,740 --> 01:09:09,240 ,你的TF我们可以肯定会去,当然,我们可以回答问题 1110 01:09:09,240 --> 01:09:11,500 在年底的审查会议。 1111 01:09:11,500 --> 01:09:14,220 但,这是一个复杂的话题,我有更多的例子,是要显示 1112 01:09:14,220 --> 01:09:18,790 这将有助于澄清指针实际上是什么。 1113 01:09:18,790 --> 01:09:22,500 >> 在这种情况下,指针是相当于阵列, 1114 01:09:22,500 --> 01:09:25,229 同样的事情作为一个int数组,这样我就可以使用这个指针。 1115 01:09:25,229 --> 01:09:29,840 所以我索引为0,和不断变化的第一个整数为1, 1116 01:09:29,840 --> 01:09:39,689 改变所述第二至2的整数,和第三至3的整数。 1117 01:09:39,689 --> 01:09:44,210 因此,更多的指针。好了,记得Binky。 1118 01:09:44,210 --> 01:09:48,319 在这种情况下,我们分配了一个指针,或我们宣布一个指针, 1119 01:09:48,319 --> 01:09:52,760 但最初,当我刚刚宣布的指针,它不指向在内存中的任何地方。 1120 01:09:52,760 --> 01:09:54,930 这只是它里面的垃圾值。 1121 01:09:54,930 --> 01:09:56,470 所以,我不知道该指针所指向的。 1122 01:09:56,470 --> 01:10:01,630 它有一个地址,只是充满了0和1的地方,它最初宣布。 1123 01:10:01,630 --> 01:10:04,810 我不能做任何事情,直到我调用malloc 1124 01:10:04,810 --> 01:10:08,390 然后它给了我一个很小的空间就堆在那里我可以把内部的值。 1125 01:10:08,390 --> 01:10:11,980 再说,我不知道,此内存里面有什么。 1126 01:10:11,980 --> 01:10:16,780 所以我必须做的第一件事是检查系统是否有足够的内存 1127 01:10:16,780 --> 01:10:20,850 给我1个整数摆在首位,这就是为什么我在做此检查。 1128 01:10:20,850 --> 01:10:25,020 如果指针是空的,这意味着,它没有足够的空间,或某些其他错误发生, 1129 01:10:25,020 --> 01:10:26,320 所以我要退出,我的计划。 1130 01:10:26,320 --> 01:10:29,400  但是,如果它没有成功,现在我可以使用这个指针 1131 01:10:29,400 --> 01:10:35,020 *指针的地址在哪里 1132 01:10:35,020 --> 01:10:38,480 该值的地方是,它设置它等于1。 1133 01:10:38,480 --> 01:10:41,850 因此,在这里,我们检查,如果该内存存在。 1134 01:10:41,850 --> 01:10:45,380 >> 一旦你知道它的存在,你可以把它 1135 01:10:45,380 --> 01:10:50,460 你要投入什么样的价值,在这种情况下,1。 1136 01:10:50,460 --> 01:10:53,060 一旦我们完成它,你需要释放该指针 1137 01:10:53,060 --> 01:10:57,160 因为我们需要的系统内存,你提出的要求摆在首位。 1138 01:10:57,160 --> 01:10:59,690 因为电脑不知道什么时候,我们已经完成了它。 1139 01:10:59,690 --> 01:11:02,510 在这种情况下,我们明确地告诉它,好吧,我们就大功告成了与记忆。 1140 01:11:02,510 --> 01:11:10,780 如果其他应用程序需要它,其他一些程序需要它,感觉自由地前进,并把它。 1141 01:11:10,780 --> 01:11:15,110 我们还可以做的是,我们就可以得到局部变量上设置的地址。 1142 01:11:15,110 --> 01:11:19,080 所以int x是里面堆放的主要框架。 1143 01:11:19,080 --> 01:11:23,060 而当我们使用这个符号,这和运营商,它是什么 1144 01:11:23,060 --> 01:11:27,310 它需要的x,和x是只是一些数据在存储器中,但它有一个地址。 1145 01:11:27,310 --> 01:11:33,790 它位于什么地方。因此,通过调用&X,这是什么做的是它给了我们x的地址。 1146 01:11:33,790 --> 01:11:38,430 通过这样做,我们正在做的指针指向其中x是在内存中。 1147 01:11:38,430 --> 01:11:41,710 现在,我们只是做一些事情,如* X,我们会得到5回。 1148 01:11:41,710 --> 01:11:43,820 这颗恒星被称为提领。 1149 01:11:43,820 --> 01:11:46,640 按照地址,你会得到它的价值,存放在那里。 1150 01:11:51,000 --> 01:11:53,310 >> 有什么问题吗?是吗? 1151 01:11:53,310 --> 01:11:56,500 [学生]:如果你不这样做的三尖的东西,它仍可以编译吗? 1152 01:11:56,500 --> 01:11:59,490 是。如果你不这样做的3指针的东西,它仍然要进行编译, 1153 01:11:59,490 --> 01:12:02,720 但我会告诉你发生了什么在第二,并没有这样做, 1154 01:12:02,720 --> 01:12:04,860 这就是我们所说的内存泄漏。你不给系统 1155 01:12:04,860 --> 01:12:07,850 支持它的记忆,所以一段时间后程序会积累 1156 01:12:07,850 --> 01:12:10,940 内存,它的使用,并没有其他人可以使用它。 1157 01:12:10,940 --> 01:12:15,750 如果你见过有150万字节在您的计算机上的Firefox, 1158 01:12:15,750 --> 01:12:17,840 在任务管理器,这是怎么回事。 1159 01:12:17,840 --> 01:12:20,760 你有内存泄漏的程序,他们没有处理。 1160 01:12:23,080 --> 01:12:26,240 那么,如何指针的算术运算的工作吗? 1161 01:12:26,240 --> 01:12:29,480 好了,指针运算是有点像索引到一个数组中。 1162 01:12:29,480 --> 01:12:36,370 在这种情况下,我有一个指针,我做的是我的第一个元素的指针指向 1163 01:12:36,370 --> 01:12:42,100 此数组中的3个整数,我已经分配好了。 1164 01:12:42,100 --> 01:12:46,670 所以现在我做什么,明星的指针只是改变列表中的第一个元素。 1165 01:12:46,670 --> 01:12:49,140 星级指针+1点在这里。 1166 01:12:49,140 --> 01:12:53,140 因此,指针是在这里,指针+1是在这里,指针+2是在这里。 1167 01:12:53,140 --> 01:12:56,610 >> 因此,只要加1是沿着这个数组同样的事情。 1168 01:12:56,610 --> 01:12:59,880 我们做的是,当我们这样做的指针+1,你的地址在这里, 1169 01:12:59,880 --> 01:13:04,180 中获得的价值在这里,你把一个明星从整个表达式 1170 01:13:04,180 --> 01:13:05,990 取消对它的引用。 1171 01:13:05,990 --> 01:13:09,940 所以,在这种情况下,我这个数组中的第一位置设置为1,则 1172 01:13:09,940 --> 01:13:13,970 第二位置为2〜3中的第三位置。 1173 01:13:13,970 --> 01:13:18,180 我在做什么在这里是我打印的指针+1, 1174 01:13:18,180 --> 01:13:19,970 这只是给了我2。 1175 01:13:19,970 --> 01:13:23,650 现在,我递增指针,所以指针等于指针+1, 1176 01:13:23,650 --> 01:13:26,780 向前移动。 1177 01:13:26,780 --> 01:13:30,810 所以现在如果我打印出来的指针+1 +1指针现在是3, 1178 01:13:30,810 --> 01:13:33,990 在这种情况下,打印出3。 1179 01:13:33,990 --> 01:13:36,560 而以免费的东西,我给它的指针 1180 01:13:36,560 --> 01:13:40,540 必须指出的数组,我回来了从malloc的开始。 1181 01:13:40,540 --> 01:13:43,430 因此,在这种情况下,如果我在这里呼吁3,这不会是正确的, 1182 01:13:43,430 --> 01:13:45,070 因为它是在中间的数组。 1183 01:13:45,070 --> 01:13:48,820 我必须减去到原来的位置 1184 01:13:48,820 --> 01:13:50,420 最初的第一点,我才可以释放它。 1185 01:13:56,300 --> 01:13:58,450 因此,这里是一个更复杂的例子。 1186 01:13:58,450 --> 01:14:03,360 在这种情况下,我们7个字符,一个字符数组分配。 1187 01:14:03,360 --> 01:14:06,480 >> 在这种情况下,我们正在做的是,我们在第6循环, 1188 01:14:06,480 --> 01:14:09,900 我们将它们设置为Z。 1189 01:14:09,900 --> 01:14:13,350 因此,对于int i = 0,I> 6,我+ +, 1190 01:14:13,350 --> 01:14:16,220 所以,指针+我只是给我们,在这种情况下, 1191 01:14:16,220 --> 01:14:20,860 指针,指针1,指针2,指针3,依此类推等等回路中。 1192 01:14:20,860 --> 01:14:24,040 它要做的是得到该地址,解引用获得的价值, 1193 01:14:24,040 --> 01:14:27,440 和变化值到Z。 1194 01:14:27,440 --> 01:14:30,350 那么,在年底记住这是一个字符串,对不对? 1195 01:14:30,350 --> 01:14:33,560 所有的字符串结束的空终止字符。 1196 01:14:33,560 --> 01:14:38,620 所以,我要做的就是在指针6,我把空终止符中。 1197 01:14:38,620 --> 01:14:43,980 现在我基本上是做什么在这里实现输出一个字符串,对不对? 1198 01:14:43,980 --> 01:14:46,190 >> 所以,当输出现在,当它达到一个字符串的结束吗? 1199 01:14:46,190 --> 01:14:48,230 当它击中的空终止字符。 1200 01:14:48,230 --> 01:14:52,030 因此,在这种情况下,我原来的指针指向该数组的开始。 1201 01:14:52,030 --> 01:14:56,410 我的第一个字符打印出来。我将它移到1。 1202 01:14:56,410 --> 01:14:58,420 我打印的字符。我移动过来。 1203 01:14:58,420 --> 01:15:02,180 我一直这样做,直到我到达终点。 1204 01:15:02,180 --> 01:15:07,750 而现在的结束*指针解引用,并得到空终止字符。 1205 01:15:07,750 --> 01:15:11,780 所以我的while循环运行,只有当该值不是空终止字符。 1206 01:15:11,780 --> 01:15:13,770 所以,现在我退出这个循环。 1207 01:15:18,780 --> 01:15:21,180 所以,如果我从这个指针减去6, 1208 01:15:21,180 --> 01:15:22,860 我回去的方式开始。 1209 01:15:22,860 --> 01:15:27,880 请记住,我这样做是因为我去的开始,以释放它。 1210 01:15:27,880 --> 01:15:30,270 >> 所以,我知道这是一个很多。有什么问题吗? 1211 01:15:30,270 --> 01:15:31,870 请,是吗? 1212 01:15:31,870 --> 01:15:36,610 [学生提问不知所云] 1213 01:15:36,610 --> 01:15:38,190 你能说大声吗?抱歉。 1214 01:15:38,190 --> 01:15:44,140 [学生]:最后一张幻灯片之前释放的指针, 1215 01:15:44,140 --> 01:15:47,300 你改变指针的值吗? 1216 01:15:47,300 --> 01:15:50,370 [约瑟夫]所以,就在这里。 >> [学生]:哦,好吧。 1217 01:15:50,370 --> 01:15:51,890 [约瑟夫]所以,我有一个指针减减,右, 1218 01:15:51,890 --> 01:15:54,140 移动的东西回来,然后我释放它, 1219 01:15:54,140 --> 01:15:57,000 因为这个指针指向的数组的开始。 1220 01:15:57,000 --> 01:16:00,420 [学生]:但是,这不会需要你停止了之后的所有行。 1221 01:16:00,420 --> 01:16:03,130 [约瑟夫]所以,如果我停止后,这将被视为内存泄漏, 1222 01:16:03,130 --> 01:16:04,810 因为我没有运行免费的。 1223 01:16:04,810 --> 01:16:11,290 [学生]:我后的第一个三线指针+1 [不知所云] [不知所云]。 1224 01:16:11,290 --> 01:16:13,140 [约瑟夫]嗯。那么,什么是那里的问题? 1225 01:16:13,140 --> 01:16:14,780 抱歉。不,不。走,走,请。 1226 01:16:14,780 --> 01:16:16,870 [学生]:所以,你就不会改变指针的值。 1227 01:16:16,870 --> 01:16:19,130 你会不会有,做指针减减。 1228 01:16:19,130 --> 01:16:19,730 [约瑟夫]是的,没错。 1229 01:16:19,730 --> 01:16:21,890 所以,当我做指针+1和+2指针, 1230 01:16:21,890 --> 01:16:24,410 我不这样做指针等于指针+1。 1231 01:16:24,410 --> 01:16:27,260 所以,只是停留指针指向的数组的开始。 1232 01:16:27,260 --> 01:16:31,460 这是只有当我做加再加,它的值设置里面的指针, 1233 01:16:31,460 --> 01:16:33,550 它实际上移动一起。 1234 01:16:36,860 --> 01:16:37,780 好的。 1235 01:16:40,550 --> 01:16:42,030 还有问题吗? 1236 01:16:44,680 --> 01:16:47,790 >> 同样的,如果这是铺天盖地的,这将覆盖在会议上。 1237 01:16:47,790 --> 01:16:50,710 问问你的教学研究员,它结束时,我们可以回答的问题。 1238 01:16:53,510 --> 01:16:56,600 通常我们不喜欢做这减去的事情。 1239 01:16:56,600 --> 01:16:59,760 这要求我跟踪我多少数组中的偏移。 1240 01:16:59,760 --> 01:17:04,520 所以,总的来说,这是只是为了解释如何指针运算。 1241 01:17:04,520 --> 01:17:07,970 但是,我们通常喜欢做的是什么,我们要创建的副本的指针, 1242 01:17:07,970 --> 01:17:11,640 然后,我们将使用该副本,当我们走动的字符串。 1243 01:17:11,640 --> 01:17:14,660 因此,在这些情况下,您使用的整个字符串复制到打印, 1244 01:17:14,660 --> 01:17:19,040 但我们没有这样做指针减6跟踪我们搬到了多少, 1245 01:17:19,040 --> 01:17:22,700 因为我们知道,我们仍然指向原来的点开始的列表 1246 01:17:22,700 --> 01:17:25,340 我们改变的是这个副本。 1247 01:17:25,340 --> 01:17:28,250 因此,在一般情况下,改变你原来的指针的副本。 1248 01:17:28,250 --> 01:17:32,350 不要试图有点像 - 不要改变原来的副本。 1249 01:17:32,350 --> 01:17:35,290 试图改变你原来的只读副本。 1250 01:17:41,540 --> 01:17:44,870 所以,你会注意到当我们通过串入的printf 1251 01:17:44,870 --> 01:17:48,990 你不必在它前面放一个明星,像我们一样与所有其他指针引用,对不对? 1252 01:17:48,990 --> 01:17:54,180 所以,如果你打印出整个字符串的%s需要一个地址, 1253 01:17:54,180 --> 01:17:57,610 在这种情况下一个指针,或在这种情况下,像一个字符数组。 1254 01:17:57,610 --> 01:18:00,330 >> 字符,字符*和数组同样的事情。 1255 01:18:00,330 --> 01:18:03,690 指针是字符,字符数组同样的事情。 1256 01:18:03,690 --> 01:18:05,720 所以,我们要做的是通过指针。 1257 01:18:05,720 --> 01:18:08,150 我们没有通过,如*指针或类似的东西。 1258 01:18:13,110 --> 01:18:14,930 因此,数组和指针是同样的事情。 1259 01:18:14,930 --> 01:18:19,160 当你正在做的事情,比如x [Y]在这里的数组, 1260 01:18:19,160 --> 01:18:21,960 它在做什么引擎盖下的是它说,没关系,这是一个字符数组, 1261 01:18:21,960 --> 01:18:23,690 所以这是一个指针。 1262 01:18:23,690 --> 01:18:26,510 因此,x是同样的事情, 1263 01:18:26,510 --> 01:18:28,650 所以它做什么是Y到X, 1264 01:18:28,650 --> 01:18:31,820 这是同样的事情向前发展在内存中。 1265 01:18:31,820 --> 01:18:34,930 而现在X + Y为我们提供了某种形式的地址, 1266 01:18:34,930 --> 01:18:37,570 我们解引用地址或箭头 1267 01:18:37,570 --> 01:18:41,640 内存中该位置在哪里,我们得到的价值,在内存中的位置。 1268 01:18:41,640 --> 01:18:43,720 所以,所以这两个是完全一样的东西。 1269 01:18:43,720 --> 01:18:45,840 这只是一个语法糖。 1270 01:18:45,840 --> 01:18:48,090 他们做同样的事情。他们只是对彼此的不同句法。 1271 01:18:51,500 --> 01:18:57,590 >> 那么,什么可能出错的指针吗?一样,有很多。好吧。所以,不好的事情。 1272 01:18:57,590 --> 01:19:02,410 你可以做一些不好的事情不检查,如果您的malloc调用返回null,正确的吗? 1273 01:19:02,410 --> 01:19:06,560 在这种情况下,我要求给我的系统 - 这个数字是什么? 1274 01:19:06,560 --> 01:19:11,200 2亿次4一样,因为一个整数的大小为4个字节。 1275 01:19:11,200 --> 01:19:13,810 我要求它像8十亿字节。 1276 01:19:13,810 --> 01:19:17,270 当然,我的电脑是不是能够给我这么大的内存回。 1277 01:19:17,270 --> 01:19:20,960 而我们没有检查,如果这是空的,所以,当我们试图取消对它的引用在那里 - 1278 01:19:20,960 --> 01:19:24,270 按照箭头的地方的去 - 我们没有这方面的记忆。 1279 01:19:24,270 --> 01:19:27,150 这就是我们所说的释放空指针。 1280 01:19:27,150 --> 01:19:29,710 这基本上使你出现段错误。 1281 01:19:29,710 --> 01:19:31,790 这是你可以segfault错误的方式之一。 1282 01:19:34,090 --> 01:19:38,090 其他不好的事情可以做 - 哦,好的。 1283 01:19:38,090 --> 01:19:40,650 这是一个空指针解引用。好吧。 1284 01:19:40,650 --> 01:19:45,160 其他不好的事情 - 嗯,要解决,你只要把在那里的检查 1285 01:19:45,160 --> 01:19:46,980 检查指针是否为空 1286 01:19:46,980 --> 01:19:51,000 和退出的程序,如果它发生了,malloc返回一个空指针。 1287 01:19:55,110 --> 01:19:59,850 这是XKCD漫画。人们理解它。排序的。 1288 01:20:06,120 --> 01:20:09,350 >> 因此,记忆体。我去了这一点。 1289 01:20:09,350 --> 01:20:12,000 我们在一个循环中调用malloc,但我们每次调用malloc 1290 01:20:12,000 --> 01:20:14,370 我们正在失去这个指针指向的轨道, 1291 01:20:14,370 --> 01:20:15,750 因为我们弄错了。 1292 01:20:15,750 --> 01:20:18,410 因此,初始调用malloc给我的记忆在这里。 1293 01:20:18,410 --> 01:20:19,990 我的指针的指针。 1294 01:20:19,990 --> 01:20:23,020 现在,我不释放它,所以现在我调用malloc。 1295 01:20:23,020 --> 01:20:26,070 现在,在这里。现在,我的记忆中指出在这里。 1296 01:20:26,070 --> 01:20:27,640 指着在这里。指着在这里。 1297 01:20:27,640 --> 01:20:31,820 但我已经失去了所有的记忆,在这里,我分配的地址跟踪。 1298 01:20:31,820 --> 01:20:35,100 所以现在我没有任何参考了。 1299 01:20:35,100 --> 01:20:37,230 所以,我不能让他们自由这个循环之外。 1300 01:20:37,230 --> 01:20:39,390 因此,为了解决这样的事情, 1301 01:20:39,390 --> 01:20:42,250 如果你忘了空闲内存,你会得到此内存泄漏, 1302 01:20:42,250 --> 01:20:45,810 你必须释放内部的存储器中,这个循环一旦你用它做。 1303 01:20:45,810 --> 01:20:51,400 那么,这是什么情况。我知道很多你不喜欢这一点。 1304 01:20:51,400 --> 01:20:55,270 但现在 - 耶!你得到这样的44,000千字节。 1305 01:20:55,270 --> 01:20:57,110 所以,你释放它的循环结束时, 1306 01:20:57,110 --> 01:20:59,770 而这只是每次释放内存。 1307 01:20:59,770 --> 01:21:03,620 从本质上讲,你的程序没有内存泄漏了。 1308 01:21:03,620 --> 01:21:08,150 >> 现在,别的东西你可以做的是释放一些内存,你问过两次。 1309 01:21:08,150 --> 01:21:11,060 在这种情况下,你的malloc东西,你改变它的值。 1310 01:21:11,060 --> 01:21:13,140 您可以免费一次,因为你说你用它做。 1311 01:21:13,140 --> 01:21:14,940 但后来我们再释放它。 1312 01:21:14,940 --> 01:21:16,730 这是非常糟糕的东西。 1313 01:21:16,730 --> 01:21:18,820 它不会到最初出现段错误, 1314 01:21:18,820 --> 01:21:23,350 但经过一段时间这样做是双重释放这会破坏你的堆结构, 1315 01:21:23,350 --> 01:21:27,200 你将学习多一点点,如果你选择一个类CS61。 1316 01:21:27,200 --> 01:21:30,000 但本质上一段时间后你的电脑会感到困惑 1317 01:21:30,000 --> 01:21:33,010 什么样的内存位置和它的存储 - 1318 01:21:33,010 --> 01:21:34,800 在数据被存储在内存中。 1319 01:21:34,800 --> 01:21:38,080 因此,两次释放一个指针是一个坏的事情,你不想做。 1320 01:21:38,080 --> 01:21:41,600 >> 其他的东西,可以去错了不使用sizeof。 1321 01:21:41,600 --> 01:21:44,460 因此,在这种情况下,你的malloc 8个字节, 1322 01:21:44,460 --> 01:21:46,700 这是为两个整数同样的事情,对不对? 1323 01:21:46,700 --> 01:21:49,580 所以,这是绝对安全的,但它呢? 1324 01:21:49,580 --> 01:21:52,160 那么,作为卢卡斯谈到不同的体系, 1325 01:21:52,160 --> 01:21:54,220 整数是不同长度。 1326 01:21:54,220 --> 01:21:57,970 因此,在您正在使用的电器,整数是4个字节, 1327 01:21:57,970 --> 01:22:02,370 但其他一些系统上,他们可能是8个字节,也可能是16个字节。 1328 01:22:02,370 --> 01:22:05,680 所以,如果我只是在这里使用这个号码, 1329 01:22:05,680 --> 01:22:07,310 这个程序可能会在设备上工作, 1330 01:22:07,310 --> 01:22:10,360 但它不会在其他一些系统分配足够的内存。 1331 01:22:10,360 --> 01:22:14,020 在这种情况下,这是sizeof运算符用于。 1332 01:22:14,020 --> 01:22:16,880 当我们调用的sizeof(int),这样做是什么 1333 01:22:16,880 --> 01:22:21,910  它为我们提供了一个程序正在运行的系统上的整数的大小。 1334 01:22:21,910 --> 01:22:25,490 所以,在这种情况下,表示sizeof(int)将返回4类似器具上, 1335 01:22:25,490 --> 01:22:29,980 现在这个意愿,4 * 2,8, 1336 01:22:29,980 --> 01:22:32,330 这仅仅是为两个整数的必要的空间的量。 1337 01:22:32,330 --> 01:22:36,710 在不同的系统中,如果一个int是16个字节或8字节一样, 1338 01:22:36,710 --> 01:22:39,380 它只是将返回足够的字节来存储量。 1339 01:22:41,830 --> 01:22:45,310 >> 最后,结构。 1340 01:22:45,310 --> 01:22:48,340 所以,如果你想存储在内存中的数独板,怎么可能我们做到这一点呢? 1341 01:22:48,340 --> 01:22:51,570 你可能会想到的第一件事像一个变量, 1342 01:22:51,570 --> 01:22:53,820 一个变量的第二件事情,第三件事情是一个变量, 1343 01:22:53,820 --> 01:22:56,420 第四件事 - 坏,右一个变量? 1344 01:22:56,420 --> 01:23:00,750 所以,你可以在此之上的一种改进是一个9×9阵列。 1345 01:23:00,750 --> 01:23:04,480 这很好,但是如果你想其他的东西相关联的数独板 1346 01:23:04,480 --> 01:23:06,490 喜欢的难度董事会, 1347 01:23:06,490 --> 01:23:11,740 或者,例如,你的分数是什么,或你解决这个板多少时间呢? 1348 01:23:11,740 --> 01:23:14,970 好了,你可以做的是,你可以创建一个结构。 1349 01:23:14,970 --> 01:23:18,910 我基本上可以说是在这里,我定义这个结构, 1350 01:23:18,910 --> 01:23:23,230 我定义的板9×9的数独板组成。 1351 01:23:23,230 --> 01:23:26,650 >> 它所拥有的,它具有的水平的名称的指针。 1352 01:23:26,650 --> 01:23:30,730 它还具有X和Y,这是我现在的坐标。 1353 01:23:30,730 --> 01:23:35,980 还花费的时间[不知所云],它有到目前为止,我已经输入的总数的移动。 1354 01:23:35,980 --> 01:23:40,010 因此,在这种情况下,我可以分组一大堆的数据整合到一个结构 1355 01:23:40,010 --> 01:23:42,790 而不是它像飞舞着像不同的变量 1356 01:23:42,790 --> 01:23:44,540 ,我真的不能跟踪的。 1357 01:23:44,540 --> 01:23:49,720 这让我们有很好的语法形式的引用不同的结构,这里面的东西。 1358 01:23:49,720 --> 01:23:53,430 我可以做board.board,我得到的数独板。 1359 01:23:53,430 --> 01:23:56,320 Board.level,我是多么艰难。 1360 01:23:56,320 --> 01:24:00,540 ,Board.x和board.y给我,我可能会在董事会的坐标。 1361 01:24:00,540 --> 01:24:04,730 因此,我访问就是我们所说的结构体中的字段。 1362 01:24:04,730 --> 01:24:08,840 这定义的sudokuBoard,这是一个类型,我有。 1363 01:24:08,840 --> 01:24:14,800 现在,我们在这里。我有一个变量称为“板”的类型sudokuBoard。 1364 01:24:14,800 --> 01:24:18,820 因此,现在就可以访问这个结构在​​这里的所有领域。 1365 01:24:20,830 --> 01:24:22,450 >> 任何关于结构的问题吗?是吗? 1366 01:24:22,450 --> 01:24:25,890 [学生]:对于整数X,Y,你宣布一个行吗? >> [约瑟夫]嗯。 1367 01:24:25,890 --> 01:24:27,400 [学生]:所以,你可以做,所有的人? 1368 01:24:27,400 --> 01:24:31,200 喜欢在x,y的逗号倍,总? 1369 01:24:31,200 --> 01:24:34,460 [约瑟夫]是的,你可以做到这一点,但我之所以把x和y在同一行 - 1370 01:24:34,460 --> 01:24:36,330 ,问题是我们为什么能做到这一点在同一行吗? 1371 01:24:36,330 --> 01:24:38,600 我们为什么不把所有这些在同一行上 1372 01:24:38,600 --> 01:24:42,090 x和y是彼此相关的, 1373 01:24:42,090 --> 01:24:44,780 而这仅仅是风格上更正确的,在一定意义上, 1374 01:24:44,780 --> 01:24:46,600 因为它的分组在同一行上的两件事情 1375 01:24:46,600 --> 01:24:49,340 ,像那种同样的事情。 1376 01:24:49,340 --> 01:24:51,440 而我只是分裂分开。这只是一种风格的东西。 1377 01:24:51,440 --> 01:24:53,720 它在功能上并没有任何差别。 1378 01:24:58,150 --> 01:24:59,270 对结构的任何其他问题? 1379 01:25:03,030 --> 01:25:06,620 您可以定义一个图鉴与结构。 1380 01:25:06,620 --> 01:25:11,720 宠物小精灵有一个数字,它有一个字母,一个老板,一个类型。 1381 01:25:11,720 --> 01:25:16,990 然后,如果你有一个数组的神奇宝贝,你可以弥补图鉴,对不对? 1382 01:25:16,990 --> 01:25:20,810 好了,爽。因此,结构的问题。这些都是相关的结构。 1383 01:25:20,810 --> 01:25:25,270 >> 最后,GDB。 GDB让你做什么呢?它可以让你调试你的程序。 1384 01:25:25,270 --> 01:25:27,650 如果你还没有使用GDB,我建议看短 1385 01:25:27,650 --> 01:25:31,250 只是在GDB是什么,你如何使用它,你会如何使用它, 1386 01:25:31,250 --> 01:25:32,900 和测试程序。 1387 01:25:32,900 --> 01:25:37,400 因此,让你做什么GDB是它让暂停[不知所云]你的程序 1388 01:25:37,400 --> 01:25:38,920 和一个实际线。 1389 01:25:38,920 --> 01:25:42,600 例如,我想在我的计划,如3号线暂停执行, 1390 01:25:42,600 --> 01:25:46,010 而我在第3行,我可以打印出所有的值有。 1391 01:25:46,010 --> 01:25:49,710 因此,我们所说的像行暂停 1392 01:25:49,710 --> 01:25:52,350 我们称这种放一个断点,在该行 1393 01:25:52,350 --> 01:25:55,920 然后我们就可以打印出当时的变量在程序状态的。 1394 01:25:55,920 --> 01:25:58,990 >> 然后,我们可以从那里通过的程序行由行一步。 1395 01:25:58,990 --> 01:26:03,200 然后我们就可以看的堆栈状态的时间。 1396 01:26:03,200 --> 01:26:08,600 因此,为了使用GDB,我们所做的就是我们称之为铛上的C文件, 1397 01:26:08,600 --> 01:26:11,290 但我们有通过-ggdb标志的。 1398 01:26:11,290 --> 01:26:15,850 一旦我们做,我们只是运行gdb生成的输出文件。 1399 01:26:15,850 --> 01:26:18,810 所以你得到一些像这样质量的文本, 1400 01:26:18,810 --> 01:26:21,990 但真的所有您需要做的是输入命令的开头。 1401 01:26:21,990 --> 01:26:24,250 在主要突破主要把一个断点。 1402 01:26:24,250 --> 01:26:28,470 列表400列出了400行左右的代码行。 1403 01:26:28,470 --> 01:26:31,410 因此,在这种情况下,你可以环顾四周,说,哦, 1404 01:26:31,410 --> 01:26:34,360 我想设置一个断点,在397行,这条线, 1405 01:26:34,360 --> 01:26:37,170 那么你的程序运行到这一步,这将打破。 1406 01:26:37,170 --> 01:26:41,120 这将暂停在那里,您可以打印出来,例如,价值高或低。 1407 01:26:41,120 --> 01:26:46,410 因此,有一堆你需要知道的命令, 1408 01:26:46,410 --> 01:26:48,660 该幻灯片将在网站上, 1409 01:26:48,660 --> 01:26:54,000 所以,如果你只是想引用这些还是喜欢把它们放在你的备忘单,感觉很自由。 1410 01:26:54,000 --> 01:27:00,650 >> 酷。这是测试复习0,如果您有任何问题,我们将坚持围绕。 1411 01:27:00,650 --> 01:27:03,850 好的。 1412 01:27:03,850 --> 01:27:09,030 >>  [掌声] 1413 01:27:09,030 --> 01:27:13,000 >> [CS50.TV]