int scanf(const char *format, ...);
从 stdin 读取数据,按照 format 转译,并将结果存储到指定位置。
参数:
format
:指向指定读取输入方式的字符串指针,字符串内包含三种类型。
int num1 = 0;
int num2 = 0;
// 此时 scanf 中有 7 个空白字符(空白字符还有制表符、回车符等)
// 在实际输入中输入 1 个或多个空白字符都是可以正确读取的
scanf("%d %d", &num1, &num2);
int num1 = 0;
int num2 = 0;
// 如果在终端输入形式如下:12 31
// 那么此时 scanf 会直接返回,并不会将两个数字读取到 num1、num2
// 正确的输入形式应是:请输入第一个数字:12,请输入第二个数字:31
scanf("请输入第一个数字:%d,请输入第二个数字:%d", &num1, &num2);
...
:各接收实参,一个可变长度的指针列表。
&
符号就比较清楚了。如果没加 &
符号,将变量的值传递给函数,而 scanf 函数却把它解释为一个地址。当它被解引用将数据写入时,要么导致程序终止,要么导致一个不可预料的内存位置的数据被改写返回值:
当格式化字符串到达末尾或者读取的输入不再匹配格式字符所指定的类型时,输入就停止。被成功赋值的接收实参的数据即为返回值。
如果在任何输入值被转换之前文件就已经到达末尾,函数就返回常量值 EOF。EOF 是常量值 -1,与 ASCII 中字符都不相同,这是为了避免二进制被错误解释为 EOF。
format 的格式为:
%[width][modifiers]type
width(宽度,可选)是一个数值,用于指定当前读取操作中读取的最大字符数。
int num = 0;
// 如果在终端输入 1002,num 最多只能读取三个字符,所以 num 的值为 100
scanf("%3d", &num);
格式代码 | h | l | L | ll |
---|---|---|---|---|
d | short | long | long long | |
u | unsigned short | unsigned long | ||
f | double | long double |
限定符的主要目的是为了指定参数的长度。如果整形参数比缺省的整形参数更短或更长,在格式代码中省略限定符就是一个常见的错误。浮点类型也是如此。
如果省略了限定符,可能会导致一个较长变量只有一部分被初始化,或者一个较短变量的相邻内存也被修改。
double dNum = 0.0;
long double ldNum = 0.0;
// 如果只使用 %f,那么就会导致有一部分没被初始化
scanf("%lf", &dNum);
scanf("%Lf", &ldNum);
short int sNum = 0;
// 如果只使用 %d,那么就会导致相邻内存被非法修改,这极有可能导致进程崩溃
scanf("%hd", &sNum);
C/C++ 并没有具体规定各种数据类型占用大小,只是给了一些限制,因此不同编译环境下结果可能不同,下表为 g++ 4.8.5 下的结果。
数据类型 | 占用内存(32 位) | 占用内存(64 位) |
---|---|---|
char | 1 | 1 |
short | 2 | 2 |
int | 4 | 4 |
long | 4 | 8 |
float | 4 | 4 |
double | 8 | 8 |
long double | 12 | 16 |
type(转换字符,必选)的内容及含义如下:
转换字符 | 参数类型 | 含义 |
---|---|---|
c | char* | 读取单个字符。如果给出宽度,就读取给定数目的字符 |
d | int* | 十进制有符号整数 |
u、o、x | unsigned int* | 无符号整数。u 被解释为十进制、o 被解释为八进制、x 被解释为十六进制 |
f、g | float* | 浮点型字面值常量 |
s | char* | 读取一串非空字符串 |
p | void* | 读取一个指针(即内存地址) |
% | (无) | 两个 %% 就是 % 本身,与输入的 % 相匹配 |
注意:当使用 %s 格式时,要小心缓冲区溢出的情况,最好在前面显式地控制读取的最大长度。
缓冲区溢出:10 个 char 大小的数组,却读取了 20 个字符,多的这部分就是溢出的,这就有可能超出当前函数栈帧引发段错误,或修改了不该修改的内存地址。
int printf(const char *format, ...);
从给定位置加载数据,转换为字符串等价物,并将结果写到 stdout。
参数:
format
:指向指定数据转译方式的字符串,包含两种类型
...
:指定要打印的数据参数返回值:
如果函数调用成功,返回值是实际打印的字符数(不包含表示字符串结束的 ‘\0’);
如果函数调用失败,返回值是一个负数。
格式字符串的形式为:
%[flags][width][.precision][modifiers]type
flags 可以同时出现多个,且无顺序要求。
标志 | 含义 |
---|---|
- | 指定被转换的参数在其字段内左对齐(默认是右对齐) |
+ | 指定在输出的数前面加上正负号 |
空格 | 如果第一个字符不是正负号,则在其前面加上一个空格 |
0 | 对于数值转换,当输出长度小于字段宽度时,添加前导 0 进行填充 |
# | 指定下表的另一种输出形式 |
用于 | # 标志 |
---|---|
o | 保证产生的值以一个零开头 |
x、X | 在非零值前加 0x 前缀(%X 则为 0X) |
width(宽度,可选)是一个数值,用于指定要输出的最小字符数。
转换后的参数输出宽度至少要达到这个数值。如果参数的字符数小于该数值,则在参数左边填充字符(默认是空格)。
-
,要求参数左对齐的话,则在右边填充.precision(精度,可选),通过点号分隔字段的宽度和精度。
type(转换字符,必选)的内容及含义如下:
转换字符 | 参数类型 | 含义 |
---|---|---|
c | int | 参数被裁剪为 unsigned char 类型并作为字符打印 |
d、i | int | 参数作为有符号十进制整数打印 |
u、o、x、X | unsigned int | 参数作为无符号值打印。u 使用十进制;o 使用八进制;x 或 X 使用十六进制 |
e、E | double | 参数以指数形式输出单、双精度浮点数。小数点后面的位数由精度字段决定,默认是 6 |
f | double | 参数按照常规的浮点数形式打印。小数点后面的位数由精度字段决定,默认是 6 |
s | char* | 打印一个字符串 |
% | (无) | 打印一个 % 字符 |
注:如果 % 后边的字符不是转换字符,则其行为没有定义。