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