扬声器1:大家好。 我们将开始。 我认为,人们仍然要 是在过滤。 但因为时间的关系,所以我们可以 让你们离开这里的时候, 我们将要开始。 所以,欢迎到CS50测验0条评论。 对于那些你还没有意识到谁 然而,你必须在周三的问题。 宇豪。 如果你还没有开始研究,或尚未 还没有意识到这还不存在, 过去的测验和有关的所有信息 您的测验上cs50.net/quizzes。 这里也有一些不错的东西放在那里, 从过去10过去的测验 年以及信息 有关本测验和主题 将被覆盖。 所以,让我们开始吧。 所以你们可能还记得,第一次 一流的大卫每天对这些灯。 所以基本上,一切都变 就在一台计算机的引擎盖 二进制进行。 二是指它的声音是什么 等,0和1的。 它有两个值,即 可以被表示。 所以就像在节的第一天 当大卫打开一盏灯 球来表示,或者1,我们的电脑 懂二进制的0和 1的,打开或关闭。 二进制的基础。 每个地方的代表 在基地2。 所以,你加2到0至 1至2一路上扬。 要计算你的二进制文件是什么 十进制,你只要按照这个公式 类型的事情。 如果你有一个1在其中任何一个地方, 您可以通过乘以什么 基地是在加了起来, 你得到的小数点。 因此,这是怎么算 5二进制。 就像我们在做什么的 最后一张幻灯片,这是你会如何 代表1到5。 同样,就像你可以添加和 减去十进制或基10,或 任何真正的基地,就可以添加 并减去二进制。 你会什么期望时​​,你 添加两个起来,如果它等于更大 比1,你随身携带1,使之成为0, 做加法的方式,只是 就像你所期望的定期 小数或任何其它位置。 酷。 所以像我,以前的一切说, 我们的计算机的引擎盖下继续 在0和1的,或二进制完成。 那么,我们如何表达,例如, 字母或数字或字符? 而这个问题的答案是ASCII码。 ASCII是字符之间的映射 我们会在常看到 英语类的A,B的, C'S,下划线,破折号和 类似的事情。 它映射了一个ASCII值。 ASCII值仅仅是一个数字, 可以通过你的计算机可以理解。 就这样,你可以做加法和 减法与数字,你可以做 他们的ASCII值。 所以在本例中,什么 这将打印出来? 是啊,所以只是一个空间B空间c空间 D.在哪里我的鼠标去了? 请注意,你可以在65定义为int。 而当你使用打印出来 %的C,它会解释,作为一个 性格和打印出A。 同样,你可以声明 它作为一个字符。 而当你使用百分比打印出来 C,它会解释,由于 百分之四。就像你可以添加一个 号,可以添加字符 ASCII值,在这种情况下。 那么一点点的指针为大家。 5,作为一个字符串,不 实际上等于5。 那么我们如何转换 串5的整数5? 任何想法? 是啊。 因此,如果我们有5个为一个字符串, 我们可以减去0。 而这将给我们5。 同样,如果我们有5作为 整数,字符串添加0。 这给予我们的字符串5。 酷。 如今,回想起演讲之一, 我们谈到的算法。 那么,如何才能真正想要一台电脑 做有趣的事情? 你知道,只是加减 数字和印刷出来的东西是不是 令人兴奋。 通常情况下,我们希望我们的计算机 执行某种算法。 一些更复杂 不仅仅是简单的算术题。 一个算法就是一步步套 对于如何执行的指令 一定task-- 就像一个配方。 你可能还记得第一天 培训班里大卫指望我们的房间 人又有多少人 在房间里。 您可以用来计数 一个接一个。 1,2,3,4。 在这种情况下,一个线性时间算法。 但大卫介绍的算法 你算人在房间里 每个人都站起来,你说你的 号给他人,添加 号了,一个人坐了下来。 而你再说一遍。 这是一种算法。 我们可以分析一下如何有效的 算法是基于它的运行时间。 但我们会谈论一点点 稍后详细说明。 因此,所有的算法也 写成伪代码。 伪就像是一个英语 语法用来表示 一种编程语言。 例如,如果我们想问问用户 猜我最喜欢的数字,我们 可能具有伪代码本身。 获取用户的猜测。 如果猜测是正确的,告诉他们 他们是正确的,别人告诉他们 他们是不正确的。 和伪代码是很容易的方式 代表一个想法或一种算法。 所以,现在我们可能要实际写 这在语言的计算机 可能认识。 因此,我们可以写我们的伪代码和 理解到这一点的源代码。 到目前为止,源代码必须坚持 到了一定的语法 一种编程语言。 到目前为止,在CS50,我们已经 使用大多数是C被。 所以这可能是C语言源代码。 后来在使用过程中,你晚上来 与其它编程接触 语言如PHP。 或者,如果你甚至采取其他的类,你 可以做使用Java,Python,甚至OCML。 但是,在我们的C程序语言,这是 我们如何编写的源代码 伪代码算法 我刚才前面所述。 因此,如何真正做你的电脑 明白吗? 就像我之前,只说真的 理解零和一。 那么它是怎样从源头上得到 代码的东西,可以 明白? 那么,我们有什么 所谓的编译器。 如果你还记得早在大部分的 pset时,你有一些程序 写在一个点C文件。 然后,您可以键入化妆。 那么,是什么让做什么? 您可以键入make来编译 计划,因为someone-- 谁写的p将; 大概David-- 创建make文件。 并且告诉make知道你跑 编译器,叫做铛,这将 然后编译源代码,以反对 代码,这是零和一 您的计算机理解。 但过了一会儿,我们会去 更深入的了解编译器。 所以记得PSET 0,where--是, 你有问题吗? 听众:[听不清]? 扬声器1:是的。 我觉得他们其实 应该是在网上。 是啊。 听众:是不是像[听不清]? 扬声器1:不是。 在上cs50.net/quizzes。 听众:斜线测验,削减到2013年, 斜线0,只是通过点击 竞猜2013年和测验0, 审查部分幻灯片。 扬声器1:是啊,所以如果你们想 拉了起来,看着它在你的 自己的电脑,那也没关系。 再说一遍。 听众:[听不清]。 扬声器1:是啊,[听不清] 为虚拟变量。 哦,是吗? 听众:[听不清]? 扬声器1:没有,罢工 不在考试。 对不起,她的问题是,为 罢工的考试。 而事实并非如此。 所以PSET 0,你们应该都 使用临时实施的东西。 我们学到了一些基本的编程 采用从头构建块。 因此,让我们来看看一些 这些积木 组成一个程序。 首先是布尔表达式。 布尔表达式是那些与 0或任何有 两个可能的值。 在这种情况下,真的还是假的, 开启或关闭,是或否。 一个简单的,很简单的一个例子, 使用布尔程序 表现在这里。 因此,为了使布尔表达式 是有用的,我们有布尔运算符。 这些操作符可以使用 比较特定值。 因此,我们有和或不等于,小于 大于或等于,大于或 等于和小于 或大于。 但这些运营商并不十分有用 除非我们可以将它们组合成 条件。 所以你们可能还记得从头 并从p设置我们 有情况。 它们本质上是一样的叉 你的程序的逻辑 执行取决于是否 一个条件得到满足。 所以,我们有一个条件 在这个过程中多次使用的是 如果,否则,如果和其他条件。 这里有一个如何的例子 你可能会使用。 有谁知道之间的区别 if语句都只是用 下节如果,其他的方式, 如果和别人结合起来呢? 是吗? 听众:[听不清]。 扬声器1:没错。 所以,如果我有,如果沿着这条一路 这样,即使该状态下返回 如此,它仍然会继续 测试下两个。 然而,与其他人,如果一个else 语句中,如果返回true, 其他人都没有测试。 关于什么问题吗? 酷。 所以,你使用的if-else的其他内容 语句,如果你知道,它只能 是这些案件之一。 因此,我们知道,如果x小于0,它的 绝对不会是 大于0。 接下来,另一个积木 我们学到的循环。 我们有三种类型的循环。 for循环,while循环, 做while循环。 一般,当你坐下来 写的东西,你必须决定 要使用三种。 那么,我们如何决定哪一个? 我们一般使用for循环,如果我们知道 多少次我们要遍历 通过什么或多少次 我们要执行的任务。 我们使用whil​​e循环,如果我们需要一些 条件是真实的,以保持正常运行。 我们用做的,而非常相似, 一段时间,但我们希望我们的代码在运行 至少一个时间。 所以,做一段时间,无论是在DO线 总是至少运行一次。 然而,随着时间,它 可能无法运行在所有如 条件不成立。 有任何问题吗? 因此,一个结构循环。 你们都看到了这一点。 您初始化它。 你有某种条件。 因此,举例来说,我们可能会初始化 作为i等于0。 i小于10。 我+ +。 很简单的事,我们所做的一切。 对于一个while循环,同样的,你有 有某种初始化的, 某种情况下,与 一些更新。 因此,我们可以实现我们的for循环也 作为一个while循环利用这一点。 同样用do while循环, 我们可能有一些初始化, 执行的东西,更新,和 然后检查状态。 所以,现在的功能。 我们把一切融合在一起。 我们可能需要写一些 种功能。 常见的功能,你可能 看到已经是主要的。 主要是一个函数。 它有一个返回类型,int类型。 它有一个函数名,主。 它有参数,argc和argv。 因此,主要就是一个函数。 你可能已经使用的其他功能, printf--的printf是一个函数 - 调用getInt,TOUPPER。 但这些发生在已 实施为我们 一些库。 如果你们还记得,包括 这CS50.h库或 标准I / O库。 是的,问题? 听众:主要是用C只是固有的? 难道只是一种[听不清]吗? 扬声器1:现在的问题是 如果主要是内在℃。 是的,所有的功能 有一个主要功能。 这是一种必要的计算机 要知道从哪里开始 运行代码。 听众:那你会不会[听不清]? 扬声器1:第 还有没有其他问题? 酷。 所以,就像你可以使用一个函数 这是为你写的,你也可以 编写自己的功能。 这是一个功能,有人可能 写来计算容积 一个Q,例如。 有一个返回类型在这里,在这种情况下, INT,我们的函数名称Q和我们 参数列表。 并请注意,您必须写入数据 要的参数类型 使用,否则该函数不 知道什么样的 参数我应该接受。 所以,在这种情况下,我们希望 整数作为我们的输入。 那么,为什么我们要使用的功能呢? 首先,伟大的组织。 他们帮助打破你的代码 更多的组织块,使 它更易于阅读。 简化。 这是很好的设计。 当你读一段代码 而主要功能是真的, 真的很长,它可能是更难 原因是什么回事。 所以,如果你把它分解成函数, 这可能是更容易阅读。 和复用能力。 如果你有一个代码块,它的被 所谓或运行多次, 而不是重写代码的10倍 在主函数中,你可能会 想重新使用它。 然后每次需要使用 一段代码,调用该函数。 因此,如果我们记得划伤, 我们也谈到了几个概念, 其中的一个线程。 线程是多的概念 代码序列 执行在相同的时间。 所以回想起大卫有一天1 你们算过的数 人在房间里。 从本质上讲,是怎么回事 上都是你们的人 运行单独的线程。 而这些线程都撞在了一起 得到某种答案。 同样,在刮,当你有 多精灵,你可能 有一只猫和一只狗。 他们会同时 运行自己的脚本。 即穿线的一个例子。 和其他的概念,这是 在从头开始介绍了事件。 而事件的多个部位时, 与对方你的代码进行通信。 在划痕,这时候你用的是 广播控制和我 接收模块。 而且,在习题集4,我们看到 事件一点点为好。 你们可能已经使用 在GEVENT库。 并有一个功能waitForClick 在你等待 为用户点击。 和你的点击,在这种情况下,将 该事件并等待点击是你的 事件处理程序。 而且,在整个运行你的pset 与工作有关的pset时,你 可能接触到 其中一些命令。 这就是你输入到您的 终端窗口或其他窗口 这显示了对你的G编辑, 本质上,浏览你的计算机。 因此,例如,ls列出了 一个目录的内容。 使目录中创建一个新的文件夹。 CD,改变目录。 RM,删除,删除文件 或者某些目录。 然后删除目录 删除一个目录。 听众:[听不清]? 扬声器1:是的,当然。 不好意思,问题是,如果你 建议把这个 在备忘单。 它可以帮助。 如果你有足够的空间,你可以把它放在。 它也只是一般够用了 要记住,因为当你使用它 你可能只想 有它记住。 这会让你的生活变得更加简单。 我有没有回答你的问题? 所以,现在,我们谈一点点 简单说一下库。 但是,这两个主要的,我们已经 使用至今在使用过程中有 标准I / O和CS50。 都包括什么样的东西 在标准I / O库? 是的,到目前为止,我们已经使用了printf的。 在CS50,我们使用调用getInt 和GetString。 和数据类型的字符串也恰好 在这CS50库中声明。 我们将讨论多一点深入了解 图书馆如何工作的,以及他们如何 用你的代码的其他部分交互。 但就是这两种主要的是我们 已经走在接触至今 过程。 类型。 这些都是很好的记住多少 每个类型由或代表如何 许多个字节的每个类型的requires-- INT,4个字节;字符,1个字节。 浮存金是4个字节。 什么是双? 听众:[听不清]。 扬声器1:是啊,所以浮动 但增加一倍的大小。 那么长? 听众:[听不清]。 扬声器1:确定。 什么是多长时间? 听众:[听不清]。 扬声器1:是的,加倍的诠释。 是的。 听众:[听不清]。 扬声器1:长[听不清]。 然后很长很长的两倍。 听众:没有,没有。 长仅仅是一个int。 它依赖于结构 前[听不清] 及诠释具有相同的尺寸。 [听不清]。 扬声器1:那么漫长而 int类型是相同的。 再长的长 是双INT。 酷。 然后,什么是最后的类型? 听众:指针。 扬声器1:是的,所以我们学会了 约三分一点点。 也不管指针是什么 指着to--它可能是一个char明星 或int star-- 它总是4个字节的指针。 有关该问题? 是吗? 听众:[听不清]? 扬声器1:那么长的和一个int是 同样在这CS50设备。 听众:该设备是完全 互换。 扬声器1:是啊。 所以后来很长很长的两倍一个int。 听众:这是32位? 扬声器1:32位,是的。 听众:所以[听不清]? 扬声器1:是的,如果它不 明确地说,你 应承担32位。 听众:它会说什么 像假设的 建筑类的设备。 对于64位的唯一的事情, 变化是long和指针。 他们都[听不清]。 扬声器1:是吗? 听众:问。 因此,在实践测验之一, 它询问一个unsigned int。 因此,如何将是决定 从一个int [听不清]? 扬声器1:一个无符号 在同样4个字节。 但是,什么是有关签署不同 int和无符号整型? 听众:[听不清]。 扬声器1:对。 一个可以代表负值。 但它是如何做到这一点? 听众:[听不清]。 扬声器1:是啊,这样可以节省1 位来表示的符号。 签名的有一位是 代表符号。 和无符号仅仅是全部阳性。 听众:确定。 所以,你说,一个是双 一个浮动的两倍? 扬声器1:双两倍 一个浮动的大小,是的。 听众:如何做一个指针 到长隆[听不清]? 扬声器1:所以,问题是怎么做 指针长long-- 怎么只有4个字节时, 很长很长的8个字节。 所以,记得是一个指针, 本质上,在非常基础的值。 听众:[听不清]。 扬声器1:是啊,所以指针 仅仅是一个内存位置。 所以不要紧多少空间 该指针指向。 它仅需要4个字节来跟踪 的内存位置。 还有没有其他问题? 酷。 所以,过去的事情我有 是标准输出。 你应该使用它们经常 以至于你能记住。 但是,这是当我们使用 printf的,例如。 而我们这些占位符 被称为格式代码。 所以百分之c char字符,%的I为整数, 而且我们还可以用百分比Ð。 这是同样的事情。 但是,一般地,在CS50我们 尝试使用%的I。 百分比的f浮动。 LD百分比长和长 %的S代表字符串。 同样,我们一直在使用数 这些转义序列。 例如,反斜杠N代表新的生产线。 这仅仅是当你的格式 你的代码进行打印F。 是吗? 听众:什么是百分之D代表? 扬声器1:所以问题 是什么%的D代表? 百分比d为为整数。 百分比D和百分之i是相同的。 听众:有什么的区别 反斜杠n和反斜线R' 扬声器1:所以,问题是有什么 反弹n和区别 反弹R' 我觉得反斜线Řis-- 听众:所以反斜线Ř只是意味着 返回到行的开始 没有实际去一个新的生产线。 所以,如果你打印一个反斜杠r和你 回到该行的开头 那么您打印更多的东西,您覆盖 的东西,这已经在 [听不清]。 然而,正实际上进入到一个新的 线并进入[听不清]。 扬声器1:嗯,没有其它问题? 好吧。 我将它交给 丹谁将会继续。 [掌声] DAN:所有用右手。 因此,我将谈论另一个广 来自属于类思想范围 大约有代表性两周和 本周三开始出发 拥有铸造,这是只是一种方式 治疗某些类型的值作为 不同类型的值。 因此,我们可以用字符来做到这一点 整数,浮点数到整数,并 长期多头增加一倍。 所有这些东西可以作为方法 一种治疗某些数值的 减炭一些其他 数值。 因此,有一些问题这一点, 当然,当你投来的 之类的东西浮到整数。 所以这是一个有点怪异。 我们有一个浮动是1.31。 我们10,000相乘。 然后我们将其打印为int。 这是什么输出? 10000次1.31。 所以13000,是猜测? 观众:我认为这是一万元。 丹:所以我10,000乘以它 之前我投它。 听众:哦。 那岂不是有1个9 有的0号? 丹:你可能有一些奇怪的数字。 所以,正确的,它的1.3倍10,000元。 这就是13000。 而这额外的weird-- 听众:13,100。 DAN:13,100。 谢谢,罗布。 而这额外的weirdness-- 这9,9-- 很简单,因为这件 结束了向下舍入其中 它不应该有。 是啊。 听众:铸件发生 以后别的什么吗? 丹:是因为我有这样的,印刷的,它 做这个乘法之前 这是否铸造。 听众:[听不清]。 丹:我想会先投, 是的,这将是10,000元。 还要别的吗? 酷。 因此,这是13099。 为什么会这样? 不精确。 花车是不完美的。 他们只能代表数字一 若干显著数字。 因此,如果我们在打印出8 SIG的无花果 这个浮球,我们得到了一种 难看的数字。 那是因为1.31不能准确 可以通过简单的表示 两个机器的权力。 所以,它最终以最接近 猜,这结束了 是有点低。 有意义吗? 行。 现在,切换为不同的方式 这样做的条件语句,所有 我们关心的是一个单一的变量。 所以在这个特定的例子中,我们 获取来自用户的整数。 然后,我们正在寻找 什么是整数。 据推测,它的数量 与第一和第四。 这就是我们要求的。 所以,你要做的开关 变量名称。 然后你建立可能的案件 值可能有关系。 所以,案例一,说这是低的。 然后你打破脱身 的开关状态,以便 你不继续下去。 在接下来的case-- 所以案例二和案例three-- 如果是情况2,它只是下降到 代码的第一行就认为与 案例三,直到看到一个突破。 因此原因,你得到的情况下一个 仅打印低是因为我 这里有这样的突破。 如果我说,忽略了这个break-- 如果我把这个breakaway-- 它将打印低,然后它会 打印中,然后它会断裂。 所以休息时间是一个重要的组成部分 开关条件和 他们应该在那里。 未明确规定的个案 由默认处理 案例中的开关,应投。 听众:那1,2,3, 4为N? DAN:价值是n即可。 是的。 是吗? 听众:所以当你有 在[听不清]? 丹:你将打印低,然后 它将打印中间,并 那么它会打破。 听众:为什么会打印 中间如果[听不清]? 丹:所以根据案件的一切 前下破下降。 因此,案件一个打印是下面情况 一个作为这列打印。 是吗? 听众:[听不清]? 丹:所以这个数字仅仅是一个特定的 值,该变量 可以了吧? 这是否有道理? 是啊。 听众:[听不清]? 丹:是的,案例2将打印 中间再突破。 听众:[听不清]? 丹:我觉得任何? 还有什么其他的数据类型 你能切换? 听众:您可以切换 以上的任何数据类型。 但它只是意味着任何超过个字符 和整数之类的东西,因为 如果你切换指针 这并没有真正意义, 切换负载,如果它甚至让我们 你这样做,因为浮点说, 在精确度,你不会真的 要做到这一点呢。 这么漂亮多了,只是整数和 字符之类的东西。 丹:是的,这是当你有明确的 值,你知道,我认为,可以 一个开关实际上是有用的。 好不好? 行。 范围是声明的范围 可变的延伸。 因此,在这个代码块小我, 这将是完全错误的。 而原因就是我声明此诠释 这个范围的循环中岛 然后我试图引用 I的,对循环范围之内。 所以基本上,你可以考虑一下范围 如任何声明 用大括号内只 存在这些大括号内。 如果你尝试使用该变量 这些大括号外面,你会 获得来自编译器的错误。 是吗? 听众:所以这个也不行? 丹:这是不行的,肯定的。 字符串。 串一个char *。 他们是完全一样的。 他们只是指向字符。 那您有任何字符串应该结束 用反斜杠零,这就是 一个C约定。 这就是所谓的NULL结束。 和NULL-- 资本氮,大写的U,资本 L,资本L-- 是不一样的 NULL结束。 这是一个指针。 这是一个字符。 他们是非常不同的。 记住它。 这将是对测验,大概。 我还没有看到测验。 是吗? 听众:那空是,比如说,指针? 丹:是的。 听众:是什么[听不清]? 丹:如果说,malloc的调用,当你 没有足够的内存来获得 无论你要求的尺寸, malloc的返回NULL。 这是,基本上,每当一个函数 应该返回一个指针,你 需要核对NULL,因为 null是一个漂亮的good-- 这是,排序,垃圾的价值。 这是一个零尽可能指针走。 当你调用一个函数, 返回一个指针。 你会想要检查是 确保该指针不为NULL 因为空是很常见的。 这有点垃圾的回报。 所以,如果事情没有去正确的, 刚刚返回NULL来代替。 听众:[听不清]? 丹:是的,这就是这个。 听众:[听不清]? DAN:拼写它,因为这。 这是NULL结束。 这是小写的n-U-L-L,如果 你拼了。 听众:我刚去 背部和测试它。 如果你试图把一个浮点 值转换开关,它会骂你 他说,声明需要表达 的整数类型。 丹:你去那里。 但是,是的,究竟是什么问题又来了? 听众:[听不清]? 丹:所以资本氮,大写的U,资本 L,资本,L是一个实际的C件事。 这是空指针和意志 只有这样看待。 你永远不会尝试拼 NULL字符和看到任何 除此之外的方法。 是吗? 听众:所以回国为char或最大 东西在音符,将它 体现了相同的功能 为[听不清]? 听众:所以你指的是 从getchar函数返回的字符最大,或 不管它是什么? 听众:是的。 听众:是啊,所以一般 长期为所有这些事情 是定点值。 因此,像从调用getInt返回int最大 从getchar函数字符最大,它的 应该是这样,那好吧,如果 这些东西都返回给我们, 出事了。 为指针,我们只是碰巧有 该标记值,每个人都 同意后。 这就是你回来的东西 当事情出错。 因此,焦炭max是我们正在使用的是什么 代表什么 如NULL或的getchar。 听众:所以,如果你正在测试的getchar, 可能你只是把空? 会有所作为? 丹:你不能只检查空。 你必须检查字符最大,因为 从函数返回值是 一个字符不是一个指针。 是吗? 听众:这个问题问 字符串长度。 这是否包括NULL字符? 丹:没有。 而这实际上是字符串的长度如何 知道要停止,因为它通过 您的字符数组,直到 它看到一个空字符。 然后,它像所有 没错,我完成了。 听众:[听不清] 5? 丹:你好是5。 是的。 所以数组是连续 的存储器块。 他们可以即时访问说的 数组的名字,然后,在大 牙套,不管指数你想要去 到,他们是从零到索引 减去1的阵列的长度。 他们正在用的类型声明 那你存储的东西 阵列,该阵列的名称,然后 无论大小是数组。 因此,这是长度的字符数组 6有这些值。 是吗? 听众:[听不清]? 丹:是的。 听众:[听不清]? 丹:如果你有什么事 入阵已经作出。 所以,你可以指定,而不是以此为, 比如说,焦炭,无论名称的 数组是空的方括号等于花 振奋ħ逗号ê逗号Ł逗号Ł逗号 Ø逗号NULL字符 和大括号。 这也将作为一个声明。 听众:[听不清]? DAN:然后,你需要有 规模已经作出。 听众:[听不清]? 丹:是的。 所有用右手。 命令行参数的方法 从用户为获得输入 参数为主。 主要有两个参数。 争论正被数 沿着命令行和传递 串载体或一个字符串数组 所有的参数。 所以,如果我说,所谓的功能,如 点了1个空格,2的空间,3, ARGC是4。 而在argv 0将是一个点了。 Argv1将是1。 argv2将2 argv3会 3,在特定的情况下。 是吗? 听众:[听不清]? DAN:数组中的最后一个元素 因为数组长度的argc加 1 ARGB的,最后一个元件 是NULL指针。 它的argc加1。 所以,我刚才说了,它的情况下, 会做argv 0点了。 ARGV 1是1 argv2是2的argv 3 3。 的argv 4,它是一个容量较大的 比的argc将是NULL。 这就是NULL指针。 是的。 那是因为字符串 一个char星是一个指针。 所以它必须是相同的类型。 是吗? 听众:两个问题。 所以一,什么是之间的区别 这和GetString超过一种类型的其他 在用户发动机? 其二,它是存储在 您最近的记忆? 所以像,GetString的会 是[听不清]? DAN:它在哪里存放? 我不知道它的存储。 听众:所以,其实,你知道如何任何 函数调用它的参数 被存储在栈? 所以argc和argv是参数主要 他们是在栈上,还是真的 只是上面的你在想什么的 堆栈的开始。 什么是另一部 的问题吗? 听众:那么什么是[听不清]? 丹:是的,它只是用不同的方式 的获取来自用户的输入。 这一次的稍微更高效, 这是顺手的脚本,因为你 只需将参数传递到您的主 功能,而不必等待 对于用户,如果你没有任何用户。 听。是啊,弄弦 将[听不清]。 它会存储你所需要的东西。 丹:是吗? 听众:[听不清]? 丹:是的,argv的0总是包括 点斜线函数调用。 是吗? 听众:[听不清]? 丹:是的,每个参数都 在NULL字符结束,因为他们 都是字符串。 听众:[听不清]? 丹:是的,argv中的argc是一个NULL指针。 听众:[听不清]? 丹:哦,是的。 是啊,对不起。 听众:所以[听不清]? 丹:所以现在的问题是,如果你有 命令行点斜线点了1,2, 会命令行的数量 论据有两个或会是3? 观众:我觉得它不 真正的问题。 我倾向于说,哦,你没有通过 当任何命令行参数, 很明显,你调用的函数。 所以,我倾向于用声音排除 在命令行功能 即使它的参数 包括argv中。 DAN:但如果是在test-- yeah--而且如果你说的东西 喜欢的argc等于3, 你在安全的地位。 是吗? 听众:[听不清]? 丹:我认为,如果不调用此 在argc和argv的字符串括号 但保留了相同的类型,只是叫 不同的像他们的东西 和b,是否仍然有效? 它仍然正常工作, 你只是 - 代替使用argc-- 你会用A和B。 是吗? 听众:[听不清]? 丹:所以,问题是GetString的是 将存储存储器中的堆 因为GetString的为char *。 它在人堆里,因为它存储内存 现在要求在实际的malloc 实施的GetString的。 好了,继续前进。 安全。 因此,要实现真正的安全,你靠不 1,你不许任何人进入任何 您的信息,这是为什么 每个人都建立自己的机器, 自己的操作系统,其所有 从头开始计划,显然 不要连接到任何其他机器 通过互联网。 所以,电脑是不安全的。 他们真的是。 我们必须相信其他人。 和安全的想法是,你 试图限制的量 你需要信任。 而你做到这一点的方法之一 就是通过加密。 密码学是,本质上, 我们有秘密。 有时候,我们必须通过我们的秘密 沿着通过,比方说,因特网或 其他事情。 我们不希望人们 要知道这些秘密。 所以我们我们的秘密加密成一个方法 我们希望没有人能搞清楚。 因此,我们used-- 通过这个类别 - 的过程中 事情像恺撒密码和 [听不清],这两者都是非常 加密的东西不安全的方式。 他们很容易找出他们 是和你的秘密是。 现实世界中使用的多 复杂的加密方案。 我们不会进入 不止于此。 调试。 GDB是最好的。 我要再次强调这一点。 用GDB所有的时间每 时间你有问题。 命令,在广发行是有用的 打破,你通过其中一条线 数,函数名,基本上是 凡在你的代码要停止, 并能够采取控制。 打印需要一个变量,并打印出 不管这个变量是在那 点在你的执行。 接下来将您执行 沿着一个步骤。 并加强在函数内部的步骤 在你执行。 其他的东西跑,这是怎么 你实际运行的代码。 继续采取所有必要的步骤 到达下一个断点。 还有很多很多的人。 找一找。 他们是伟大的。 是吗? 听众:[听不清]? 丹:是的,这是一个调试器。 因此,一个调试器是一个程序, 让你调试你的程序。 这不是一个程序,发现错误的 你,虽然这将是巨大的。 而在去年对我来说是搜索。 所以,我们谈到搜索的类型 大约在这个类是线性搜索, 这只是你通过每 搜索空间的元素,1 元素的时间,直到你找到什么 你正在寻找或直到您到达 您的搜索空间的末端,在这 点你说你找不到 你要找的元素。 而这需要在最佳恒定时间 这是0的1,最差线性 时间,这是0的n。 二进制搜索,它需要 肮脏的元素。 你去你的元素中间, 看你要寻找的元素 是比元件更大或更小 你是在中间。 这是更大的,你说的底部 您的搜索空间是你的 当前的位置,中间, 你重新启动该进程。 如果是更小的,你看说 这the--是啊,这是怎么回事? 听众:[听不清]? 丹:是的。 样的一个已经教任何形式 这个类是公平的游戏进行测试。 [笑] DAN:而事实上,你有没有 这样做的问题集,这是公平 游戏进行测试。 听众:我们能过目一下如何to-- 丹:这将是走了过来。 扬声器2:在实际的代码 [听不清]是study.cs50.net。 所以,如果你看一下实际问题 在合并排序页面 study.cs50.net,存在的代码 实现合并排序。 所以,你不必实施 它自己今晚。 但要确保你了解它,而 单纯的记忆。 听众:[听不清]? 扬声器2:合并排序页面 study.cs50.net,有一种做法是 即,如果您通过点击问题 的问题,在最后有一个 溶液,这是合并 排序的实现。 但要确保你了解它 而不是单纯的记忆 或复制下来。 听。一个完全有效的 考试问题会 像这里有一个列表。 这是什么表像后 的选择排序一步或 插入排序或什么的。 列表中的一个完整的循环。 所以,即使你没有最终需要 它的代码,你需要了解它 足以知道怎么回事 要修改这个数组。 丹:这是对我来说。 [掌声] 卢卡斯:嘿大家。 我的名字是卢卡斯。 我要谈的递归,所有 我们所学的种类,以及 所有指针点点。 行? 所以首先,递归。 这是什么意思是说, 函数是递归? 听众:自称。 卢卡斯:好,调用自身,是的。 所以喜欢这幅画,例如。 这就像里面的图片 的图象的等等。 因此,举例来说,你可以have--丹 这说的是二进制搜索。 一种方法,其中二进制搜索是 递归是你的事实 试图找到一个号码。 所以,你去中间。 然后检查是否有数字 在左和右。 然后,如果你发现了数量为 要在左边,这是相同的 为再次做搜索的事情,但 只是在列表的左边。 所以这是它的声音 喜欢它的递归。 所以这就是为什么你们有递归 解决方案归并排序。 好了,这里有一个例子。 所以我们可以说,我想选择 所有的数字从1到n。 我也意识到,n的总和 数为n加N减1至1。 但是,如果我看以n减1加 Ñ​​减2加1,这是相同的 作为求和号的事 直到n减去1。 所以我可以说的平等和之和的 等于n,减去1的n个加的总和。 这是否有道理? 而且我也有别的东西 称为基的情况下,它是 数的总和最多 零是零。 所以,当我到达数 零,我停止计数。 这是否有道理? 因此,这里有一个如何的例子 我可以实现这一点。 所以我有一些这样的功能。 这需要一个整数n。 所以在这里我首先检查是否n是 小于或等于零。 所以,如果是小于或等于零,我 返回零,这是我们的基本情况。 否则,我只能返回否加 的数字从和 1到n减1。 有意义吗? 行。 因此,这里是什么样子。 你有2等于总和 2加1的总和。 而一些1是1加 总和为0,即0。 有意义吗? 因此,如果我们看一下堆栈的 程序,这是什么样子。 首先,我们的主要功能。 然后在主功能 所谓的总和2。 然后和2会说,哦,总和 2等于2加一的总和。 所以我加1和堆栈。 与1之和为要拨打的总和 0时,其也将被加入 到堆栈中。 然后每个这些那些是 在另一个上面有回 之前,其他的人可以继续下去。 因此,例如,这里,0相加, 首先,将要返回0。 然后选择1和。 然后的1之和为要 返回1总结2。 最后,2之和为将 返回3主。 这是否有道理? 这是非常重要的,了解如何 堆栈的工作,并尝试 看它是否有道理。 OK,这样排序。 那么,为什么是排序重要的是, 首先? 我们为什么要关心? 任何人吗? 举个例子? 是吗? 听众:[听不清]。 卢卡斯:是的,确定。 这样你就可以更有效地进行搜索。 这是一个很好的方式。 因此,举例来说,我们有很多的 的东西,其实,在我们的生活中 进行排序。 例如,词典。 这是非常重要的,以把所有的 在某种顺序的话,我们 可以轻松地访问。 这就是他在说什么。 可以更有效地搜索。 想起来有多难将有 字典中的词语是在 随机顺序。 你必须看,好看多了, 每一个字,直到找到 一句话,你要寻找的。 如果你使用Facebook还时 你看你的朋友,你是 要看到,Facebook的把你的 仔细的朋友的上的那些顶级 你不要跟那么多。 如果你走一路的底部 你的好友列表,你会看到 的人,你可能甚至不 请记住,你的朋友。 那是因为Facebook的种种 你的朋友的基础上如何 关闭您是给他们。 因此,组织数据。 也口袋妖怪。 所以你看,所有的小宠物 有数字。 这就是像一个简单的 存取数据的方式。 听众:访问口袋妖怪。 卢卡斯:是的。 听众:[听不清]。 卢卡斯:是的。 好了,选择排序。 选择排序是要选择 列表中最小的未分类的每个值 时间在每一次迭代。 这有点像你做的那种 在你的头脑,当你试图 排序手头上的列表。 基本上,所有你要做的就是你 为最小的数。 你把它在排序列表。 然后你去找 下一个最小的数。 然后你继续做 该等等。 因此,选择排序,基本上是你 选择每次最小 未分类的价值。 把在排序结束 该列表的一部分。 并继续这样做。 因此,让我们赶紧看看 这看起来像。 因此,这里的排序 和未排序的列表。 这样的排序列表, 它最初是空的。 然后我会选择 最小数目在这里,这是2。 所以我得到了2号,我把 在列表的前面。 然后我找下一个最小 元件,它是3。 所以我把它在最后 的排序列表。 然后我一直在这样做。 我发现4,并把它在末端。 查找5,并把它在末端。 以及怎么看待那些时代的 我是说把它放在结尾是, 基本上,交换两个值。 行? 然后最后一个,你只 多了一个元素。 因此,它已经排序。 好了,插入排序。 插入排序,你要去也有 中有一个排序的事情, 一个未排序的列表。 唯一的一点是,每一次 您要添加的元素排序 列表中,你只要挑元素 在未排序列表的前面。 然后你会发现什么 位置应该是在所划分的 该列表的一部分。 让我们来看看这是什么,所以 这更有意义。 所以一开始,例如,我想 插入的数目3 列表排序的一部分。 因此,列表不会有什么。 所以,我可以把数字3。 现在,我想5号添加到 列表的排序的一部分。 所以,我看5号。 我注意到,这是大于3。 所以,我知道,那一定是3后。 所以我把3和5。 然后,我想插入数字2。 我注意到,2号居然是 最后则两个3和5。 所以,我居然还要把它所有的 方式在列表的开头。 所以,我必须这样做,种,将所有 在分类列表中,这样我可以元素 令空间的数量2。 然后,我看到的数字6。 我认为,它应该是在5。 所以我把它放在那里。 最后,我看4号。 而且我注意到它应该 介于3和5。 然后我把它放在那里,移 所有其他元素。 有意义吗? 冒泡排序。 因此,冒泡排序,基本上是你在做什么 要do--我们称之为泡沫 那种因为你通过列表​​中 - 它实际上是更好,如果我只是展示 你喜欢this-- 你要去比较 相邻的号码。 而且你要交换他们 如果他们没有立场 以正确的顺序。 所以基本上,看到的是什么 发生在这里,例如, 你有8个和6个。 你知道的排序顺序会 实际上是6和5,对不对? 所以,你要交换的订单。 然后,我看到8和4在这里。 我做同样的事情。 我换了。 最后,图2和8。 我也掉他们。 这就是所谓的冒泡排序,因为后 每个迭代,其实, 最多列表中得到所有 的方式向列表的末尾。 这是否有道理? 因为它保持它的交换 并且将它移动到右侧。 好了,这是第二个迭代。 这将是同样的东西。 我会做一个交换和 然后最后一个。 í不存在互换 和列表进行排序。 所以在冒泡排序,我们基本上保持 经历名单和交换 事情直到我注意到,我没有做 任何掉期这样做迭代,这 意味着列表已经排序。 有意义吗? 让我们来谈谈一点点 有关运行时间。 所以,不要你们还记得大 O,欧米茄,和Theta? 是吗? 好了,什么是大O,首先? 听众:[听不清]。 卢卡斯:是的,这就是所谓的最坏情况 运行时,它只是意味着它的 你所期望的程序多少 取来运行。 如,在上of-- 在这个case--ñ。 中的元素的数量 列表中的最坏情况。 如,在最坏的情况下。 因此,对于冒泡排序,例如, 我们有N多的大O。 为什么我们呢? 为什么冒泡排序大OÑ多? 听众:[听不清]。 卢卡斯:是的,所以最坏的情况下会 我必须做n次迭代。 所以每次迭代将要 带来的最大的元素,以结束 的列表。 因此,最坏的情况是,我有 要做到这一点的事情n次。 并为每个时代,我要 做了N互换,因为我有比较 每两个元素。 所以这就是为什么它的Ñ平方 因为它的n次ñ。 然后,选择排序是也可为N平方 因为,每一次迭代,我要 看每一个元素 在列表中。 然后找到最小的, 这意味着我必须 期待通过n个元素。 而我所要做的是n次,因为 我要选择所有的n个元素。 插入排序是也可为N平方 因为在最坏的情况下会 是,一,我要插 n个数,对不对? 所以,我已经知道我要去 有n次迭代。 但对于每一个这些数字,如果我有 把所有的数字中 排序列表,并把它所有的方式 在前面,该将为n平方 因为这将为n n次重试。 有意义吗? 怎么样欧米茄? 听众:[听不清]。 卢卡斯:这是最好的情况。 所以,这就像在很多次的 排序,最好的情况下是 当列表已经排序。 所以,你真的没有 做任何事情。 冒泡排序有最好的 情况的n。 难道你们知道为什么吗? 听众:[听不清]。 卢卡斯:是的,如果你防不胜防 数据配给是否有任何掉期或 不,如果你碰到这样的设置 如果有一个迭代中,如果真 名单已经排序,基本上, 什么事情要发生是我要去 试换每两个 相邻的元素。 我要看到 有没有掉。 我只是回来的时候了。 因此,这意味着我不得不 通过列表一次。 因此,它是N,因为我期待 在n个元素。 为什么选择排序Ñ方? 是啊,即使列表进行排序,对于 选择排序的每次迭代,我 有选择最小的元素。 因此,这意味着我必须出去找 在未排序的所有元素 列出并找出最小 对于每一次迭代。 这是否有道理? 和插入剑的,因为Ñ 情况下我试图插入 号码和所有的数字,当我 尝试插入他们,我看到他们 在正确的位置上。 我没有去检查所有的其他 在未排序的列表编号。 所以,这就是为什么它会为n。 有意义吗? 什么是时间值损耗? 听众:[听不清]。 卢卡斯:什么,对不起? 再说一遍。 听众:[听不清]。 卢卡斯:没错。 所以,你可以看到只有选择 存储在归并排序有θ驱动。 那是因为你只有西塔 如果这两个大O和欧米茄是相同的。 行。 最后,合并排序是在为log N。 然后,作为丹说,合并排序 是一种像同样的方式, 你做的二进制搜索。 所以,你得到的清单。 而且你会在半切。 然后把它们剪掉 在较小的一半。 然后将它们合并。 你们记住这一点,对不对? 好了,因为他说的话。 好了,指针。 那么,什么是指针? 听众:[听不清]。 LUCAS:一个地址。 行。 我知道大卫展示了一堆 宾基和视频的东西指着 彼此。 但我喜欢把指针 为仅仅是一个地址。 因此,这是即将变 以存储一个地址。 所以它只是这个特殊的变量 这是4个字节长。 请记住,该指针是什么 总是4字节长为32位 机,以便与外壳 家电。 它只是有位置 它里面的变量。 好了,有这个记忆,基本上是这样。 因此,每个内存块实际上有一个 标签,这是在地址 slotty内存。 因此,这意味着我可以有 指针指向 所有这些地址。 那么,为什么我们要使用指针的原因是 如果我要记住位置 一个特定的变量是内存。 和你们记得其中的一个 案例是,如果我有一个函数 如果我真的想你 掉期为实数,其实我 必须发送一个指针。 不变量。 难道你们还记得吗? 所不同的between-- 名称是什么? 按价值计算,调用调用 参考了吧? 好吧,是的。 所以,通过值调用。 当你刚发一个变量 发挥你只是发送一个值。 所以你实际发送 该变量的副本。 和你的程序一点也不在乎 关于是否真正相同的变量 进行复印。 并呼吁参照指 实际上,我送的副本 指针指向的变量。 因此,这意味着我要送的 该变量的位置。 所以感觉我的位置 可变的,当我打电话的功能 使用指针,我能够真正 改变是在主数据。 有意义吗? 虽然,指针是复印件, 指针仍具有的实际地址 我想改变的变量。 有意义吗? 所以创建的指针。 请记住,指针总是有 它的指向的类型 到,然后一个明星。 然后你把这个名字。 所以请记住,只要你有 什么明星,它就像一个指针 ,无论变 输入您了。 因此,这里在星,例如,它的 指针和一个整数。 然后炭星是一个指针 炭星等等。 是吗? 听众:如果我们有一个 指针到n明星的X. 我知道,创建一个指向x的指针。 它也x声明为整数? 卢卡斯:好了,当你说北辰X, 你没有创建一个指向 变量x。 您正在创建一个名为x的指针。 听众:[听不清]。 卢卡斯:所以当我说北辰X,我 他说,嘿,在内存中,我将 让这三个框之一。 而我会说,那 将是x,它 将是一个指针。 和一些有趣的指针 就是我们说他们有 4个字节的32位机。 和用于其原因是因为 4个字节的32位。 和机器都是64位的实际 有地址的指针 这是64位长。 因此,它只是意味着的大小 在机器的地址是不同的。 因此,引用和间接引用。 有两个运算符 你们应该还记得。 第一是符号。 二是明星。 不要误会由明星和这 STAR因为记得,在 这种情况下,你有n个明星。 这就像一个整体的东西在一起。 有否N空间的明星。 因此,这意味着,它的类型。 请记住,当你拥有 变星,你是 谈论的类型。 当你只有明星,然后 变量的名称,它意味着 你提领的指针,它 也就是说你正在看 指针,找到地址是 指向,将这个地址, 看着那无论何时 你在那里。 所以我告诉我的学生,当你有 明星,你应该认为这是 的内容的缩写。 所以,如果你有一个指针,你 做明星的指针,它的 该指针的内容。 所以,你去到任何它的指向 并期待在恒定内容。 而符号是一样的 东西的地址。 所以,如果我有A--像一个变量,让我们 说我做的int a等于3-- 如果我想找到该地址 变量的存储,我可以做 &符号à。 因此,它的地址。 有意义吗? 因此,这里有一个例子。 这是缺少INT B和诠释三。 所以的int a = 3意味着 我打算去记忆。 我要去寻找一个插槽 和把数3此处。 然后INT b等于c 4。 我会做同样的事情。 转到内存放了一些 4在一个箱子。 和INT等于5。 发现了另一个盒子,并把数字5。 那么,什么是这行做了呢? 北辰PA等于符号à。 所以,首先,正星PA。 它是什么做的? 听众:[听不清]。 卢卡斯:是的,所以北辰PA,第一, 声明了一个名为PA指针。 然后它的分配的值 该指针是一个地址。 所以连字号à。 然后,如果我做星PB, 什么是星PB? 哦,对不起。 这也不翼而飞。北辰PB。 我的意思是明星的PC。 我很抱歉。 这是同样的事情。 但现在我很好AR创建一个指针 到B,然后指向到c。 是吗? 听众:[听不清]? 卢卡斯:是的。 所以,如果你去记忆和你去 盒子是代号为PA, 你究竟要 看到了一个地址。 行? 是吗? 听众:[听不清]? 卢卡斯:是的,指针是一个地址。 永远不要忘记这一点。 这就像最重要 部分有关指针。 还有存储和地址 一些变量。 还要别的吗? 还有没有其他问题? 行。 所以,指针和数组。 请记住,当我做int数组3, 基本上,我在做什么是我,那种 的,在声明一个指针。 所以数组是一种像一个指向 在内存中特定的地方中,我 分配三个插槽的整数。 这是否有道理? 所以,当我做int数组3,就是我 这样做,基本上是创建三个 插槽中的内存。 所以,我只是觉得在内存中三个插槽。 所以,如果我这样做,那么,星阵,它 基本上意味着阵列的内容, 这意味着我删除的指针,我走了 到那个地方,它的指向, 我把头号。 然后,如果我做星阵加1, 这是同样的事情,因为这样做阵列 支架一个,这只是意味着我去 它的指向的地方。 然后加1品牌 我移动一个位置。 于是我去到这个位置,实际上, 并把两个数。 然后,终于,当我做 阵加2,我去哪里 阵列的指点一下。 然后我移动到内存块。 然后我把三号这里。 是吗? 听众:所以星阵简直是 说的第一点。 你还可以加1,只是因为 我们只有真正 在引用的第一个地址。 卢卡斯:是的。 我们为什么,例如,假设数组 0,阵列1和阵列2? 我是说,你为什么这样做0, 1,2,3,而不是1,2,3? 其中一个原因是,一个,计算机 程序员喜欢开始 从0开始计数。 二是因为当你做阵列0, 这是同样的事情,因为这样做阵列 加0,这意味着我去 那个位置,我不 跳过任何存储器块。 所以,我不动任何内存块。 是吗? 听众:[听不清]? 卢卡斯:所以她叫什么 这样的区别 这或做的malloc。 一的区别是 int数组3是创建一个 数组在栈上。 当我这样做的malloc,它 在堆上创建。 这是否有道理? 那么,如何malloc的实际工作? 那么,为什么我们甚至需要使用malloc? 你的编译器种人物所有 你声明的变量。 而他所有的创造空间 他们在堆栈中。 因此,所有的变量都将 在某处的堆栈。 因此,这里的环境变量。 所以基本上,空间,这些变量 在内存分配在 编译时间。 因此,这意味着你的电脑有 要知道所有这些变量的 事前。 它并不需要知道什么样的价值 你要放他们。 但是,它需要知道如何 你需要多少内存。 但现在让我们说,例如, 你要创建一个数组或采取 字符串,你正在做 从所述用户。 你不知道过了多久字符串 将是,例如。 所以,你不知道到底有多少 你分配的内存块,对不对? 因此,它并没有真正意义的 你说把100个字符。 然后,如果用户写150? 你会拧。 所以基本上,你不能确定如何 您需要分配多大内存 当你编译的程序。 你只知道,在运行时间。 所以这就是为什么你必须堆。 所以堆将会有记忆 您在正在分配 时间程序运行。 所以基本上,当你这样做的malloc什么 你正在做的,是分配内存 运行时,这意味着你 决定在那一刻的权利,你 应该有存储器。 所以,当你分配它。 这是否有道理? 所以请记住,栈有变数 这是在编译时创建的。 然后堆有变数 那你去创建 使用malloc,例如。 听众:[听不清]? 卢卡斯:那么GetString的是 要调用malloc。 让我谈谈malloc和 我会解释的GetString。 所以malloc的是同样的事情 内存分配。 因此,它会分配 存储在堆中。 而且它会返回一个指向 如该内存被分配在。 当你do--所以 这里example-- 北辰指针。 然后指针相等的malloc 英寸的10倍大小。 我创建一个指针。 然后我分配的指针 的指针,该指针的malloc的值 是给我的。 所以我问的malloc可以分配你 空间为10的整数。 这就是它的说法。 和malloc给我回一个 指针指向的地方。 有意义吗? 行。 i和GetString的是,基本上,做一个 打电话的malloc,所以你可以分配 在运行时内存。 一定要记住检查null 因为malloc的是要返回null 如果无法分配内存。 比方说,你问了一个可笑的 内存量。 您的电脑不会是 能够分配那么多。 所以malloc的只是去 返回NULL。 所以永远记得检查 您从得到的malloc指针 空或不是,因为如果是这样,你可能 被提领的指针和 导致侧故障。 最后,不要忘了 您的可用内存。 malloc的是创建存储在堆中。 而且你要释放内存 前程序结束。 好吧,这就是我。 对不起,罗布。 谢谢。 [掌声] 卢卡斯:最后还有什么问题 之前抢来? 不是吗? 是吗? 观众:我没看到 这个网上。 你已经上载了吗? 卢卡斯:我认为大卫是 很快上传。 戴夫:这将被张贴。 卢卡斯:这将是在网上。 听众:这是最高。 卢卡斯:这事? 行。 是吗? 听众:[听不清]? 卢卡斯:是的,你应该释放所有的 这被放置在堆内存中。 听众:[听不清]? 卢卡斯:是的。 任何时候你有一个文化的malloc, 你应该有自由文化 在您停止使用该变量。 所以malloc和free的 永远在一起。 他们最好的朋友。 是啊。 罗布? 罗伯:我去快。 而且视频将被提了起来。 我的麦克风。 好了,每周五天的东西。 第一件事,我们是堆栈。 因此请记住,只有一个堆 每个活动函数调用框架。 我们会看到,在一秒钟。 还记得究竟去 在每个堆栈帧将要 我们的函数的局部变量, 被传入的参数我们 功能,再加上一对夫妇 其他的事情你真的不 需要担心的。 因此,这里是一个示例程序,其中, 的通知,主要是printfing回报 富4的值。 富只是要返回 的4条6逗号价值。 酒吧是要设置一些当地的 变量n等于4倍6。 然后返回否。 因此,让我们来看看整个堆栈 这个程序的实际迭代。 所以这是我们的堆栈的底部。 请记住,堆栈长大。 所以在我们的栈底,我们 有主堆栈帧。 当程序启动时,主 总是要处于 我们的堆栈底部。 什么是我们的内部 堆栈帧主? 因此,即使没有本地 变量主,就像我之前说的, 我们argc和RGV占用空间 里面主要的栈帧。 所以主要是现在要 调用函数foo。 这意味着foo的是要 让自己的堆栈帧。 所以,现在我们的内部 函数foo。 什么需要去 Foo的堆栈帧? 那么,富有一个参数n。 而n等于4,因为那是什么 主要是通过为富的说法。 所以,现在富会打电话吧。 什么是酒吧将有内 它的“堆栈帧? 它具有点¯x等于4 Y等于六。 这还不是全部,我们将不得不 因为在酒吧的堆栈帧 也有局部变量n。 而n我们将设定为24。 所以,现在酒吧是要返回否。 因此,巴将返回24 堆栈帧富。 而由于酒吧现在回来,那 意味着我们出栈帧 在酒吧从堆栈中。 因此,所有的酒吧一直是记忆 用现在堆栈。 现在,富也要去 回到24主。 所以,现在富正在恢复,内存 在富用其' 堆栈帧也不见了。 而现在,主要是要调用printf。 所以printf的只是另一种功能。 当我们调用printf,这将是 对于printf的另一个堆栈帧 函数调用。 什么是我们传递的printf? 这是怎么回事去 在它的堆栈帧。 最起码,我们传递 即%的I反斜杠n和 参数24。 它可能有更多在它的堆栈帧 如果printf的碰巧使用一些 局部变量。 我们不知道。 但是,所有的云在printf中的 堆栈帧。 这将执行中的printf。 随后的printf的实现。 它会回来。 最后,主做。 主会回来。 然后我们的程序就完成了。 是吗? 听众:你看到[听不清] 参数[听不清] 参数? 罗伯:所以是有细微的差别 之间的参数和参数。 真的,在共同的说话,人们往往 只是混淆了所有的时间。 但是参数是正规 的东西的名称。 所以argc和argv是 参数为主。 争论实际上是你 传中的那些参数。 所以,当我调用foo 4,4有 是我传递的​​参数。 和参数n,内 富,取值为4 因为4是参数。 听众:[听不清]? 罗伯:n是吧一个局部变量。 n是本地还是要富,但 这是一个参数为foo。 这不是一个局部变量。 是吗? 听众:[听不清]? 罗伯:富时打电话是酒吧和 返回不管酒吧的回报。 听众:[听不清]? 罗伯:是啊,刚看到多 堆栈帧。 是吗? 听众:为什么叫做foo 之前的printf? 罗伯:printf的前为何被称为富? 这样我就可以有,而是做了一些 如int x等于4富 再印的X. 而是,我结合了功能 调入的printf参数。 但是请注意,我们不能真正 执行调用printf,直到我们 弄清楚了4 foo是。 所以,我们要评估这个。 只有一次这样做了会 回来和评估的。 是吗? 听众:因为这两个栏[听不清] 价值,为什么我们没有[听不清]? 罗伯:他们完全应该是int。 这是没有抓到过 多遍。 因此,它应该是i​​nt酒吧和INT 因为这两个的富 正在返回的整数。 虚空只有当他们不打算 返回的实际值。 是吗? 听众:如果你有一个以上的行 返回[听不清]? 罗伯:上面返回的行? 听众:是的。 就像如果你做了printf和[听不清] 将其打印了两次? 罗伯:所以富里面? 如果我们有一个printf就在这里? 听众:是的。 罗伯:所以,如果我们有一个正确的printf 这里,是将打印一次。 由于我们调用foo一次正确的 在这里,然后我们会打的printf。 然后我们会打电话吧。 再富将返回。 就是这样。 我们只遇到过 在printf的一次。 是吗? 听众:[听不清] printf的调用foo,因为我们是第一 调用printf的,然后我们传递 的论点。 罗伯:所以在理论上,是不是 printf的调用foo? 因此,没有。 只是为了使c为要 执行这些东西,我们才可以 调用一个函数,所有的参数 该函数必须 彻底评估。 因此,这是完全评估? 是的,它只是一个字符串。 这只是一个值。 然后,我们必须彻底 评估此。 一旦这样做了,现在所有的 它的参数进行评估。 现在,我们可以使 调用printf。 是吗? 听众:有一个问题。 如果你有一个void函数,必须 你有回报分号? 罗伯:你不是一回分号 如果你有一个void函数。 行。 所以,现在有些堆东西。 所以堆是我们要如何应对 动态内存管理。 而这直接与对比 堆栈,我们称之为自动 内存管理。 因此,在堆栈上,你从来没有真正有 处理如何局部变量 正在入栈和出栈关闭所有 这些堆栈帧和所有的东西。 你不必为此担心。 这是自动的。 所以堆是手动的。 和[听不清] 来自这些功能 malloc和free。 因此,这里的其他程序。 我们所要做的就是mallocing 的整数。 我们将它存储在明星的X. 当然,我们要检查 看是否x是零。 然后,我们将只设置什么 x被指向到50。 打印x的值指向, 打印X,然后自由的X. 所以,这是怎么实际去看看 如果我们看一下我们的堆栈和堆? 因此,我们将重新开始。 我们的叠层作为前底部。 请记住,你直接堆 反对栈? 因此,我们将有 我们堆的顶部在那里。 所以我们的栈底,我们有 我们的主堆栈帧。 它具有的argc,argv的空间,而我们 现在有一个局部变量x,它 是一个int明星。 所以,我们要遍历 通过这一方案。 第一件事,我们是 调用malloc的。 因此,我们正在做一个调用malloc的。 是的malloc函数。 这将得到一个堆栈帧。 什么是我们通过对malloc? 这是怎么回事里面去 堆栈帧。 我们路过N,也就是4的大小。 因此,传递函数malloc。 什么是malloc的呢? 它抓住了我们堆了一些空间。 所以我们会去堆。 而且我们要抢 4个字节从堆中。 所以让我们只给了 的任意地址。 为0x123假装这是一个 地址,它是在堆上。 那么究竟是怎样的里面 内存地址为Ox123区域? 垃圾。 所以,我们没有存储在它的任何东西。 因此,据我们所知, 可以是任何东西。 你不应该假设它是零。 这是最有可能不为零。 所以,现在的malloc返回。 而我们该怎么做时malloc的回报? 我们所设置的返回。 我们集合X等于什么 它返回。 那么什么是回归? 它的返回为0x123自认为是 的存储器块的地址,它 只是在堆中分配的。 因此,返回为0x123 x被现在要设定 等于为0x123的,形象地, 我们经常画为x具有实际 箭头指向该块。 但是,x只是存储的地址。 所以,现在我们要检查如果x为null。 这不是空。 我们假装是malloc的成功。 所以现在星x等于50。 因此,星记得这意味着 去那个地址。 所以,0x123的我们要 去那个地址。 所以这给我们带来了那里。 什么是我们在该地址在做什么? 我们要存储50。 所以,这条线之后,那是什么 事情进展到什么样子。 所以,现在它不再 垃圾在那里。 现在我们知道,50是在 具体地址,因为 我们设置了这一点。 行? 所以,现在我们将要打印的F。 因此,首先我们要打印的明星的X. 那么,什么是星X你是否 再次,星x表示去 事情是X指向。 所以x被存储为0x123去那。 我们得到了50。 因此,打印˚F的。 这意味着它要打印50。 然后返回。 然后我们有了第二个printf。 我们现在百分之页。 如果你还没有看到它,这就是 只是你如何打印一个指针。 因此,我们有百分之一,百分之 f和所有那些已经是。 因此%的磷,打印一个指针。 因此,x是一个指针。 所以,如果我们要打印的X本身, 我们正在打印什么是真正的内部 x,它为0x123所以首 打印f被付印50。 第二印刷f的准备 打印0x123的呀? 听众:你用百分比 X要打印的指针? 罗伯:所以你用百分比 X要打印的指针? 所以,你可以,但百分之x是公正的, 概括而言,就像如果你有一些 整数,要打印 它作为一个十六进制数。 这只是你如何做到这一点。 然而,百分比D会 打印为十进制。 这是我们得到的百分比 ð。 i是刚刚整数。 %的p是专 为指针。 因此,x是一个指针。 我们要使用百分之页。 但百分之x可能工作。 是吗? 听众:[听不清]? 罗伯:是啊。 至少在这个call--所以我 不包括在这里。 不过,这两种说法都必然 该堆栈帧中 以及任何局部变量 printf的碰巧使用。 然后下次调用printf的现在 printf的内部堆栈帧 %的p反斜杠n和不管 x值是,这是为0x123。 是吗? 听众:[听不清]? 罗伯:这将打印的东西 看起来是这样的。 听众:[听不清]。 罗伯:所以它打印它的地址表。 它看起来像一个地址。 是吗? 听众:[听不清]? 罗伯:为什么呢? 听众:[听不清]? 罗伯:这是为什么指针4个字节? 因此,有一大堆 0的在这方面。 因此,它是真正0x0000000123。 在64位系统上,将有 一大堆的多个零。 是吗? 听众:[听不清]。 罗伯:所以第一个printf 将要print-- 听众:[听不清]。 罗伯:是的,这是怎么回事打印 x的值指向。 明星说:这是什么 事指向。 抓住它。 那么什么是指向? 50。 抓住它。 这就是我们将要打印。 然而,下一个,我们 刚刚打印X本身。 什么是f里面? 为0x123。 行。 然后,终于,我们有自由。 什么是我们传递给释放? 我们传递的X. 那个时候我居然显示 它的堆栈帧。 所以我们传递的价值 0x123的释放。 所以,现在免费知道,没事的, 我必须去到堆 自由内存。 它不再使用的是什么 在地址为0x123。 所以,自由即将推出 从堆。 现在,我们的堆是空的了。 我们没有内存泄漏。 现在免费将返回。 注意,x是仍然为0x123。 不过,现在是不是有效的内存。 我们不再提领的X. 是吗? 听众:是返回0冗余? 罗伯:是returen 0冗余? 是的。 我们只是把有原因 我们有一个空气回流之一。 所以,这就像,嗯,让 包括返回0。 是吗? 听众:[听不清]? 罗伯:所以免费后X,如果发生了什么 我们尝试取消引用指针? 这有可能是万无一失。 这是可能的,我们还是会得到50。 这是可能的,也即该内存 现在正在使用的东西。 所以这是不确定的行为。 和未定义意味着什么 可能发生。 是吗? 听众:[听不清]? 罗伯:无,因此,如果您指定 X要别的东西。 所以,如果在这里我们说的x等于 malloc的东西else-- malloc的大小event-- 那么原来的块 内存不释放。 我们已经正式失去了它。 这是一个内存泄漏。 我们已经失去了所有的引用 到存储器块。 所以没有办法,我们可以不断释放它。 好了,再回到0来完成。 好吧,那么堆栈溢出。 这里有什么想法? 所以请记住,堆正在下降。 堆栈是怎么回事了。 因此,这是从演讲的例子, 我认为,其中主要的是只是要 调用此函数foo,这是怎么回事 递归调用自身过去, 一遍。 所以堆栈帧要 工作完全相同。 所以,我们要开始主 作为底部堆栈帧。 然后主要是要调用foo,这 会得到一个堆栈帧。 然后,富是要调用foo 再次,这是会得到 另一个堆栈帧。 然后又一次,又一次,又一次, 又一次,直到最后,我们运行 入堆。 因此,这是我们如何得到 堆栈溢出。 在这一点上,你赛格故障。 或者你真的赛格故障前 这一点上,却是的。 听众:是核心转储 同赛格错吗? 罗伯:所以你会看到分割 故障的核心转储。 你会得到一个核心转储时, 你赛格故障。 它就像所有的转储 您当前内存的内容,以便 你可以尝试找出 为什么你赛格故障。 是吗? 听众:[听不清]? 罗伯:所以分段错误方式 有一个堆栈溢出。 所以不一定。 段错误意味着你 触摸记忆的方式 你不应该。 使发生的一种方式是,当 您堆栈溢出,我们开始触摸 记忆体的方式,我们不应该。 是吗? 听众:[听不清]? 罗伯:所以的无限循环中。 喜欢,这就像一个无限递归 循环,所以我们得到另一个 堆栈每个时间帧。 只是里面的一个普通 无限的,而埃德蒙顿 好了,让我们甚至没有打印F-- 做一些事情。 不管。 我们不会将越来越 另一个堆栈帧。 我们只是要保持循环 在这个单指令。 堆栈没有增长。 这是事实,每个递归 电话是给了我们一个堆栈帧。 这就是为什么我们得到一个堆栈溢出。 是吗? 听众:如果你说得到 while循环,然后按[听不清]? 罗伯:所以,如果内部的while循环 有一个printf,你仍然会 不赛格故障。 我只是不希望的事情混淆。 它会循环。 你会得到一个堆栈 框架中的printf。 随后的printf会回来。 然后你再就不断循环。 你会得到一个堆栈 框架中的printf。 它会回来。 单栈帧。 所以,你没有得到这个无限 堆放堆栈帧。 听众:[听不清]? 罗伯:是的。 所以这个堆栈溢出发生 因为没有这些 调用富都回来了。 因此,如果我们回来,然后我们会 开始失去堆栈帧。 然后我们就不会堆栈溢出。 这就是为什么你需要一个基本情况 为您的个人功能。 是吗? 听众:是对潜在的尺寸和 栈堆一样的 所有的程序? 罗伯:大约。 在堆叠的电势的大小和 堆相同的所有项目? 粗略。 有一些随机化 其中栈开始和 其中堆开始。 如果你碰巧有一大堆 全局变量和的事情,你可能 从一些空间带走 你堆。 在64位系统上,你几乎 有无限怀念。 这里还有这么多。 之间的32位和64位,即 是显著差。 你会得到一大堆更多 在64位堆栈和堆空间 制度,因为只是多 解决了他们可以使用。 但单个系统上,它会 是一叠大约相同数量的 和堆空间。 好吧。 所以最后一件事是编译。 所以,你应该知道这个过程。 有四个大的步骤。 所以,第一个应该 很容易记住。 预处理。 它具有预先在它的前缀。 所以,说到一切之前。 要记住的是哈希值。 因此,散列定义和散列包括 在所有这些的。 这些都是预处理器 指令。 这些事情了 预处理器需要照顾。 那么什么是预处理器吗? 这是一个非常愚蠢的事情。 所有它的能力是所有这些 复制和剪切和粘贴操作。 因此,散列包括标准I0点小时。 那是什么做的? 它抓住了标准I0点ħ 文件并将其粘贴到顶部 无论它说散列包括 标准I0点小时。 和任何散列定义,我们已经 可见,那是什么做的? 其复制的值的哈希 定义的被定义为和粘贴的 无论你使用的值。 所以预处理器少了点真的 基于简单的文本操作。 它什么都不聪明。 所以,一切是 更为复杂。 所以,现在预处理器 完成后,我们实际编译。 那么,是什么编制是什么意思? 我们现在从C代码中去 为汇编代码。 是吗? 听众:[听不清]? 罗伯:是的,我们抓住了这一点。 所以编译。 我们打​​算从C到装配。 因此,这是一个实际的语言变化。 编译本身就意味着从去 更高层次的语言 低层次的语言。 和c是一个高层次的语言 相比于装配。 什么是组件? 它的指令是,相当 多了,做了你的CPU。 但是你的电脑仍然 不明白组装。 这只能理解和0。 因此,下一步的组装,这 使我们从这些指令 你的CPU的理解,实际上 它们翻译,以 1和0。 所以C到组装成二进制。 但我没有一个可执行的呢。 所以想CS50库。 我们已经为您提供了二进制 这CS50库,里面有GetString的 和调用getInt和所有。 但CS50 library-- 在itself--和不可执行。 它不具有一个主函数。 这只是一堆二进制 您可以使用。 所以链接是我们如何把所有 这些不同的二进制文件 成实际的可执行文件。 一,你可以键入 点斜线点出来。 因此,这是类似于文件,你 写道: - 无论你的程序is-- 塞瑟C点。 但现在它被编译 下降到二进制。 所以塞瑟点O操作。 这是我们CS50库二进制。 而且他们正在结合 成一个单一的可执行文件。 是吗? 听众:[听不清]? 罗伯:所以首先包括,记住, 哈希包括实际上是一个 预处理器步​​骤。 但是,这是不同的。 如果你不使用任何函数, 是你的单文件之外,那么, 不,你不需要任何链接 因为你拥有了一切。 这就是说,printf的被链接英寸 如果你用printf,这东西 需要在要链接 因为你没写。 并且,实际上,printf的是自动 在联系。 你知道如何在命令行或者当 你键入make,你看它有 破折号升CS50,它有链接 在CS50的图书馆? printf的,和类似的东西,是怎么回事 将自动链接的。 在任何其它的问题吗? 听众:[听不清]? 罗伯:链接? 我们有一大堆 不同的二进制文件。 这就是典型的例子 我们用的是CS50库。 我们已编制并提供给您的 二本CS50库。 您要使用的GetString 在你的程序。 所以,你去使用GetString的。 但是,如果没有我的二进制代码 GetString的,当你编译你的代码 下来,你不能真正运行 计划,因为GetString的String是 尚未完全确定。 只有当你在我的二进制链接 包含的GetString,现在,所有的 没错,其实我可以 执行GetString的。 我的文件是完整的。 我可以运行了。 是吗? 听众:是否链接转换 二进制文件到可执行? 所以,即使你没有其他 图书馆,是不是仍然是 要翻译 在[听不清]? 罗伯:所以可执行 仍然是二进制。 它只是结合了全 一串二进制文件。 听众:非常感谢你。 罗伯:没问题。 还有没有其他问题? 否则,我们的所有设置。 好吧。 谢谢。 [掌声] 听众:谢谢。 罗伯:是啊。