printf()函数和scanf()函数能让用户可以和程序交流,它们是输出/输入函数,简称I/O函数。是库函数,给了一个标准,但是各个编译器的实现会有小部分差异。
虽然printf()是输出函数,scanf()函数是输入函数,但它们的工作原理几乎相同。两个函数都使用格式字符串和参数列表。我们先介绍printf()函数,再介绍scanf()函数。
1.printf()函数
1.1 基本用法
printf()函数的作用是把参数文本输出到屏幕,前面有说过,它名字里的f是指格式化,表示可以指定参数文本的格式。
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
示例程序 的输出为:Hello World
printf()函数不会在行尾自动增加换行符‘\n’,程序运行完成时,光标就会停留在输出结束的地方,,不会自动换行。
在这里小提一下单字符I/O函数:getchar()和putchar()
它俩每次只处理一个字符。这种阅读方式十分适合计算机。
注意看俩次程序运行的光标的位置。
想让输出结果换行:在想换行的地方添加换行符‘\n’0
printf()函数在使用的时候必须包含头文件stdio.h,否则会报错。
那么学到这printf()函数就结束了吗?并没有。
1.2 占位符
所谓占位符,就是占位的意思。看示例:
图中用红框框选中的就是占位符,右边输出是参数代替占位符。这%d、%s 就是占位符。占位符的第一个字符一律是%,第二个则是类型。 如果出现多个占位符如上图第三个printf()函数,就需要按顺序输入参数,(参数也需要是类型匹配的数据)否则可能会报错,也不能少输入参数,否则编译器会添加奇奇怪怪的值,还会报警告。
如果有n个占位符,那么printf()函数的参数个数就是n+1个,如果参数个数少与占位符,printf()函数可能会输出内存中的任意值。
占位符有许多,还有许多其他的修饰符以及标记,请看如下图表:
转换说明 | 输出 |
%a | 浮点数、十六进制数和p计数法(c99/c11) |
%A | 浮点数、十六进制数和p计数法(c99/c11) |
%c | 单个字符 |
%d | 有符号十进制整数 |
%e | 浮点数,e计数法 |
%E | 浮点数,e计数法 |
%f | 浮点数,十进制计数法 |
%g | 自动选择%f或%e |
%G | 自动选择%f或%e |
%i | 有符号十进制整数(与%d)相同 |
%o | 无符号八进制整数 |
%p | 指针 |
%s | 字符串 |
%u | 无符号十进制整数 |
%x | 无符号十六进制整数,0f十六进制数 |
%% | 打印一个% |
修饰符 | 含义 |
标记 |
表1.2.3 描述了5中标记(-,+,空格,#和0),可以不使用标记或使用多个标记。 示例:“%-10d” |
数字 |
最小字段宽度 如果该字段不能容纳待打印的数字或字符串,系统会使用更宽的字段 示例:“%4d” |
.数字 |
精度 示例:“%.5f”,表示小数点后的五位数字 |
h |
和整型转换说明一起使用,表示short int或unsigned short int 类型的值 示例:“%hu”,‘%hx’ |
hh |
和整型转换说明一起使用,表示signed char或unsigned char 类型的值 示例:“%hhu” |
j |
和整型转换说明一起使用,表示intmax_t或unintmax_t类型的值,这些类型定义在stdint.h中 示例:‘%jd’ |
l |
和整型转换说明一起使用,表示long int 类型的值 示例:‘%ld’ |
ll |
和整型转换说明一起使用,表示long long int 类型的值 示例:‘%lld’ |
L |
和浮点型转换说明一起使用,表示long double类型的值 示例:‘%Lf’ |
t |
和整型转换说明一起使用,表示ptrdiff_t类型的值。ptrdiff_t是两个指针差值的类型(c99) 示例:“%td” |
z |
和整型转换说明一起使用,表示size_t类型的值。size_t是sizeof返回的类型 示例:‘%zd’ |
标记 | 含义 |
- |
待打印项左对齐。从字段的左侧开始打印该项 示例:“%-20s” |
+ |
有符号值若为正,则在值前面显示+,若为负,则在值前面显示- 示例:‘%+6.2f’ |
空格 |
有符号值若为正,则在值前面显示前导空格(不显示任何符号),若为负,则在值前面显示减号标记并覆盖空格。 示例:“% 6.2f” |
# | 把结果转换为另一种形式。如果是%o格式,则以0开始;如果是%x格式,则以0x开始;对于所有的浮点格式,#保证了即使后面没有任何数字,也打印一个小数点字符。 |
0 |
对于数值格式,用前导0代替空格填充字段宽度。对于整数格式,如果出现-标记或指定精度,则忽略该标记 示例:“%010d” |
通过以上的表格,我们对它们进行组合,就可以达到我们想要的表达,如:限定宽度、总数显示正负号、限定小数位数、输出部分字符串等等。
以下是一些示例代码:(来自于c primer plus 中文版)
#include <stdio.h>
#define PAGES 959
int main()
{
printf("*%d*\n", PAGES);
printf("*%2d*\n", PAGES);
printf("*%10d*\n", PAGES);
printf("*%-10d*\n", PAGES);
return 0;
}
// 浮点型修饰符组合
#include <stdio.h>
int main()
{
const double RENT = 3852.99;
printf("*%f*\n", RENT);
printf("*%e*\n", RENT);
printf("*%4.2f*\n", RENT);
printf("*%3.1f*\n", RENT);
printf("*%10.3f*\n", RENT);
printf("*%10.3E*\n", RENT);
printf("*%+4.2f*\n", RENT);
printf("*%010.2f*\n", RENT);
return 0;
}
//演示一些格式标记
#include <stdio.h>
int main()
{
printf("%x %X %#x\n", 31, 31, 31);
printf("**%d**% d**% d**\n", 42, 42, 42);
printf("**%5d**%5.3d**%05d**%05.3d**\n", 6, 6, 6, 6);
return 0;
}
//字符串格式
#include <stdio.h>
#define BLURB "Authentic imitation"
int main()
{
printf("[%2s]\n", BLURB);
printf("[%24s]\n", BLURB);
printf("[%24.5s]\n", BLURB);
printf("[%-24.5s]\n", BLURB);
return 0;
}
2.scanf()函数
刚学完输出,接下来我们学习输入——scanf()函数。C库包含了许多输入函数,scanf是最通用的一个,因为它可以读取不同格式的数据。当然,从键盘输入的都是文本,因为键盘只能生成文本字符:字母、数字、标点符号。把这些字符转换为对应类型,这就是scanf()函数要做的。
scanf的使用请记住以下两点:
- 如果用scanf()读取基本变量类型的值,在变量名前加上一个&(键盘:shift + 7)
- 如果用scanf()把字符串读入字符数组中,不要使用&
2.1 基本用法
请看下面这个例子:
#include <stdio.h>
int main()
{
int score = 0;
// 给变量输入一个值
printf("请输入成绩:");
scanf("%d", &score);
// 输出到屏幕上
printf("成绩是:%d", score);
return 0;
}
scanf()函数是用来读取用户从键盘的输入 。程序运行到这儿时,会停下来,等待用户输入。用户输入后,按下回车键,scanf就会处理其中的数据,将它存入变量。
scanf的语法与printf的语法大差不差,也是需要包含stdio.h头文件
int i;
scanf("%d",&i);
它的第一个参数是格式字符串,里面的占位符与printf差不多,告诉编译器如何解读用户输入,数据是什么类型的。
scanf也可以同时读入多个变量,如下:
// scanf读入多个变量
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
int c = 0;
int d = 0;
printf("Please enter four integers :\n");
scanf("%d %d %d %d", &a, &b, &c, &d);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
printf("d = %d\n", d);
return 0;
}
scanf处理占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。就比如:用户输入的时候,按下回车键将数据分为几行,也是可以解读的。(不影响解读)
scanf的原理:(内容来源于腾讯云)
用户的输⼊先放⼊缓存,等到按下回车键后,按照占位符对缓存进⾏解读。 解读用户输⼊时,会从上⼀次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第⼀个不符合条件的字符为止。
2.2 返回值
scanf返回值是一个整数,表示成功读取变量的个数。如果,没有读取到任何项,则返回0。
如果在成功读取数据前,发生了读取错误,或遇到文件末尾,则返回一个常量EOF(-1)。
EOF -- end of file -- 文件结束的标志
返回值,下来可以自己研究。
scanf的返回值可以也可以没有,通常编译器会报个警告,这里我们可以忽略,不去管他(我曾经也是执着于这个警告的消除,着实没有必要。)
2.3 占位符
- %c:字符
- %d: 整数
- %f: float类型浮点数
- %lf: double类型浮点数
- %Lf: long double 类型浮点数
- %s: 字符串
- %[ ]: 方括号中一组匹配的字符,遇到不在集合中的字符,就会停止
上述字符中,除了%c其他字符都会忽略起首的空白字符,%c不忽略空白字符,总返回第一个字符,无论是否为空格。
特别强调一下%s,不能简单的等同于字符串,他的规则:从第一个非空白字符开始,到下个空白字符之前的所有字符。
scanf()的占位符基本与printf()相同,主要是对于浮点数类型,有一点小小的差异。
scanf()将字符串读入字符数组的时候,不会检测字符串是否超出了数组长度。因此,很容易进行溢出,如下图:
那么如何解决? 很简单,规定字符串的长度即可,%[m]s,[m]中的m是一个整数,规定字符串的长度。
同时也有方法可以使%s读取空格,见代码:
2.4 赋值忽略符
在用户输入的时候,可能会出现2025-5-3这些输入,那么,scanf必然会报错,该如何避免这种事情多的发生。scanf提供了一个赋值忽略符--*,只要把*放在占位符%后面,该占位符就不会有返回值,解析后就会被丢弃。
3.小结
printf()和scanf()函数对输入和输出提供多种支持。两个函数都使用格式字符串,其中包含的转换说明表明待读取或待打印数据项的数量和类型。另外,可以使用转换说明控制输出的外观:字符宽度、小数位数和字段内的布局。