c 编程/stdio.h/scanf
| 此页面可能需要通过引用可靠出版物来验证事实。 您可以通过添加对可靠出版物的引用或更正被引用为事实的陈述来提供帮助。 |
scanf 是一个函数,它根据指定的格式从给定的字符串流源读取数据,源于C 编程语言,并且存在于许多其他编程语言中。
scanf 函数的原型是
int scanf(const char *format, ...);
该函数返回成功匹配的项目总数,该总数可能小于请求的总数。如果输入流已耗尽或在任何项目匹配之前从该流读取操作失败,则返回 EOF。
就可追溯性而言,“scanf” 代表“扫描格式”,因为它扫描输入以查找有效标记并根据指定的格式解析它们。
scanf 函数存在于C 中,它从标准输入(通常是命令行界面 或类似的文本用户界面)读取数字和其他数据类型 的输入。
以下显示了 C 代码,该代码从标准输入读取可变数量的无格式十进制整数,并在单独的行上打印出每个整数
#include <stdio.h>
int
main(void)
{
int n;
while (scanf("%d", & n))
printf("%d\n", n);
return 0;
}
在被上述程序处理后,如下的凌乱整数列表
456 123 789 456 12
456 1
2378
将整齐地显示为
456 123 789 456 12 456 1 2378
要打印出一个单词
#include <stdio.h>
int
main(void)
{
char word[20];
if(scanf("%19s", word) == 1)
puts(word);
return 0;
}
无论程序员想要程序读取什么数据类型,参数(如上面的 &n)都必须是指向内存的指针。否则,该函数将无法正常执行,因为它将尝试覆盖错误的内存部分,而不是指向您尝试获取输入的变量的内存位置。
由于 scanf 被指定为仅从标准输入读取,因此许多具有接口 的编程语言(如PHP)具有 sscanf 和 fscanf 等派生函数,但没有 scanf 本身。
根据实际的输入源,程序员可以使用 scanf 的不同派生函数。两个常见的例子是 sscanf 和 fscanf。
fscanf 派生函数从指定的 文件流 读取输入。原型如下
int fscanf (FILE *file, const char *format, ...);
(PHP)
mixed fscanf (resource file, const string format [, mixed args...])
fscanf 派生函数的工作方式与原始 scanf 函数类似 - 读取的部分输入在文件关闭并重新打开之前不会被再次读取。
sscanf 派生函数从作为第一个参数传递的 字符串 读取输入。与 fscanf 的一个重要区别是,每次调用该函数时,都会从字符串的开头读取字符串。没有在成功读取操作时递增的“指针”。原型如下
int sscanf (const char *str, const char *format, ...);
(PHP)
mixed sscanf (const string str, const string format [, mixed args...])
int vscanf (const char *format, va_list args);
int vsscanf (const char *source, const char *format, va_list args);
int vfscanf (FILE *file, const char *format, va_list args);
这些函数与没有 v 前缀的相同函数类似,只是它们从 va_list 中获取参数。(参见 stdarg.h。)这些变体可用于可变参数函数。
scanf 中的格式化占位符 与其反函数 printf 中的格式化占位符 大致相同。
格式字符串中很少有常量(即不是格式化占位符 的字符),主要是因为程序通常不是为了读取已知数据而设计的。例外情况是 1 个或多个空白 字符,它们会丢弃输入中的所有空白字符。
以下是一些最常用的占位符
%d: 以带符号十进制 数字的形式扫描一个整数。%i: 以带符号数字的形式扫描一个整数。类似于%d,但在前面有0x时将数字解释为十六进制,在前面有0时将数字解释为八进制。例如,字符串031将使用%d读取为 31,使用%i读取为 25。%hi中的标志h表示转换为short,hh表示转换为char。%u: 扫描十进制unsigned int(注意,在 C99 标准中,输入值的负号是可选的,因此如果读取到负数,则不会出现错误,结果将是二进制补码。参见strtoul()。Template:Failed verification) 类似地,%hu扫描unsigned short,%hhu扫描unsigned char。%f: 以标准(定点)表示法扫描一个浮点数。%g、%G: 以标准或指数表示法扫描一个浮点数。%g使用小写字母,%G使用大写字母。%x、%X: 以无符号十六进制 数字的形式扫描一个整数。%o: 以八进制 数字的形式扫描一个整数。%s: 扫描一个字符串。扫描在空白 处结束。一个空字符 会存储在字符串的末尾,这意味着提供的缓冲区必须比指定的输入长度至少长 1 个字符。%c: 扫描一个字符 (char)。不会添加空字符。(空格): 空格扫描空白 字符。%lf: 作为双精度 浮点数扫描。%Lf: 作为长双精度 浮点数扫描。
以上可以在数值修饰符和 l、L 修饰符(代表“长”)之间复合使用,这些修饰符位于百分号和字母之间。百分号和字母之间也可能存在数值(在 long 修饰符之前,如果有的话),指定要扫描的字符数。百分号之后的一个可选的星号 (*) 表示通过此格式说明符读取的数据不应存储在变量中。格式字符串后面的参数不应包含此丢弃的变量。
printf 中的 ff 修饰符在 scanf 中不存在,导致输入和输出模式之间存在差异。ll 和 hh 修饰符在 C90 标准中不存在,但在 C99 标准中存在。[1]
格式字符串的示例为
"%7d%s %c%lf"
以上格式字符串将前七个字符扫描为十进制整数,然后读取剩余字符作为字符串,直到遇到空格、换行符或制表符,然后扫描其后的第一个非空白字符,以及其后的双精度浮点数。
scanf 通常用于程序无法保证输入格式正确的情况。因此,健壮的程序必须检查 scanf 调用是否成功,并采取相应的措施。如果输入格式不正确,错误数据仍然会保留在输入流中,必须在读取新输入之前读取并丢弃。避免这种情况的另一种读取输入的方法是使用 fgets,然后检查读取的字符串。最后一步可以使用 sscanf 完成,例如。
与 printf 一样,scanf 容易受到 格式字符串攻击 的影响。应非常小心地确保格式化字符串包含字符串和数组大小的限制。在大多数情况下,来自用户的输入字符串大小是任意的;它无法在 scanf 函数执行之前确定。这意味着使用没有长度说明符的 %s 占位符本质上是不安全的,并且可以利用缓冲区溢出。另一个潜在问题是允许动态格式化字符串,例如存储在配置文件或其他用户控制文件中的格式化字符串。在这种情况下,除非事先检查格式化字符串并强制执行限制,否则无法指定允许的字符串大小的输入长度。与此相关的是额外的或不匹配的格式占位符,它们与实际的 vararg 列表不匹配。这些占位符可能会部分从堆栈中提取,包含不希望的甚至不安全的指针,具体取决于 varargs 的特定实现。
/* 另一种仅在某些特殊编译器上有效的用法是
scanf("请输入一个值 %d",&n);
它会打印引号内的字符串,并在指示的 % 号处停止接受输入。*/
- : 输入格式转换 – Linux 库函数 手册
- C++ 对
std::scanf的参考
- ↑ C99 标准,第 7.19.6.2 节“fscanf 函数” 第 11 行。