Tip:
Highlight text to annotate it
X
[Powered by Google Translate] [CS50图书馆]
内特 - 哈迪森] [哈佛大学]
[这是CS50。 CS50.TV]
CS50库是一个有用的工具,我们已经安装在设备上
使您更轻松地编写程序,提示用户输入。
在这段视频中,我们将拉回来的窗帘,看看究竟是什么在CS50库。
>> 在C库上的视频,我们来谈谈如何#include头文件
你的源代码库中,
然后你链接的二进制库文件中的链接阶段
编译过程。
头文件指定的库的接口。
也就是说,他们的所有细节,图书馆的资源供您使用,
像函数声明,常量和数据类型。
二进制库文件包含了执行的库,
这是从库的头文件和库的C源代码文件编译的。
>> 二进制库文件看,因为它是,在二进制,是不是很有趣。
所以,让我们来看看库,而不是在头文件。
在这种情况下,只有一个头称为cs50.h.的文件
我们已经安装了它在用户目录
随着其他系统库的头文件。
>> 你会注意到的第一件事情之一是,cs50.h#包括从其他库的头文件 -
持股量,范围,标准的布尔值,标准库。
同样,不重新发明轮子的原则,
我们已经建立了的CS0库使用的工具,为我们提供。
>> 接下来的事情,你会看到在图书馆,我们定义一个新类型,叫做“string”。
这条线真的仅仅是创建一个别名为char *类型,
所以它不会奇迹般地灌输新的字符串类型与属性
通常与其他语言的字符串对象,
如长度。
我们已经做到了这一点的原因是保护新的程序员的血淋淋的细节
的指针,直到他们准备好了。
>> 下一个部分的头文件声明的功能
,CS50库的提供以及相关的文档。
在这里,请注意信息的详细程度。
这是超级重要的,让人们知道如何使用这些功能。
我们宣布,在功能来提示用户并返回字符,双打,花车,整数,
长期的渴望,和字符串,用我们自己的字符串类型。
信息隐藏的原则,
我们已经把我们定义在一个单独的C语言实现文件 - cs50.c -
在用户的源代码目录。
我们已经提供了该文件,你可以看一看,
从中汲取教训,并重新编译它,如果你想在不同的机器上,
即使我们认为这是更好的工作设备上的这个类。
无论如何,让我们来看看它现在。
>> 的的功能GETCHAR,GetDouble,GetFloat,调用getInt,GetLongLong
全部建成的GetString函数。
事实证明,基本上都遵循相同的模式。
他们使用一个while循环来提示用户输入的一行。
他们返回一个特殊的值,如果用户输入一个空行。
他们试图解析用户的输入,作为适当的类型,
无论是一个字符,双,花车等。
然后他们返回的结果,如果输入成功解析
或者它们重新提示用户。
>> 在较高的水平,这里没有什么真正棘手的。
你可能会写自己在过去类似的结构化的代码。
也许最神秘的前瞻性部分是sscanf的调用,分析用户的输入。
sscanf函数的输入格式转换系列的一部分。
住在标准io.h,它的工作是解析一个C字符串,
根据一个特定的格式,存储在变量中的解析结果
所提供的主叫方。
由于输入格式转换功能是非常有用的,广泛使用的功能
不超直观的第一,
我们就去了如何sscanf的作品。
>> sscanf的是一个char *的第一个参数 - 一个指向字符的指针。
对于机能得以正常工作,
字符应该是一个C字符串的第一个字符,
空\ 0字符终止。
这是要分析的字符串
到sscanf函数的第二个参数是一个格式字符串,
通常通过在一个字符串常量,
,你可能会看到一个这样的字符串时,使用printf之前。
格式字符串中的百分号表示转换符。
该字符紧跟一个百分号,
表示,我们希望sscanf的转换为C型。
在调用getInt,你看,有一个%d和%C。
这意味着,sscanf的将尝试一个十进制整数 - % - 和一个char - %C。
对于每一个转换中指定的格式字符串,
sscanf的预计,相应的参数后,在其参数列表。
这个参数必须指向一个相应类型的位置
要在其中存储的转换的结果。
>> 典型的方法,这样做是在栈上创建一个变量前sscanf的调用
对于每一个项目,你要解析的字符串
然后使用地址操作符 - 符号 - 通过指针
这些变量的sscanf的调用。
你可以看到,在调用getInt,我们正是这样做的。
前sscanf的调用,我们称为n声明一个int和一个char调用C堆栈上的,
我们sscanf的调用指针传递给他们。
把这些变量在栈上优于使用空间分配
的堆用malloc,避免malloc调用的开销,因为你,
你不必担心内存泄漏。
没有前缀一个百分号字符不提示转换。
相反,他们只需要添加的格式规范。
>> 例如,如果格式字符串在调用getInt%d代替,
sscanf的寻找字母a,后面跟着一个int,
,虽然它试图将其转换为int,它不会做任何事情的一个。
唯一的例外是空白。
格式字符串中的空格字符匹配任何数量的空白 -
甚至都没有。
所以,这就是为什么注解中提到的可能与领先的和/或尾随的空白。
所以,在这一点上它看起来像我们sscanf的调用尝试将其解析用户输入的字符串
通过检查可能的前导空格,
其次是一个int值将被转换并存储在int变量n
一定量的空白,后面的字符
存储在char变量c。
>> 的返回值呢?
sscanf的解析输入线从开始到结束,
停止当它到达末尾时,或当一个字符在输入
不匹配的格式字符,或当它不能转换。
它的返回值是用来挑选时停止。
如果它停止了,因为它已经达到结束的输入字符串的
之前,作出任何转换之前,不匹配的格式字符串的一部分,
特殊常量EOF返回。
否则,它返回成功转换的数量,
这可能是0,1或2,因为我们已经要求两个转换。
在我们的例子中,我们要确保用户输入一个int,并仅使用一个int。
>> 所以,我们希望sscanf的返回1。知道为什么吗?
如果sscanf函数返回0,则没有转换,
所以用户键入的输入开始时的int以外的东西。
如果sscanf的返回2,然后用户没有正确地键入它在在开始的输入,
但他们在一些非空白字符,然后键入后
因为%c转换成功了。
哇,这是一个相当冗长的解释为一个函数调用。
无论如何,如果你想sscanf的和它的兄弟姐妹的更多信息,
检查手册页,谷歌,或两者。
有很多的格式字符串选项,
而这些可以为您节省大量的手工劳动时,试图解析字符串C.
>> 在图书馆看的是最后一个函数GetString的。
事实证明,GetString的是一个棘手的功能,正确写,
即使它看起来像一个简单的,共同的任务。
为什么会出现这样的情况呢?
好吧,让我们想想我们要如何来存储线,用户键入的
由于字符串是一个字符序列,
我们可能要存储在一个数组在堆栈上,
但我们需要知道过了多久数组是要当我们声明。
同样,如果我们想要把它的堆,
我们需要通过对malloc我们要保留的字节数,
但这是不可能的。
我们不知道用户输入多少字符
之前,用户实际上并键入它们。
>> 这个问题是只保留一大块的空间,比方说,一个天真的解决方案
在一个块的1000的用户的输入的字符,
假设用户将永远不会输入一个字符串,它长。
这是一个坏主意,原因有两个。
首先,假设,用户通常不键入字符串中的那么长,
你可能会浪费大量的内存。
在现代化的机器,这可能不是一个问题,如果你这样做
在一个或两个分离的情况下,
但是,如果你在一个循环中用户的输入,存储供以后使用,
您可以快速地吸了一吨的内存。
此外,如果你写的是一个较小的计算机程序 -
在内存有限的设备,如智能手机或别的东西 -
该解决方案将导致问题的速度快了很多。
第二,更严重的不这样做的原因是,它让你的程序脆弱
什么所谓的缓冲区溢出攻击。
在编程中,缓冲器是用来临时存储输入或输出数据的存储器,
在这种情况下,这是我们1000字符块。
过去的块数据被写入时发生缓冲区溢出。
>> 例如,如果一个用户实际上在超过1000个字符类型。
你可能已经经历过这样的意外编程时数组。
如果你有10个整数的数组,没有什么可以阻止你试图读取或写入
15日的诠释。
有任何编译器警告或错误。
该计划只是失误直行和访问内存
如认为第15的int,这样就可以覆盖其他变量。
在最坏的情况下,可以覆盖一些程序的内部
控制机制,从而导致你的程序执行不同的指令
比您预期。
>> 现在,它是不是共同做这个意外,
但是,这是一个相当普遍的技术坏人破坏程序
在其他人的电脑上,并把恶意代码。
因此,我们不能只用我们的天真的解决方案。
我们需要一种方法来防止我们的计划是脆弱的
一个缓冲区溢出攻击。
要做到这一点,我们需要确保增长,因为我们阅读我们的缓冲区
更多的来自用户的输入。
该如何解决呢?我们使用堆分配的缓冲区。
因为我们可以改变它的大小调整realloc函数,
而我们跟踪的两个数字 - 在缓冲区中的下一个空槽的索引
和缓冲区的长度或容量。
我们读到chars中从用户1在一个时间使用fgetc函数。
fgetc函数需要的参数 - STDIN - 是一个参考的标准输入字符串,
预连接的输入信道,用于传输用户的输入,这是一个
从终端到该程序。
>> 每当用户键入一个新的角色,我们要检查一下,如果索引
下一个空闲槽加1是大于缓冲区的容量。
+1,因为如果下一个可用的索引为5,
然后我们缓冲区的长度必须是6感谢0索引。
如果我们已经用完了空间,在缓冲区中,然后我们尝试调整它的大小,
一倍,使我们的次数减少,我们调整
如果用户是在一个很长的字符串输入。
如果字符串中已经得到了太长时间,如果我们运行的堆内存,
我们释放我们的缓冲区,并返回null。
>> 最后,我们追加字符的缓冲区。
一旦用户点击进入或返回,标志着一个新的生产线,
或特殊字符 - 控制D - 信号输入,
我们做一个检查,看看如果用户输入的任何所有。
如果没有,则返回null。
否则,因为我们的缓冲区可能是超出我们所需要的,
在最坏的情况下,它几乎两倍大,因为我们需要
因为我们每年翻一番的时间调整,
我们的字符串,只是使用的空间量,我们需要一个新的副本。
我们增加了一个额外的1 malloc调用,
有特殊的NULL终止符的空间 - 在“\ 0”,
我们添加一旦我们在其余的字符复制到字符串,
使用strncpy而不是strcpy
因此,我们可以指定要复制我们到底有多少个字符。
STRCPY复制,直到它击中了\ 0。
然后,我们帮助我们缓冲的副本,并返回给调用者。
>> 谁知道这样一个看似简单的功能,可以这么复杂吗?
现在你知道什么进入CS50库。
>> 我的名字是Nate哈迪森,这是CS50。
[CS50.TV]