对于printf函数,我们主要要掌握printf函数的输出格式。
而对于scanf函数,我们则要知道几个输入过程中的错误输入情况和scanf函数的实现原理。
- (1)printf 函数
- printf 中 格式控制 部分 的完整格式:
- "% - 0 m.n l或h 格式字符"
- 下面对组成格式说明的各项加以说明:
- ① % 表示格式说明的起始符号,不可缺少。
- ② - 有-表示左对齐输出(右侧补空格),如省略表示右对齐输出(左侧补空格)。
- ③ 0 有0表示指定空位填0,如省略表示指定空位不填。
- ④ m.n m指域宽,即对应的输出项在输出设备上所占的字符数。n指精度。用于说明输出的实型数的小数位数。对数值型的来说,未指定n时,隐含的精度为n=6位。
- ⑤ l或h l对整型指long型,对实型指double型。h用于将整型的格式字符修正为short型。
- ⑥ 格式字符(格式字符用于 指定输出项的 数据类型 和 输出格式) :
- d格式:用来输出十进制整数。有以下几种用法:
- %d %hd %ld
- o格式:以无符号八进制形式输出整数
- x格式:以无符号十六进制形式输出整数
- u格式:以无符号十进制形式输出整数
- c格式:输出一个字符
- s格式:用来输出一个串。有几种用法列举:
- ① %s 例如:printf("%s","CHINA")输出"CHINA"字符串(不包括双引号)。
- ② %ms 输出的字符串占m列,如字符串本身长度大于m,则突破获m的限制,将字符串全部输出。若串 长小于m,则左补空格。
- ③ %-ms 如果串长小于m,则在m列范围内,字符串向左靠,右补空格。
- (以下④⑤条中的 m和n 的含义不同于上面)
- ④ %m.ns 输出占m列,但只取字符串中 左端 n个字符。这n个字符输出在m列的右侧,左补空格。 注意:如果n未指定,默认为0。如果n>m,则m自 动取n的值,即保证n个字符正常输出。
- ⑤ %-m.ns 其中m、n含义同上,n个字符输出在m列范围的左侧,右补空格。 注意:如果n未指定,默认为0。如果n>m,则m自动取n的值,即保证n个字符正常输出。
- (2)scanf 函数
- scanf是一个阻碍式函数,程序在执行过程中会停在scanf函数出现的地方,直到接收数据时才会执行后面的代码。
- scanf使用时注意的几个点:
- ① 如果在控制台输入时,输入了多个空格、回车、Tab都会被系统忽略的(这其中包括输入多个实型常量 和 整型常量时如果其间输入了多余的空格、回车、Tab也是都会被系统忽略的)
- ② 当 字符型常量 与 整型常量 或 实型常量 混合输入的时候,要注意添加分隔符,来避免无意输入 空格 造成的错误
- ③ 在scanf中,尽量不要使用\n,因为会造成在输入的时候无限换行。如果使用了\n,那么在输入的时候一定要原样输入“\n”才可以解决
-
- scanf的实现原理:系统会将用户在控制台输入的内容放入输入缓冲区,scanf会从输入缓冲区内逐个取出内容赋值给格式符,如果类型不一致的话不会修改原有数据。并且如果输入缓冲区中不为空,那么再次使用scanf时scanf会一直从缓冲区中获取值,而不会要求用户再次输入。
- 接下来一段代码会将上面 需要注意的几个点 和 实现原理 相结合为大家展示:
-
#include <stdio.h> int main(int argc, const char * argv[]) { int intValue1 = 1; char charValue1 = '1'; int intValue2 = 2; char charValue2 = '2'; int intValue3 = 3; printf("-----第一次输入:-----\n"); scanf("%d%c%d", &intValue1, &charValue1, &intValue2); printf("\n-----第一次输出:-----\n"); printf("intValue1 = %d,charValue1 = %c,intValue2 = %d\n", intValue1, charValue1, intValue2); printf("\n-----第二次输入:-----\n"); scanf("%c%d", &charValue2, &intValue3); printf("\n-----第二次输出:-----\n"); printf("charValue2 = %c,intValue3 = %d\n\n", charValue2, intValue3); return 0; } /* * 运行结果: -----第一次输入:----- 19 s 32 -----第一次输出:----- intValue1 = 19,charValue1 = ,intValue2 = 2 -----第二次输入:----- -----第二次输出:----- charValue2 = s,intValue3 = 32 */
- 运行结果分析:
首先看输入部分,第一次看似输入了3个值,实则不然,我们输入了5个。分别是:19 空格 s 空格 32
再看第二次输入,直接被跳过了。
其次看输出部分,一次输入(只按了一次回车),两次结果都打印出来了:
intValue1 = 19,charValue1 = ,intValue2 = 2,charValue2 = s,intValue3 = 32
经上面的分析,我们一共在控制台手动输入了5个值,也就是让scanf去输入缓冲区去取5次值,第一次输入scanf将前三个值取出来,也就是取出 19、空格、s,并将他们赋给intValue1、charValue1、intValue2,前两个正常赋值,但是第三个值 s 和 intValue2的类型不匹配,所以输入缓存区里的值 s 并没有被取走,而intValue2显示的就是它初始化时被赋予的值 2。
试想一下,现在输入缓存区中还存在三个值,那就是第一次没被取走的 s 以及 空格 和 32。所以说第二次控制台输入不会执行,而是继续在输入缓存区中取值。自然 s 赋给了 charValue2,又因为 空格 换行 tab 遇到 非char类型的值时会被忽略,所以说 空格 就被忽略了。那么最后一个值 32 就被赋给intValue3了。
- 接下来一个小问题,来加深理解这部分内容:
-
#include <stdio.h> void test1(); int main(int argc, const char * argv[]) { int a = 0; int b = 0; int c = 0; int d = 0; int e = 0; int f = 0; printf("第一次输入:\n"); scanf("%i,%i,%i", &a, &b, &c); printf("-----第一次输入结束-----\n"); printf("第一次输出结果---%i,%i,%i,%i,%i,%i\n", a, b, c, d, e, f); // setbuf(stdin, NULL); // 清空输入缓存区的缓存数据 printf("第二次输入:\n"); scanf("%i,%i,%i", &d, &e, &f); printf("-----第二次输入结束-----\n"); printf("第二次输出结果---%i,%i,%i,%i,%i,%i\n", a, b, c, d, e, f); return 0; } /* * 运行结果: 第一次输入: 1,2,3,4,5,6 -----第一次输入结束----- 第一次输出结果---1,2,3,0,0,0 第二次输入: -----第二次输入结束----- 第二次输出结果---1,2,3,0,0,0 */
- 运行结果分析:
和上面的程序一样,一次性输入多个值,那么会在缓存区里存储未赋值的数据。那为什么第二次输入的时候d、e、f的值还是0呢?不应该是4,5,6吗?这是因为在输入的时候我们加上了逗号作为分隔符,而一次输入6个值时,c与d之间是没有逗号作为分隔符的,但我们却多输入了一个逗号,那么逗号就会从缓存区中取出并依次赋给d、e、f,但类型不匹配,所以说赋值失败,于是输出结果d、e、f还是0。
-
/* * 如果是按下面的方式进行输出,空格去替代3和4之间的逗号,那么赋值时空格遇到非char类型的数据自动忽略,所以后面的4、5、6成功赋值 * 运行结果: 第一次输入: 1,2,3 4,5,6 -----第一次输入结束----- 第一次输出结果---1,2,3,0,0,0 第二次输入: -----第二次输入结束----- 第二次输出结果---1,2,3,4,5,6 */