标准输入输出

标准输入输出.png

敲击键盘输入的数据会缓存到 stdin 缓冲区中,scanf函数就从缓冲区中取出数据。printf函数会把要显示的数据放到 stdout 缓冲区中,由显示器从中取出并显示。缓冲区中的数据都是一次性的,读取之后就会消失,你完全可以理解为管道。

由于不同系统,不的硬件底层实现输入输出的具体方法可能不一样,C语言要求系统为每个程序提供两个指针,这两个指针分别指向两个结构体,这两个结构体分别表示了键盘和屏幕在内存中的抽象表示(缓冲区的地址值被记录在这个结构体中),并将指向这两个结构体的指针命名为stdin和 stdout.这两个指针就是所谓的标准输入和标准输出。

标准输出

格式:printf(格式串,表达式1,表达式2,…)

原理:打印格式串的内容,并用后面的表达式替换格式串中的转换说明

printf.png

格式串里面包含两个内容:普通字符和转换说明。

普通字符原样输出即可,因为内容已经写死。所以这里最值得讲的就是转换说明,也是很多人没有弄明白的地方。

转换说明的作用就是起到占位符的作用,它的格式:%[符号][宽度][.精度]类型

1
2
3
%m.pX		//右对齐,当显示字符不足 m 时,左补空格
%-m.pX // 左对齐,当显示字符不足 m 时,右补空格
%0m.pX // 右对齐,当显示字符不足 m 时,左补0

m 用来控制最小字段宽度。如果输出字段大于等于指定宽度就正常输出,否则 - 右补空格 或 0 左边 0 来满足欠缺的长度;如果你没有指定符号的话,就会左补空格。

1
2
3
4
5
6
7
8
9
10
11
	int age = 1000;

printf("age = %d | ", age);
printf("age = %3d | ", age);
printf("age = %5d | ", age);
printf("age = %-5d | ", age);
printf("age = %07d | ", age);

// 输出

age = 1000 | age = 1000 | age = 1000 | age = 1000 | age = 0001000 |

p 用来控制精度。如果指定的精度大于要输出的精度就会补0,否则显示指定长度的精度。

1
2
3
4
5
6
7
8
9
	double dnum = 192.167;

printf("dnum = %.1f | ", dnum);
printf("dnum = %.2lf | ", dnum);
printf("dnum = %.3lf | ", dnum);
printf("dnum = %.5lf | ", dnum);

// 输出
dnum = 192.2 | dnum = 192.17 | dnum = 192.167 | dnum = 192.16700 |

X代表发生的类型转换。

1
2
3
4
5
6
7
8
9
10
11
(1)%d:用于显示十进制有符号数,char,short,int,long long

(2)%u:用于显示十进制无符号数,unsinged short,unsigned int,unsigned long long

(3)%x: 用于显示十六进制整数,所有有符号及无符号整型

(4)%f:用于显示十进制浮点数,float,double

(5)%c:显示字符

(6)%s:显示字符串

标准输入

格式:scanf(格式串,表达式1,表达式2,…)

原理:本质是模式匹配

从左到右,根据格式串匹配 stdin 中的字符。如果匹配成功,继续匹配下一项;如果匹配失败,立即返回。最后,返回匹配成功的转换说明的个数。

我们的格式串包含三块内容:普通字符,空白字符,转换说明。

(一)普通字符需要精确匹配,如果匹配失败就会立即退出

1
2
3
4
5
int num;

// 普通字符需要精确匹配,如果匹配失败就会立即退出
scanf("/%d/", &num);
printf("num = %d", num);

如果你在输入字符的时候没有正常输入前面的 / 或 后面的 / ,那么就会匹配失败,并且立即退出。如果你没有成功匹配前面的 / ,那么立即匹配失败并退出,导致 num 为随机值,因为你不会有输入 num 值的机会。如果你没有匹配后面的 /,那么立即匹配失败并退出,但是 num 会正常输出,因为在此之前你已经成功输入 num 值并匹配到占位符中,只是后面的 / 没有匹配成功。如果 / 后面还有其他字符,也不会得到输出的,因为后面的 / 匹配失败导致后续的格式串也得不到匹配了,即没有被加入到 stdin 缓冲区中。

(二)在寻找数的起始位置时,会忽略任意零个或多个空白字符(如空格、制表符、换行符)

1
2
3
4
5
6
	int num1;
int num2;

//任意多个(包括0个)空白字符(如空格、制表符、换行符)
scanf("%d%d", &num1, &num2);
printf("num1 = %d , num2 = %d", num1, num2);

scanf输出.png

你可以看到数字 10 前面的空白字符会被忽略,数字 20 前面的空白字符会被忽略。因为 scanf 函数在寻找每个数的起始位置时会跳过空白字符,所以它可以成功读取这些数。

下面强调几个使用 scanf 容易忽视的地方:

  • scanf 的格式字符串中,任何空白字符(空格、制表符、换行符)都会使得 scanf 忽略输入中的空白字符,直到遇到下一个非空白字符。
  • scanf 有返回值,返回匹配成功的个数。不要将 scanf 放到 while 循环中使用。
  • 使用 %c 时需要注意,scanf 不会跳过空白字符,可能会读取到空格或换行符。因此要在 占位符前面加上一个空格,比方说 ‘ %c’。
  • 使用 %s 读取字符串时,scanf 会跳过前导空白字符,并在遇到第一个空白字符时停止读取。

getchar 和 putchar

前面我们将 scanf 获取单个字符存在问题,你必须占位符前面添加一个空格才可以,但是这很容易让人忘记。getchar 函数用于从标准输入读取一个字符。

getchar 从标准输入(通常是键盘)读取一个字符。如果输入的字符是 EOF 或在按下回车键之前没有输入字符,它将返回 EOF。

1
int getchar(void);

而 putchar 就用于输出一个字符了。

1
int putchar(int char);

参考阅读:C语言的标准输入输出