C语言细节 字符输入/输出

1.缓冲区
(1)无缓冲输入与缓冲输入:

1.无缓冲输入:如果正在等待的程序可以立即使用输入的字符,称为无缓冲输入(或直接输入)

2.缓冲输入:如果输入的字符先被收集并存储在1个称为缓冲区(Buffer)的临时存储区
按下Enter键后正在等待的程序才能使用输入的字符,称为缓冲输入

在这里插入图片描述

如以下程序:
#include <stdio.h>

int main(void) {
    char ch;
    while ((ch=getchar())!='#') {
        putchar(ch);
    }
    return 0;
}
//结果:
Hello,I would[Enter]
Hello,I would
like a#in the[Enter]
like a
//在部分老式系统中会是:
HHeelllloo,,II wwoouulldd[Enter]
lliikkee aa#

(2)缓冲输入的优点:

缓冲输入的优点有:
①把若干个字符作为1个块进行传输比逐个发送这些字符节约时间
②如果输入错误,在按下Enter键之前都可以直接用键盘进行修改

不过,有些时候也需要无缓冲输入,如在游戏中,按下1个键就需要执行相应的命令

(3)完全缓冲与行缓冲:

缓冲分为完全缓冲和行缓冲:
完全缓冲是指在缓冲区被填满时刷新缓冲区并发送内容至目的地,通常出现在文件输入中
缓冲区的大小取决于系统,通常是512B或4096B
行缓冲是指在出现换行符时(通常是按下Enter键时)刷新缓冲区并发送内容至目的地

(4)如何选择:

ANSI C及后续的C标准均规定输入是缓冲的,但K&R把决定权留给了编译器的编写者
ANSI C决定使用缓冲输入的原因是:一些计算机不允许无缓冲输入
不过,有些系统为无缓冲输入提供了一系列特殊的函数,但C标准没有该规定
getchar()使用的是行缓冲输入

2.结束键盘输入
(1)文件,流,键盘输入:

文件(file)是存储器中存储信息的区域;通常,文件都保存在某种永久存储器中.文件对计算机系统
很重要,如程序就保存在文件中

C有许多有关文件的库函数;从底层来说,C可以使用OS的基本文件工具直接处理文件,这些直接调用
操作系统的函数称为底层I/0(Low-Level I/O).由于OS不同,无法为普通的底层I/O函数创建标准
库,ANSI C也不打算这样做.但从较高层面上,C可以通过标准IO包(Standard I/O Package)来处
理文件.这涉及创建用于处理文件的标准模型和1套标准I/O函数.在这一层面上,具体的C实现负责
处理不同系统的差异,以便用户使用统一的界面
不同系统在处理文件时存在差异.如不同系统存储文件的方式不同,有些把文件内容存储在一处,而
文件相关的信息存储在另一处;有些在文件中创建1份文件描述.在处理文件方面,有些使用单个换
行符标记行末尾,有些使用回车符和换行符的组合来表示行末尾.在衡量文件大小上,有些使用最小
字节,有些使用字节块
如果使用标准I/O包,就不用考虑这些差异,因此,可以用if(ch=='n')检查换行符.即使系统实际用的是回车符和换行符的组合来标记行末尾,I/O函数会在2种表示法之间相互转换

从概念上看,C不是直接处理文件而是处理流(Stream).流是1个理想化数据流,实际的输入/输出映
射到流.这意味着不同属性/种类的输入,由属性更统一的流来表示.打开文件的过程就是把流与文
件相关联的过程,且读写都通过流来完成,而不用考虑具体的属性/种类(:流是OS提供的接口)
stdin流表示输入的内容,stdout流表示输出的内容.getchar()/putchar()/printf()/scanf()
都是标准I/O包的成员,用于处理这2个流.输入通常是从键盘,输出通常是到屏幕
以上内容表明,可以用处理文件的方式来处理输入的内容.如可以用C的输入函数中内置的文件结尾
检测器来结束输入

(2)文件结尾:

OS需要以某种方式判断文件的开始和结束.旧的方法是在文件结尾放1个特殊字符作为标记
之后,OS使用内嵌的Ctrl+Z来标记文件结尾,这曾经是OS使用的唯一标记
不过现在有一些其他选择,如记录文件大小,所以现在的文本文件不一定有嵌入的Ctrl+Z
但是如果有,OS会将其视为1个文件结尾标记(见下图)

在这里插入图片描述

OS标记文件结尾的另1种方法是记录文件大小.如文件有3000B,程序读到3000B时便到达文件结尾
使用这种方法就可以在文件中存储任何字符,包括Ctrl+Z

无论OS使用哪种方法检测文件结尾,在C语言中,getchar()/scanf()检测到文件结尾时对会返回1个殊
值EOF(End of File).通常EOF在stdio.h中被定义为-1:
#define EOF -1
使用-1是因为getchar()的返回值为0~127(ASCII码)/0~255(扩展字符集),-1不对应任何字符
另外,绝大部分系统都可以通过键盘模拟文件结尾条件,因而无需特别处理


int ch;//或char ch;也可以,但部编译器可能报错,因为getchar()返回int类型
while ((ch=getchar())!=EOF) {//EOF定义在stdio.h中
    putchar(ch);
}
//输入Ctrl+Z后终止(注意:①不是输入EOF或-1 ②不同系统需要输入的终止命令不同)

3.重定向和文件

在默认情况下,C程序使用标准I/O包查找stdin作为输入源,但也允许从其他地方(如文件)查找输入

使用文件:
1.使用特定函数对文件进行操作
2.设计能与键盘和屏幕互动的程序,通过不同渠道重定向输入到文件或从文件输入,即把stdin/
stdout赋给文件,继续使用getchar()/putchar()通过流操作数据

重定向的使用有一些限制,但用起来比较简单;此外,重定向和OS有关,与C无关
UNIX/Linux/Windows都有重定向特性,一些C实现还在缺乏该特性的系统中模拟该特性

//以下使用的echo_eof.c中的代码为:
#include <stdio.h>
int main(void) {
	fflush(stdin);
	int ch;
	while ((ch=getchar())!=EOF) {
		putchar(ch);
	}
	return 0;
}

(1)重定向输入:

使用(输入)重定向运算符(<)进行输入的重定向:
<programm_file> < <source_file>
  #参数说明:
    programm_file:要执行的程序(路径及文件名)
    source_file:作为输入设备的文件(从该文件输入)

C程序不知道输入的内容来自哪里,只知道这是要导入的字符流
C把文件和I/O设备放在1个层面,重定向后,文件就相当于程序使用的输入设备

#实例(Linux/UNIX):编译echo_eof.c,生成可执行文件echo_eof并有1个名为words的文本文件
$ ./echo_eof#运行该文件
$ ./echo_eof < words#运行该文件,并将输入重定向至words
We secure,
    we conatin,
        we protect.
#实例(Windows):可执行文件为echo_eof.exe,文本文件为words.txt
C:\Users\1234>G:\echo_eof.exe < G:\words.txt
We secure,
    we conatin,
        we protect.
#注意:'>'两侧的空格在Linux/Windows/UNIX中都可选,但在某些系统中不允许有这些空格

(2)重定向输出:

使用(输出)重定向运算符(<)进行输出的重定向:
<programm_file> > <target_file>
  #参数说明:
    programm_file:要执行的程序(路径及文件名)
    source_file:作为输出设备的文件(输出的该文件)

#实例(Windows):
C:\Users\1234>G:\echo_eof.exe > G:\words.txt
jdaklaksnlaskxn\n\r\tczx\n\nsasas\r
#注意:\n等不会被识别为换行符等,[Enter]才是换行
^Z#注意:需在某行开始处按Ctrl+Z才会结束,如果该行前面有字符,不会结束
#实例(Linux/UNIX):
$ ./echo_eof > G:words
jdaklaksnlaskxn\n\r\tczx\n\nsasas\r
^D

(3)组合重定向:

2个重定向运算符可以同时使用,如:
C:\Users\1234>G:\echo_eof.exe > G:\words.txt < G:\as.txt
也可以写为(因为命令与运算符的顺序无关):
C:\Users\1234>G:\echo_eof.exe < G:\as.txt > G:\words.txt

#注意:
1.在1条命令中,输入文件和输出文件不能相同,如下述命令错误:
C:\Users\1234>G:\echo_eof.exe < G:\words.txt > G:\words.txt
因为重定向输出会将输出文件中原有的内容清空,这样从该文件输入前该文件就已被清空
故该命令只会清空words.txt,而不执行其他操作
2.使用重定向符不能从多个文件输入,也不能输出到多个文件
3.用重定向运算符连接的2个文件必须1个是程序文件,另1个是数据文件

(4)通过函数重定向:

//这几个函数都在stdio.h里
打开指定文件:<fp>=fopen("<fname>","<mode>");
从文件中读取字符:<ch>=getc(<fp>);
关闭文件:fclose(<fp>);
  //详情参见 C语言细节.文件的输入与输出.二 部分
  //参数说明:
    fname:文件路径及文件名
    mode:打开模式;可为r/w/a/~b/~+
    fp:返回文件内容;如果打开失败,NULL

4.混合使用scanf()和getchar():

//二者均从stdin中获取数据
#include <stdio.h>
void display(char cr,int lines,int width);
int main(void) {
	fflush(stdin);
    int ch,rows,cols;
    printf("enter a character and two integers,use blank to separate:\n");
    while ((ch=getchar())!='\n') {
        if (scanf("%d %d",&rows,&cols)!=2) {
            break;
        }
	    display(ch,rows,cols);
	    while (getchar()!='\n') {
	        continue;
	    }
        printf("enter character and integer again,or enter a newline to quit\n");
    }
    printf("Bye");
    return 0;
}
void display(char cr,int lines,int width) {
	int row,col;
	for (row=1;row<=lines;row++) {
		for (col=1;col<=width;col++) {
			putchar(cr);
		}
		putchar('\n');
	}
}
//结果:
enter a character and two integers,use blank to separate:
d 3 4
dddd
dddd
dddd
enter character and integer again,or enter a newline to quit
s 2 5
sssss
sssss
enter character and integer again,or enter a newline to quit

Bye
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值