文章目录
8.scanf 和 printf 介绍
8.1printf
8.1.1基本用法
printf() 的作用是将参数文本输出到屏幕。
#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}
打印:
Hello World
printf() 不会在行尾自动添加换行符,运行结束后,光标就停留在输出结束的地方,不会自动换行。
为了让光标移到下一行的开头,可以在输出文本的结尾,添加一个换行符 \n
。
#include <stdio.h>
int main(){
printf("Hello World\n");
return 0;
}
8.1.2占位符
printf() 可以在输出文本中指定占位符。
所谓 “占位符”,就是这个位置可以用其他值代入。
#include <stdio.h>
int main()
{
printf("There are %d apples\n", 3);//输出 There are 3 apples
return 0;
}
上面示例中, There are %d apples\n
是输出文本,里面的 %d
就是占位符,表示这个位置要用其他值来替换。占位符的第一个字符一律为百分号 %
,第二个字符表示占位符的类型, %d
表示这里代入的值必须是一个整数。
printf()
的第二个参数就是替换占位符的值,上面的例子是整数 3 替换 %d 。执行后的输出结果就是 There are 3 apples
。
int main() {
printf("%s will come tonight", "list");
return 0;
}
%s
表示代入的是字符串。
输出文本里面可以使用多个占位符。
8.1.3占位符列举
最常用的几个我用✨标出来了
-
%a :十六进制浮点数,字母输出为小写。
-
%A :十六进制浮点数,字母输出为大写。
-
%c :字符。//✨
-
%d :十进制整数。// int ✨
-
%e :使用科学计数法的浮点数,指数部分的 e 为小写。
-
%E :使用科学计数法的浮点数,指数部分的 E 为大写。
-
%i :整数,基本等同于 %d 。
-
%f :小数(包含 float 类型和 double 类型)。//float %f✨ double - %lf✨
-
%g :6个有效数字的浮点数。整数部分一旦超过6位,就会自动转为科学计数法,指数部分的 e为小写。
-
%G :等同于 %g ,唯一的区别是指数部分的 E 为大写。
-
%hd :十进制 short int 类型。✨
-
%ho :八进制 short int 类型。
-
%hx :十六进制 short int 类型。
-
%hu :unsigned short int 类型。✨
-
%ld :十进制 long int 类型。✨
-
%lo :八进制 long int 类型。
-
%lx :十六进制 long int 类型。
-
%lu :unsigned long int 类型。✨
-
%lld :十进制 long long int 类型。
-
%llo :八进制 long long int 类型。
-
%llx :十六进制 long long int 类型。
-
%llu :unsigned long long int 类型。
-
%Le :科学计数法表示的 long double 类型浮点数。
-
%Lf :long double 类型浮点数。✨
-
%n :已输出的字符串数量。该占位符本身不输出,只将值存储在指定变量之中。
-
%o :八进制整数。
-
%p :指针(用来打印地址)。✨
-
%s :字符串。✨
-
%u :无符号整数(unsigned int)。✨
-
%x :十六进制整数。✨
-
%zd : size_t 类型。✨
-
%% :输出一个百分号。
举个例子:
int main() {
printf("%hd\n",100);
printf("%ho\n", 100);
printf("%x\n", 15);
return 0;
}
打印:
100//100用十进制表示是100
144//100用八进制表示是144;64+32+4
f//15用十六进制表示是f
👌
8.1.4输出格式
printf() 可以定制占位符的输出格式。
8.1.5限定宽度
printf() 允许限定占位符的最小宽度。
为了方便查看,我就把空格用⏹️来表示了。
#include <stdio.h>
int main()
{
printf("%5d\n", 123); // 输出为 "⏹️⏹️123"
return 0;
}
上面示例中, %5d 表示这个占位符的宽度至少为5位。如果不满5位,对应的值的前面会添加空格。
输出的值默认是右对齐,即输出内容前面会有空格;如果希望改成左对齐,在输出内容后面添加空格,可以在占位符的 % 的后面插入一个 - 号。
#include <stdio.h>
int main()
{
printf("%-5d\n", 123); // 输出为 "123⏹️⏹️"
return 0;
}
对于小数,限定符会限制所有数字的最小显示宽度。
#include <stdio.h>
int main()
{
printf("%12f\n", 123.45);//输出 "⏹️⏹️123.450000"
printf("%4lf\n", 123.45);//输出 :"123.450000"
printf("%12.1lf\n",123.45);//输出:"⏹️⏹️⏹️⏹️⏹️⏹️⏹️123.5"
//在C语言中,当使用 %lf 格式化浮点数时,会根据指定的小数位数进行四舍五入。
printf("%*.*lf\n",12,1,123.45);//输出:"⏹️⏹️⏹️⏹️⏹️⏹️⏹️123.5"
//这里的*相当于起了个数值传递的功能//和上面那个%12.1lf一个作用
printf("%s\n","abcdef");//输出:"abcdef"
printf("%.3s\n","abcdef");//输出:"abc"
return 0;
}
举个例子:
#include <stdio.h>
int main()
{
printf("%5d\n", 123456);
return 0;
}
打印:
123456
为啥不是12345呢?🤔莫非C语言不存在了?🤣
因为%5d
表示这个占位符的宽度至少为5位。如果不满5位,对应的值的前面会添加空格。如果超过5位,正常输出就行,5是最少输出5位。
8.1.6总是显示正负号
默认情况下, printf() 不对正数显示 + 号,只对负数显示 - 号。如果想让正数也输出 + 号,可以在占位符的 % 后面加一个 + 。
#include <stdio.h>
int main()
{
printf("%d\n", 12); // 输出 12
printf("%d\n", -12); // 输出 -12
printf("%+d\n", 12); // 输出 +12
printf("%+d\n", -12); // 输出 -12✨
return 0;
}
8.1.7限定小数位数
输出小数时,有时希望限定小数的位数。举例来说,希望小数点后面只保留两位,占位符可以写成 %.2f
。
#include <stdio.h>
int main()
{
printf("Number is %.2f\n", 0.5);//输出 Number is 0.50
return 0;
}
这种写法可以与限定宽度占位符,结合使用。
#include <stdio.h>
int main()
{
printf("%6.2f\n", 0.5);//输出为 "⏹️⏹️0.50"
return 0;
}
最小宽度和小数位数这两个限定值,都可以用 * 代替,通过 printf() 的参数传入。
#include <stdio.h>
int main()
{
printf("%*.*f\n", 6, 2, 0.5);
return 0;
}
// 等同于printf("%6.2f\n", 0.5);
8.1.8输出部分字符串
%s
占位符用来输出字符串,默认是全部输出。如果只想输出开头的部分,可以用 %.[m]s
指定输出的长度,其中 [m]
代表一个数字,表示所要输出的长度。
#include <stdio.h>
int main()
{
printf("%.5s\n", "hello world");//输出 hello
return 0;
}
8.1.9输出多个占位字符
printf() 参数与占位符是一一对应关系,如果有 n
个占位符, printf() 的参数就应该有 n + 1
个。如果参数个数少于对应的占位符, printf() 可能会输出内存中的任意值。
int main() {
printf("%s says it is %d o'clock\n", "list", 10);
printf("%s says it is %d o'clock\n", "avwfb", 20);
return 0;
}
打印:
list says it is 10 o'clock
avwfb says it is 20 o'clock
上面的n+1
是哪来的?🤨
8.2scanf
8.2.1scanf输入一个参数
需要给变量输入值就可以使用 scanf 函数.
#include <stdio.h>
int main()
{
int score = 0;
printf("请输入成绩:");
scanf("%d", &score);
printf("成绩是:%d\n", score);
return 0;
}
运行截图:
输入90
点击回车
scanf() 的第一个参数 %d
,表示用户输入的应该是一个整数。
scanf("%d", &score);
%d
就是一个占位符, %
是占位符的标志, d
表示整数。第二个参数 &score
表示,将用户从键盘输入的整数存入变量score
。
8.2.2scanf输入多个参数
scanf("%d%d%f%f", &i, &j, &x, &y);
scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。所以,用户输入的数据之间,有一个或多个空格不影响 scanf() 解读数据。另外,用户使用回车键,将输入分成几行,也不影响解读。
可以这样
1 2 0.4 4.6
也可以这样
1
2
0.4
4.6
来个例题做做:
int main() {
int x;
int y;
scanf("%d=%d", &x, &y);
printf("%d %d", x, y);
return 0;
}
如果想输入i的值为2,想输入j的值为3
很多初学者直接会输入2 3
然后得到一个奇怪的结果:
🤨然后怀疑电脑坏了。
为啥y不显示 3却显示这么个怪东西呢?
注意:scanf函数里面的%d=%d
,这里面有个等号啊!😡
应该输入2=3,对应scanf("%d=%d", &x, &y);
里面的%d=%d
。
如果你输入 2 3 而不是 2=3 , scanf 将无法正确解析输入,因为它期望的是一个等号而不是一个空格。由于 scanf 无法匹配格式字符串中的等号,它不会为 y 读取任何值,因此 y 的值将是未定义的。也就是随便来个值咯。
既然这样,我把%d和%d写一起不就无法输出了吗?🤔
int main() {
int x;
int y;
scanf("%d%d", &x, &y);
printf("%d %d", x, y);
return 0;
}
并不是这样的😡
我们先输入1空格 2,再回车一样能得到这个值。
scanf("%d=%d", &x, &y);
就像这个一样,只要在输入x和y的时候,中间有个=就行了,电脑可不管x和=,或者y和=之间有几个空格。
scanf("%d=%d\n", &x, &y);
如果里面写了 \n
,那么输入的时候也要输入\n
建议写代码的时候%d之间不要有空格,不然检查不仔细可能会出现奇怪的错误。
再来题练练:
下面的程序里面,用户输入"⏹️⏹️⏹️-13.45e12#⏹️0"
会发生什么?
int main() {
int x;
float y;
scanf("%d", &x);
printf("%d\n", x);
scanf("%f", &y);
printf("%f\n", y);
return 0;
}
打印:
🤯🤯🤯
首先x跳过了开头的空格读取了-13。因为x是int类型的。
因为y是float类型的,所以从这里的小数点开始读。先读到0.45,然后遇到这个e12。这里面e12表示的是科学计数法。0.45e12表示的是 0.45乘上10的12次方。然后发现后面有个#,读不了,就结束了读取。
所以y就得到了这么怪东西。
8.2.3scanf的返回值
1.scanf() 返回值
scanf() 的返回值是一个整数,表示成功读取的变量个数。
如果没有读取任何项,或者匹配失败,则返回 0 。
如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量 EOF (-1)。
int main() {
int a = 0;
int b = 0;
int c = 0;
int d = 0;
int ret = scanf("%d %d %d %d", &a, &b, &c, &d);
printf("%d %d %d %d\n", a, b, c, d);
printf("ret = %d\n", ret);
return 0;
}
输入:
1 2 3 4
打印 :
1 2 3 4
ret = 4
然后我们改变一下输入的东西。
输入:
1 2 3,4
打印 :
1 2 3 0
ret = 3
这次ret=3了。
接着,我们再改变一下输入的东西。
这里面我输入的是CtrlZ
,也就是按住Ctrl
的时候按住Z
,然后回车继续按。
这里按了3次是因为VS这里需要3次。在VS环境中按3次 ctrl+z
,才结束了输入。其他软件里面可能按一次再回车就好了。
输出的ret = -1,刚好和上面说的如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量 EOF (-1)。
吻合。
2.scanf() 输入%c
%c
不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格。
int main() {
char ch = 0;
scanf("%c", &ch);
printf("xxx%cyyy", ch);
return 0;
}
输入:
⏹️⏹️ejs
打印:
xxx⏹️yyy
输入:
sdyuy
打印:
xxxsyyy
如果要强制跳过字符前的空白字符,可以写成 scanf(" %c", &ch)
,即 %c
前加上一个空格,表示跳过零个或多个空白字符。
int main() {
char ch = 0;
scanf(" %c", &ch);//%c的前面有个空格
printf("xxx%cyyy", ch);
return 0;
}
输入:
⏹️⏹️ejs
打印:
xxxeyyy
欧了👌
3.scanf() 将字符串读入字符数组:
scanf() 将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时,很可能会超过数组的边界,导致预想不到的结果。
int main()
{
char name[5];
scanf("%s", name);
printf("%s", name);
return 0;
}
输入:
wtwrtrw
打印:
报错了。
因为name[5]
数组里面最多放5个。这里面放太多了。它受不了了。
咋办呢?
为了防止这种情况,使用 %s
占位符时,应该指定读入字符串的最长长度,即写成 %🅰️s
。
其中的 🅰️ 是一个整数,表示读取字符串的最大长度,后面的字符将被丢弃。
int main()
{
char name[5];
scanf("%5s", name);
printf("%s", name);
return 0;
}
输入:
sgdggfds
结果:
还是报错!
因为scanf() 遇到 %s
占位符,会在字符串变量末尾存储一个空字符 \0
。
也就是说上面的scanf("%5s", name);
里面的5应该改成4。这样就不会溢出了。
int main()
{
char name[11];
scanf("%10s", name);
printf("%s", name);
return 0;
}
输入:
efgrgegttgteht
输出:
efgrgegttg
4.赋值忽略符
之前在 8.2.2scanf输入多个参数 这个地方讲过scanf输入与里面符号的关系。
我们也可以用赋值忽略符*
来解决这个问题。
只要把 *
加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃。
例如:
int main()
{
int year = 0;
int month = 0;
int day = 0;
scanf("%d%*c%d%*c%d", &year, &month, &day);
return 0;
}
输入:
2024 4 1
打印:
2024 4 1
可能有人会奇怪为什么说了赋值忽略符是*
,结果我放了个%*c
?
%c
是读取一个字符,%*c
是读取这个字符,然后让他不会有返回值。
都看到这里了,点个赞呗~