[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.
>> 在图书馆看的是最后一个函数Ge​​tString的。
事实证明，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]