C基础4——printf与scanf
在上文中,我们介绍了c中的数据类型,本文就来探讨一下初学者最先遇到的两个函数,printf与scanf
文章目录
写在前面
在C语言中,printf与scanf函数是贯穿始终的,它们分别是输入函数和输出函数,简称为I/O函数。它们的工作原理基本上是相同的,两个函数都是用格式字符串和参数列表,下面开始对这两个函数进行介绍。
1. 占位符
本文部分内容与图片来自博客【C语言】 全面解析占位符_c语言中的占位符-CSDN博客
在C语言编程中,占位符是一种常用的编程工具,通常用于表示即将填入的某个值。占位符不仅在格式化输出中非常有用,而且在调试和开发过程中也起到了重要作用。
占位符是一种特殊的符号或字符串,用于在输出格式中表示将来需要填入的值。在C语言中,占位符通常用于printf
、sprintf
、scanf
等函数中,以便按照特定格式输出变量的值。例如,%d
用于表示一个整数,%s
用于表示一个字符串。
常见的占位符有:
下面通过例子来演示这些占位符的使用
注意占位符与后面的值需要按照顺序对应,否则将会出现不一样的结果
2. printf
2.1基本介绍
printf() 的作用是将参数文本输出到屏幕。它名字里面的 f 代表 format (格式化),表示可以定制输出文本的格式。下面是一个最简单的printf的用法,用于打印“hello world”。
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
printf() 不会在行尾自动添加换行符,运行结束后,光标就停留在输出结束的地方,不会自动换行。这样在打印多个信息的时候会出现都打印到一行上,不易分清想要的信息。
因此为了让光标移到下一行的开头,可以在输出文本的结尾,添加一个换行符 \n 。
如果文本内部有换行,也可以通过插入换行符来实现,如下
#include <stdio.h>
int main()
{
printf("hello \n world \n");
return 0;
}
这样打印出来的hello world就会分成两行
**printf()**是在标准库的头文件 stdio.h 定义的。使用这个函数之前,必须在源码文件头部引入这个头文件。即#include <stdio.h>
2.2 输出格式
printf()可以定制占位符的输出格式。
2.2.1 限定宽度
printf()允许限定占位符的最小宽度。
#include <stdio.h>
int main()
{
printf("%5d\n",123);
printf("%-5dxxx\n",123);//加入xxx是为了更好的对比
return 0;
}
输出结果如下图所示
-
上面示例中,%5d表示这个占位符的宽度至少为5位。如果不满5位,对应的值的前面会添加空格。
-
输出的值默认是右对齐,即输出内容前面会有空格;如果希望改成左对齐,在输出内容后面添加空格,可以在占位符的%的后面插入一个 - 号。(如果打印的超出规定的数位,这有多少打印多少)上图中xxx不属于5个位置中。
对于小数,这个限定符会限制所有数字的最小显示宽度
// 输出 ” 123.450000“
#include <stdio.h>
int main()
{
printf("%12f\n",123.45);
return 0;
}
上面示例中,%12f 表示输出的浮点数最少要占据 12 位,由于小数的默认显示精度是小数点后 6位,所以 123.45 输出结果的头部会添加 2 个空格。
2.2.2 总是显示正负号
默认情况下,printf() 不对正数显示 + 号,只对负数显示 - 号。如果想让正数也输出 + 号,可以在占位符的 % 后面加一个 +.
#include <stdio.h>
int main()
{
printf("%+d\n",12) ; // 输出+12
printf("%+d\n",-12);// 输出-12
return 0;
}
2.2.3 限定小数位数
输出小数(浮点数)时,有时希望限定小数的位数。举例来说,希望小数点后面只保留两位,占位符可以写成 %.2f 。
//输出 Num is 0.50
#include <stdio.h>
int main()
{
printf("Num is %.2f\n",0.50);
return 0;
}
上面示例中,如果希望小数点后面输出4位小数**(0.5000)**,占位符就要写成 %.4f
这种写法可以和限制宽度一起使用
上面示例中, %6.2f 表示所输出的字符串最小宽度为6,小数位数为2.所以,输出字符的头部会有两个空格。
注:最小宽度和小数位数这两个限定值,都可以用 ***** 代替,通过 printf() 的参数传入。
#include <stdio.h>
int main()
{
printf("%*.*f\n",6, 2, 0.5);
return 0;
}
// 等同于printf("%6.2f\n",0.5);
上面示例中,%*.*f 的两个星号通过 printf() 的两个参数 6 和 2 传入。
2.2.4 输出部分字符串
%s 占位符用来输出字符串,默认是全部输出。如果只想输出开头的部分,可以用 %.[m]s 指定输出的长度,其中**[m]** 代表一个数字,表示所要输出的长度。
//输出 hello
#include <stdio.h>
int main()
{
printf("%.5s\n", "hello world");
return 0;
}
上面示例中,占位符 %.5s 表示只输出字符串“hello world”的前 5 个字符,即“hello”。
3.scanf
scanf 的功能用一句话来概括就是“通过键盘给程序中的变量赋值”。该函数的原型为:
# include <stdio.h>
int scanf(const char *format, ...);
3.1 scanf的用法
scanf的原理是将从键盘输入的字符转化为“输入控制符”所规定格式的数据,然后存入以输入参数的值为地址的变量中。
下面给大家举个例子
#include <stdio.h>
int main()
{
int a = 0;//初始化变量
scanf("%d",&a);//输入
printf("%d\n",a);//输出
return 0;
}
在这个程序运行的过程中,用户可以打印自己输入的值,而不是输出由程序提前设定好的值。
“输入控制符”和“输出控制符”是一模一样的。 比如一个整型数据,通过 printf 输出时用%d
输出,通过 scanf 输入时同样是用%d。
要想将程序中的 scanf 行弄明白,首先要清楚的是:
- 我们从键盘输入的全部都是字符。比如从键盘输入 123,它表示的并不是数字 123,而是字符 ‘1’、字符 ‘2’ 和字符 ‘3’。这是为什么呢?
操作系统内核就是这样运作的。操作系统在接收键盘数据时都将它当成字符来接收的。这时就需要用“输入控制符”将它转化一下。%d的含义就是要将从键盘输入的这些合法的字符转化成一个十进制数字。经过 %d 转化完之后,字符 123 就是数字 123 了。
- 第二个要弄清楚的是:&是一个取地址运算符,&后面加变量名表示“该变量的地址”,所以&i就表示变量 i 的地址。&i又称为“取地址i”,就相当于将数据存入以变量 i 的地址为地址的变量中。那么以变量 i 的地址为地址的变量是哪个变量呢?就是变量 i 。所以程序中 scanf 的结果就把值 123 放到变量 i 中。
综上所述,scanf 语句的意思就是:从键盘上输入字符 123,然后%d
将这三个字符转化成十进制数 123,最后通过 “取地址 i” 找到变量 i 的地址,再将数字 123 放到以变量 i 的地址为地址的变量中,即变量 i 中,所以最终的输出结果就是i=123
。
注意:
为什么不直接说“放到变量i中”?而是说“放到以变量 i 的地址为地址的变量中”?因为这么说虽然很绕口,但是能加强对 &i 的理解,这么说更能表达 &i 的本质和内涵。很多人在学习 scanf 的时候,经常将“变量 i”和“变量 i 的地址”混淆,从而思维开始混乱,等深刻了解 &i 的含义之后就可以不那么说了。本部分参考https://blog.csdn.net/qq_51574759/article/details/121054022
以上是 scanf 的最简单用法,也是最常用、最基本、最重要的用法。这样通过 scanf 就可以在程序运行的过程中由用户来指定变量 i 的值,这与在程序中赋值相比较功能更强大。
3.2 使用scanf时的一些注意事项
3.2.1参数的个数一定要对应
在前面介绍 printf 时说过,“输出控制符” 和 “输出参数” 无论在 “顺序上” 还是在 “个数上” 一定要一一对应。这句话同样对 scanf 有效,即 “输入控制符” 和 “输入参数” 无论在 “顺序上” 还是在 “个数上” 一定要一一对应。比如:
# include <stdio.h>
int main()
{
char ch = 0;
int i = 0;
scanf("%c%d", &ch);
printf("ch = %c, i = %d\n", ch, i);
return 0;
}
输出结果为
这种错误是初学者经常犯的,由于粗心大意,少写一个参数。
更严重的是,这种错误在编译的时候不会报错。printf 也是一样,即使“输出参数”少写了也不会报错,但从程序的功能上讲这么写就是错的。所以在编程的时候一定要避免这种错误的发生。
3.2.2 输入的数据类型一定要与所需要的数据类型一致
在 printf 中,“输出控制符” 的类型可以与数据的类型不一致,比如
# include <stdio.h>
int main()
{
int i = 97;
printf("i = %c\n", i);
return 0;
}
输出结果为
但是在 scanf 中,对于从键盘输入的数据的类型、scanf 中“输入控制符”的类型、变量所定义的类型,这三个类型一定要一致,否则就是错的。虽然编译的时候不会报错,但从程序功能的角度讲就是错的,则无法实现我们需要的功能。比如:
这里输入a,不满足%d所要求的整型类型数据,于是便返回一个初始化值i = 0.
3.2.3 在使用 scanf 之前使用 printf 提示输入
大家想一想,前面写的 scanf 程序有没有不足的地方?
程序写好之后,编译、链接、执行,然后弹出黑窗口,出现一个光标在那不停地闪。对于编写程序的人来说他知道要输入什么,但是对于用户而言,用户怎么知道是什么意思呢?所以之前的程序都缺少提示信息!因此在使用scanf之前,最好先用printf提示用户以什么样的方式输入,这样可以大大提高代码的质量。看看下面这个程序:
# include <stdio.h>
int main()
{
int i = 0;
int j = 0;
printf("请输入两个值,中间以空格分隔:");
scanf("%d%d", &i, &j);
printf("i = %d, j = %d\n", i, j);
return 0;
}
这样在执行的时候,用户一看就知道是要输入两个值,然后中间用空格隔开。所以这样写就更人性化、智能化了。
3.3 scanf小结
scanf 的使用看似细节繁杂,但使用起来非常简单。就目前而言,只要掌握以下五点:
- 在 scanf 的“输入参数”中,变量前面的取地址符&不要忘记。
- scanf 中双引号内,除了“输入控制符”外什么都不要写。
- “输出控制符”和“输出参数”无论在“顺序上”还是在“个数上”一定要一一对应。
- “输入控制符”的类型和变量所定义的类型一定要一致。对于从键盘输入的数据的类型,数据是用户输入的,程序员是无法决定的,所以在写程序时要考虑容错处理,这个稍后再讲。
- 使用 scanf 之前先用 printf 提示输入。
只要掌握了以上五点,scanf 的使用基本上就没什么问题了。至于其他注意点,到后面讲数组和指针的时候再学习不迟。
以下五点:
- 在 scanf 的“输入参数”中,变量前面的取地址符&不要忘记。
- scanf 中双引号内,除了“输入控制符”外什么都不要写。
- “输出控制符”和“输出参数”无论在“顺序上”还是在“个数上”一定要一一对应。
- “输入控制符”的类型和变量所定义的类型一定要一致。对于从键盘输入的数据的类型,数据是用户输入的,程序员是无法决定的,所以在写程序时要考虑容错处理,这个稍后再讲。
- 使用 scanf 之前先用 printf 提示输入。
只要掌握了以上五点,scanf 的使用基本上就没什么问题了。至于其他注意点,到后面讲数组和指针的时候再学习不迟。