C语言中的输入输出
缓冲区
在C语言中,输入输出缓冲区是提高I/O操作效率的一种机制。通过使用缓冲区,程序可以减少直接与硬件(如键盘、显示器或文件)交互的次数,从而提高性能。
缓冲区是内存中的一块区域,用于临时存储数据。在进行输入输出操作时,数据首先被写入缓冲区,然后再从缓冲区传输到目标设备
类型
- 全缓冲:数据在缓冲区满时才进行I/O操作,例如是对磁盘文件的读写。
- 行缓冲:当遇到换行符时,数据才会被写入设备。输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O 操作。通常情况下,终端(如命令行)就是行缓冲;标准输入(stdin)和标准输出(stdout)就是此类型。
- 无缓冲:数据将立即写入设备,没有缓冲机制。

刷新缓冲区
fflush() 函数是在 C 语言中用于刷新输出缓冲区的标准库函数。它的主要作用是将缓冲区中的数据强制写入到相应的输出流(如文件或标准输出)。(从缓冲区把数据发送到屏幕或文件被称为刷新缓冲区)
注意
- 对于输入流(如
stdin),fflush()的行为是未定义的,因此不应使用fflush()来清空输入缓冲区。 - 使用
fflush()可能会影响程序的性能,因为它会导致系统调用,从而增加 I/O 操作的频率。
格式字符串
指在编程中用来指定输入或输出数据格式的字符串,通常用于函数如 printf 和 scanf 中。在 C 语言中,格式字符串允许你控制数据的显示方式或如何解析输入。如:printf(格式字符串,待打印项1,待打印项2,… . ) ;

格式字符串的组成:实际要打印的字符+转换说明

scanf()
scanf()阻塞
C 语言没有提供输入输出关键字,C 语言的输入和输出通过标准函数库来实现,我们通过scanf 函数读取键盘输入,我们把键盘输入又成为标准输入,当scanf 读取标准输入时,如果没有输入任何内容,那么scanf 会阻塞
#include <stdio.h>
int main()
{
int a;
char c;
scanf("%d",&a);
printf("a=%d\n",a);
scanf("%c", &c);
printf("c=%c", c);
return 0;
}
输入输出结果
15
a=15
c=
首先是阻塞,输入15,然后回车,输出a=15;scanf 匹配一个字符,就会在缓冲区删除对应字符。因为scanf(“%c”,&c)时,不会忽略任何字符,所以scanf(“%c”,&c)读取了还在缓冲区中残留的\n,打印输出了换行
读取字符
scanf存在问题
scanf读取数字时会跳过空格、制表符和换行符,而scanf 在读取 %c 时不会自动跳过空白字符(空格、换行、制表符等)。这意味着如果你在读取字符之前已经输入了一个整数或其他内容,可能会因为空白字符(如换行符)而导致读取到不想要的值
#include <stdio.h>
int main()
{
int n;
char c;
scanf("%d%c", &n, &c);
printf("n=%d,c=%c",n,c);
return 0;c
}
输入输出结果

使用 %d 来读取整数时,scanf 会跳过前面空白字符并读取到 23,对于 %c,scanf 不会自动跳过空白字符
%c、 %c
在scanf格式字符串中的转换说明前加空白可跳过下一个输入项前面的所有空白,即在%c前留一个空白可跳过输入项前的所有空白
#include <stdio.h>
int main()
{
int n;
char c;
scanf("%d %c", &n, &c);
printf("n=%d,c=%c",n,c);
return 0;
}
输入输出结果

-
scanf(“%c”,&ch):从输入中的第1个字符开始读取
-
scanf(" %c",&ch):则从第1个非空白字符
getchar
通过getchar 可以一次从标准输入读取一个字符,等价于scanf(""%c",&c),
#include <stdio.h>
int main()
{
char c;
c=getchar();
printf("you input alphabet=%c\n",c);
}
输入输出结果

putchar
putchar()输出字符数据,作用是向显示设备输出一个字符
#include <stdio.h>
int main()
{
char a1,a2,a3;
a1='a';
a2='b';
a3='c';
putchar(a1);
putchar(a2);
putchar('\b');//输出转义字符
putchar(a3);
putchar('\n');//输出转义字符
}
输出结果

关于结果为什么是ac?因为’\b’是退格字符,详情点击末尾转义字符
读取字符串
scanf读取字符串
scanf 使用%s读取字符串时,都从第1个非空白字符作为字符串的开始,以下一个空白字符(空行、空格、制表符或换行符)作为字符串的结束,即可读取的字符串中不包括空白字符。如果指定了字段宽度,如3s,那么scanf()将读取3个字符或读到其中的空白字符停止。
#include <stdio.h>
int main() {
char s[100];
scanf("%s",s);
printf("%s\n",s);
return 0;
}
输入输出结果

scanf从第一个非空白字符’s’开始,直到遇到下空白字符空格作为字符串的结束
#include <stdio.h>
int main() {
char s[100];
scanf("%3s",s);
printf("%s\n",s);
return 0;
}
输入输出结果

指定了字段宽度为3,在字段宽度内没有出现空白字符,将读取3个字符停止
#include <stdio.h>
int main() {
char s[100];
scanf("%9s",s);
printf("%s\n",s);
return 0;
}
输入输出结果

指定了字段宽度为9,在字段宽度内出现了空白字符,没有读取到9个字符,而是读到其中的空白字符停止
gets()
在读取字符串时,scanf()和转换说明%s只能读取一个单词。可是在程序中经常要读取一整行输入,而不仅仅是一个单词。
gets()函数简单易用,它读取整行输入,直至遇到换行符,然后丢弃换行符,储存其余字符,并在这些字符的末尾添加一个空字符'\0'使其成为一个C字符串。
#include <stdio.h>
int main() {
char s[100];
gets(s);
printf("%s",s);
return 0;
}

注:gets()不安全,容易导致缓冲区溢出,因为 gets() 不检查输入长度,用户输入的字符数可能超过分配的数组大小,导致内存损坏或安全漏洞。gets()函数在C11标准中已被删除,有些编译器不再支持使用,可使用fgets()、gets_s()可指定最大读取字符数的函数将其替代等。
#include <stdio.h>
int main() {
char s[100];
fgets(s,sizeof(s),stdin);//推荐使用
puts(s);
return 0;
}
puts()
puts 只能用于输出字符串,在末尾添加换行符。
#include <stdio.h>
int main() {
char s[100];
gets(s);
puts(s);
return 0;
}

printf()
printf( )语句把输出发送到缓冲区,然后缓冲区中的内容再不断被发送到屏幕上。
当缓冲区满、遇到换行字符,需要输入或程序结束的时候才会把缓冲区的内容输出到屏幕上。
如下代码不会输出到屏幕上(不同编译器结果可能不同)
#include <stdio.h>
int main()
{
printf("Hello,World!");
printf("Hello,C!");
printf("Hello,VS!");
while (1) {}
}
输出结果

需要刷新输出缓冲区才能正常打印,如在格式字符串的末尾加上换行符、调用fflush()函数
#include <stdio.h>
int main()
{
printf("Hello,World!");
printf("Hello,C!");
printf("Hello,VS!");
fflush(stdout);
while (1) {}
}
输出结果

转义字符
以“\”开头的特殊字符称为转义字符,转义字符用来表示回车,退格等功能键。
转义字符列表
| 转义字符 | 名称 | 描述 | 十进制 | 八进制 |
|---|---|---|---|---|
\a | 响铃 (BEL) | 发出响铃声 | 007 | 007 |
\b | 退格 (BS) | 将当前位置移到前一列 | 008 | 008 |
\n | 换行 (LF) | 将当前位置移到下一行开头 | 010 | 010 |
\r | 回车 (CR) | 将当前位置移到本行开头 | 013 | 013 |
\t | 水平制表 (HT) | 跳到下一个TAB位置 | 009 | 009 |
\v | 垂直制表 (VT) | 在垂直方向上跳到下一个TAB位置 | 011 | 011 |
\\ | 反斜线 | 代表一个反斜杠字符 \ | 092 | 134 |
\' | 单引号 | 代表一个单引号字符 | 039 | 047 |
\" | 双引号 | 代表一个双引号字符 | 034 | 042 |
\? | 问号 | 代表一个问号 | 063 | 077 |
\0 | 空字符 (NUL) | 表示字符串的结束 | 000 | 000 |
\ddd | 八进制字符 | 1到3位八进制数所代表的任意字符 | - | - |
\xhh | 十六进制字符 | 十六进制所代表的任意字符 | - | - |
示例
#include <stdio.h>
int main() {
printf("Hello,\a World!\n"); // 响铃
printf("This is a t\best.\n"); // 退格
printf("First Line\rSecond Line\n"); // 回车
printf("Column 1\tColumn 2\n"); // 水平制表
printf("Here is a backslash: \\\n"); // 反斜线
printf("Single quote: \'\n"); // 单引号
printf("Double quote: \"\n"); // 双引号
printf("Question mark: \?\n"); // 问号
return 0;
}
输出结果
#include <stdio.h>
int main() {
printf("Hello,\a World!\n"); // 响铃
printf("This is a t\best.\n"); // 退格
printf("First Line\rSecond Line\n"); // 回车
printf("Column 1\tColumn 2\n"); // 水平制表
printf("Here is a backslash: \\\n"); // 反斜线
printf("Single quote: \'\n"); // 单引号
printf("Double quote: \"\n"); // 双引号
printf("Question mark: \?\n"); // 问号
return 0;
}
输出结果

1159






