[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]