ps:字段宽度是指打印出来的“东西”所占位置大小,比如用%8.3f打印出来的浮点数,小数点前占4个字符位,其中小数点后占3个字符位,小数点算一个字符位,如果小数点前不满4个数,就用空格代替。用%08.3f打印出来的浮点数如果小数点前不满4个数,就用0代替。
#1. 输出
#1.1 printf()函数
格式:printf(格式字符串, 待打印项1, 待打印项2,...);
要输出的内容 => 缓冲区(buffer) => 屏幕
何时发送到屏幕:
- buffer满时
- 遇到换行字符
- 需要输入时(旧编译器可能不支持)
在%和转换字符之间可加入修饰符,修饰基本的转换说明:
#include<stdio.h>
#define PAGES 999
int main(void)
{
printf("%2d\n", PAGES);
printf("%5.3d\n", 6);
printf("%05.3d\n", 6);
printf("%05.2d\n", 6);
return 0;
}
结果为:
999
006
006
06
#1.1.1 转换字符不匹配时
转换字符要匹配!!!!!
#include<stdio.h>
#define PAGES 336
#define WORDS 65618
int main()
{
short int num = PAGES;
short int mnum = -PAGES;
printf("short int:%zd, int:%zd, char:%zd\n", sizeof(short int), sizeof(int), sizeof(char));
printf("num as short and unsigned short:%hd %hu\n", num, num);
printf("-num as short and unsigned short:%hd %hu\n", mnum, mnum);
printf("num as int and char:%d %c\n", num, num);
printf("WORDS as int, short and char:%d %hu %c\n", WORDS, WORDS, WORDS);
return 0;
}
结果如下:
可以看到
short int为2字节(0~65535),用%hd打印时,范围为-32768~32767 [ -2^(15) ~ 2^(15)-1 ] ,用%hu打印时,范围为0~65535[ 0 ~ 2^(16)-1 ];
因为num=336都在这个范围内,因此 printf("num as short and unsigned short:%hd %hu\n", num, num); 打印出来都没问题。
对于printf("-num as short and unsigned short:%hd %hu\n", mnum, mnum); 由于mnum=-336,在用%hd打印的范围内,因此用%hd打印没问题;但是不在用%hu打印的范围内,因此出现问题,336用二进制表示为0000 0001 0101 0000,故-336为1111 1110 1011 0000,用%hu打印时,左边第一位不是符号位,因此65200。
对于printf("num as int and char:%d %c\n", num, num); 由于int为4字节,用%d打印时,范围为-2,147,483,648~2,147,483,647 ,336在其范围内,因此输出没问题;但336用%c输出时出现问题,因为%c为1个字节也即用%c打印时,只会输出336的后八位(01010000),也即十进制的80,对应ASKII码的P。
对于printf("WORDS as int, short and char:%d %hu %c\n", WORDS, WORDS, WORDS); WORDS=65618,包含在%d的输出里面,因此没问题;对应的二进制为0001 0000 0000 0101 0010,%hd只有两字节,因此输出 0000 0000 0101 0010=82,这种截断方式,相当于对65536(2^16)取余;%c只有一个字节,因此输出0101 0010=82,对应ASKII码的R。
#include<stdio.h>
#define PAGES 336
#define WORDS 65618
int main()
{
float n1 = 3.0;
double n2 = 3.0;
long n3 = 2000000000;
long n4 = 1234567890;
printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4);
printf("%ld %ld %ld %ld", n1, n2, n3, n4);
return 0;
}
运行结果为:
对于printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4); 前两个输出没有问题,对于n3=2000000000=0111 0111 0011 0101 1001 0100 0000 0000(一共4字节),用%e打印时,不仅看这四个字节,还看相邻的四个字节,共八个字节。
printf()函数打印时,会把float转换成double类型。
对于printf("%ld %ld %ld %ld", n1, n2, n3, n4); 一种解释:
参数传递时,把n1n2n3n4依次压入栈中,分别为8 8 4 4个字节,在输出时,printf()根据%ld从栈中按4字节依次取数,如图。
#1.1.2 printf()的返回值
printf()函数正常运行的返回值为打印字符的个数,异常时返回负数(旧版本不一定)。
#1.1.3 printf()打印较长字符串
三种字符串断行方法:
- 使用多个printf()函数
- 使用反斜杠\和ENTER换行
- 在两个用双引号括起来的字符串之间用空白格隔开;注意,"XJ" "X"输出XJX ; "XJ " "x"输出XJ X
#1.1.4 printf()的*修饰符
如果不想预先指定字段宽度,希望程序来指定,可以用*修饰符代替字段宽度。
如:设定一个输入width,用于确定字段宽度。
上面的语句,会根据width的值来确定后面number打印的字段宽度。
上面的语句,会根据width的值来确定weight打印的字段宽度;precision的值确定小数点后的位数。
#1.1.5 特殊归纳
printf("%d", printf("%d", printf("%d", 43)));
输出结果为:4321
#1.2 getchar()函数
一次只从缓冲区获取一个字符。
#1.3 gets()函数
获取字符串。
#2. 输入
#2.1. scanf()函数
转换说明:
修饰符:
#2.1.1. scanf()读取数据
- scanf()每次读取一个字符,跳过空白字符;遇到第一个非空白字符才会开始读取
- scanf()会根据转换说明来读取输入。如要输入数字,scanf()会识别数字或(+ -号),读到非数字和+ -号或者空白字符时,停止本次读取;如果第一个字符是A,则永远无法完成输入。如果使用带多个转换说明的scanf(),C规定在第1个出错处停止读取输入。
- 如果使用字段宽度,scanf()在字段结尾或第1个空白字符处停止读取(满足两个条件之一便停止)。
- 当scanf()把字符串放进指定数组中时,它会在字符序列的末尾加上'\0',让数组中的内容成为一个C字符串。
#2.1.2. 格式字符串中的普通字符
除了%C,其他转换说明都会自动跳过待输入值前面所有的空白。
#2.1.3. scanf()函数的返回值
- 返回成功读取的项数。
- 如果没有读取任何项,且需要读取一个数字而用户却输入一个非数值字符串,返回0。
- 当scanf()检测到“文件结尾”时,会返回EoF。
ps:可以利用返回值来判断是否输入正确以及退出。
如:
int num = 0;
while (scanf("%d", &num) == 1)
{
...;
}
当输入为数字时,才进入while循环;否则跳出循环。
#2.1.4 scanf()函数的*修饰符
上面的语句,会把第三个输入的值传递给n,实现跳过的功能。
#2.2 putchar()函数
输出一个字符。
#3 总结
1. printf的格式:printf(格式字符串, 待打印项1, 待打印项2,...);
printf的运行流程:要输出的内容 => 缓冲区(buffer) => 屏幕
何时发送到屏幕:
- buffer满时
- 遇到换行字符
- 需要输入时(旧编译器可能不支持)
2. printf的转换说明
3. printf()函数正常运行的返回值为打印字符的个数(换行符\n等也算一个字符),异常时返回负数(旧版本不一定);
4. printf语句过长时,可以使用\断开,也可以用写成多句;
5. scanf:数组不用加&,变量要加&;
6.
- scanf()每次读取一个字符,跳过空白字符;遇到第一个非空白字符才会开始读取
- scanf()会根据转换说明来读取输入。如要输入数字,scanf()会识别数字或(+ -号),读到非数字和+ -号或者空白字符时,停止本次读取;如果第一个字符是A,则永远无法完成输入。如果使用带多个转换说明的scanf(),C规定在第1个出错处停止读取输入。
- 如果使用字段宽度,scanf()在字段结尾或第1个空白字符处停止读取(满足两个条件之一便停止)。
- 当scanf()把字符串放进指定数组中时,它会在字符序列的末尾加上'\0',让数组中的内容成为一个C字符串。
7. scanf返回值
- 返回成功读取的项数。
- 如果没有读取任何项,且需要读取一个数字而用户却输入一个非数值字符串,返回0。
- 当scanf()检测到“文件结尾”时,会返回EoF。
8. *修饰符
对于printf来说,*修饰符可以该字段宽度交由程序的某个变量决定;对于scanf来说,*修饰符会让其跳过相应的输出项;