接下来讲讲跟输入输出有关的杂事
有些同学关心我会接下来该怎么喝水。我暂时还没有找到更大的水桶,所以喝不了水了
所以不好意思露脸了。今天我们就听听我的声音吧
在这个C++里面,有好些跟输入输出相关的类。他们都在iostream立面定义的
这下面的就是基类ios
然后从ios派生出istream,派生出ostream。那我们知道
cin就是istream对应的对象,cout就是ostream的对象。然后istream派生出ifstream
ifstream呢就是对文件进行读操作的。ostream派生出ofstream。ofstream呢
是用来对文件进行写操作的。然后istream和ostream共同派生出iostream
iostream呢又派生出fstream。fstream呢可以用来打开文件进行读操作也进行写操作。
这里列出了各个类 他们的对象。我们知道了cin是istream的对象。cout是ostream的对象。
那iostream里面除了这个cin,cout,还会有一些
其他的对象。比如cerr和clog 我们知道cin叫做标准输入,cout也称为标准输出
那cerr就称为标准错误输出。clog基本上跟cerr是
差不多的啦,也是标准错误输出。那我们在缺省的情况下不管你把一个
东西输出到cerr,输出到clog,还是输到cout,效果都是一样的。反正这些注意,
都会出现在题目上。cin它对于标准输入流,他可以用来从键盘读取数据,
也可以被重定向为从文件中读取数据,等会儿我们再看重定向
cout对于标准输出流,他用于向屏幕输出数据,也可以被重定向为向文件写入数据
cerr和clog呢可以用来对屏幕输出出错信息
cerr和clog有一点小区别,跟缓冲区有关,我们不说它
我们看一个重定向的例子。输出重定向
在这里程序里面我们有这条语句freopen("test.txt","w"stdout)
这条语句酒吧标准输出重定向到test.txt文件 这条语句的效果是什么呢
大家知道这个cout代表标准输出设备。缺省的情况下也就是屏幕。把它交给cout输出的东西
也会出现在屏幕上。但是呢,我们通过这条语句,把这个标准输出设备stdout重定向到了这个test.txt
这边的w代表写,那么在这种情况下你交给cout输出的东西就会出现在test.txt这个
文件里,他不会出现在屏幕上了。那我们看看这个程序呢,他读出,读入x,y,然后如果y
等于0的话,就要输出一个error。这个error是交给cerr进行输出的。cerr是什么啊,是标准错误
输出设备。他缺省的情况下呢就是屏幕。就是说这个error就会出现在屏幕上。这个cerr
并没有被重定向,但下面这个cout被重定向了。所以说只要y不为零的话呢x除以y的商就会被输出到test.txt
里面去。通过这个例子我们看到这个cerr还是挺有用的啊。假设有时候你的一个程序
输出的结果是一个文件。就是你想把你的程序输出结果放到一个文件里面,那你要通
过对这个cout进行重定向,然后把数据都交给cout输出,就能达到这个效果。但这个程序呢中间可能还要
输出一些调试信息。这个调试信息你并不希望他出现在这个结果的文件里头,而希望他出现在屏幕上。
这个怎么办呢。你如果把调试信息交给cout输出,那岂不是调试信息也拍到文件里了。所以解决问题的办法就是
我们把cout重定向了,但是呢我们没有把cerr重定向。然后我把调试信息交给cerr输出,这样我们这个程序的
一些正确的结果就会被重定向到文件里面,而那些调试信息呢还是通过cerr输出到了这个屏幕上。
那实际上这个标准输出可以被重定向,标准输入也可以被重定向。像这个freopen("t.txt","r"stdin)
r代表读,stdin代表标准输入设备,那这个标准输入设备被重定向以后呢
以后我们再从cin读取数据,cin读取数据的语句就不会被停下来
等待用户从键盘敲入数据。cin就直接从文件里面去读取数据了。所以家属有一个t.txt
它的内容是3.14
123,好,那我们这个程序运行起来的时候啊,就不会停下来等待用户输入而是直接
从文件里面把3.14就读到f里面去,把123读到n里面去。当你输出的时候
就是3.14 123了。那我们输入输出的地方呢我们统称为输入流
那我们知道这个键盘也是输入流的来源。一个文件也可以是输入流
尤其是我们可以把这个标准输入重定向成从文件里面读取数据,
那文件就是个输入流了。那有的时候我们不会需要
读取文件的内容。直到这个文件的内容被读完了我这个程序就结束
那我们在做从文件里面输入的时候 怎么样才知道文件的数据都已经读完了呢
那如果我们是经过了吧标准输入重定向成一个文件以后,并且用cin
从文件里面读取数据,那么我们就需要判断文件的结束,具体的办法就是
这么写。假设我现在要从一个文件里面不停地读入整数,那我怎么知道这个文件是不是已经读完了呢
我们 用一个while循环读入整数。这么写就行了。当文件结束的时候
也就是输入流结束的时候,这个表达式的返回值是
false,于是循环就可以结束。那这样说起来是比较奇怪的,因为我们前面讲过这个
右移一串符在h类里面的重改,它应该是这样的。
它的返回值是什么是,是fstream的引用。也就是说这个表达式它的返回值应该是
istream的引用,自然就是cin的引用。也就是cin。那cin怎么能够作为
这个条件,它的值可以为true也可以为false呢。按理说这是说不过去的。
但实际上这里面又碰到了一个以前没有说过的
叫,难一点的知识,叫做强制类型转换运算符的
重载。也就是说这个表达式它的返回值虽然是cin 但是在istream里面
有一个强制类型转换运算符的重载就能够把这个cin对象强制转换成
类型的值。所以当输入流结束的时候
这个心被转换出拉力的布尔类型的纸就是false。这个循环就结束了
那么关于类型强制转换运算符的重载,
同学们有兴趣的可以去看教材,或者上网搜一搜 这里就不讲了
那说到这个输入流的结束,输入流到底什么样才算结束。那么如果这个输入流是从
文件的话,比如说我们通过重定向把标准输入
定向为是从文件里面读取数据,那么着这个文件结束的时候,输入流自然的就结束了
那如果这个输入流是从键盘输入的,那怎么样才算结束呢
也就是说,如果你在键盘桥数据的时候,在单独的一行
就你敲了一个回车,下面新开一行了然后你在敲一个Ctrl+Z
这个时候输入流就会结束了 下面再来看一些istream类的几个重要的成员函数
其中一个是getline。getline呢它有两个版本。是重载的。
第一个版本我们看,它是从输入流中读取bufsize减一这么多个字符到缓冲区buf
或者读到碰到|n为止
那么读取了bufsize减一这么多个字符
或者碰到|n这两个条件,哪个先到就算哪个。那个条件先碰到了
getline函数就返回了。它的读取就结束了。
那getline的第二个版本比第一个版本多了一个
第三个参数,就是delin。就是一个字符。这个字符称为分隔符
那第二个版本呢,他从输入流中读取bufsize减一个字符到缓冲区buf
或者说还没有读取这么多个字符,但是呢已经碰到了这个分隔符,那么这个读取也结束
反正这两个条件也是哪个先到算哪个
那主意这两个函数有共同点。就是他们都会自动会在buf中 读入的数据当中添加一个结尾的|0
而且这个输入流里面的|n或者这个分隔符都不会被读到buf里面去
虽然不会被读到buf里面去呢,这个|n或者这个
分隔符都会被从输入流中取走,也就是删掉
那如果在输入流里面的|n或者
分隔符之前字符个数达到或者超过了bufsize个
那这次能读入数据,但是实际上他也会产生出错。出错的结果是
影响了下一次的读入,也就是说虽然本次读入能够完成,数据也能读进来,但是之后你再去用
cin做仍和读取操作就都会失败了。注意是之后再用cin做仍和的读取操作
还是个字符串然后我希望根据这点不同我在程序里面如果发现是整数
我就cin一个整数,如果发现是一个字符串我就cin一个 这个字符串
但是问题是你不读取一个字符出来看一下它是一个数字还是一个字符你就不知道它是一个
整数还是字符串。那你如果从输入流里面读取了一个字符以后呢
你虽然能判断出他是一个整数还是一个字符串,但这个字符已经被你读取进来了。当你下一次再要
从输入流里面读取整数和字符串的时候呢就已经撒掉了头一个字符,那这个结果就不对了
所以有时候你会觉得哎呀多读了一个字符很麻烦 你只peek了这个成员函数
就提供给你了一个手段去看一下输入流里面的
下一个字符是什么然后再决定我下一步要适应一个整数还是适应一个字符串
这是好的。那
istream还有一个putback成员函数。它能把一个字符放回到输入流里面去。你读出来觉得后悔了还可以塞回去
当然你可以把仍和一个其他字符放入这个流里面也可以
这个字符就会被放到输入流的头部,最前面的地方 然后这个ignore
ignore成员函数能够从流中删掉最多nCount个字符。就直接把这些字符从输入流里面去掉了
或者说 还没有删掉nCount个字符的时候就已经碰到了这个
‘delim那这个ignore也就算完成任务了
那这个’delim它的值是eof。eof就代表这个输入流的结束
eof一般来说它的值是一。总之呢这个函数是用来
跳过输入流里面的一些这个字符的。这个getline是这个采用的一个
istream的成员函数。我们下面补充一个在使用getline的过程当中会经常碰到的一个问题
大家看这个程序。这个程序先读入一个整数x
然后用getline的办法读取一整行
我们假设我们这一整行不会超过90个字符,不会达到90个字符,然后把整行输入
这个程序在处理不同输入的情况下可能不会导致一些问题。我们看
如果我们输入12空格abcd,这个代表回车
代表回车,那这个时候输出的结果是空格abcd。这个
很好解释。这个12被读到了x里面,然后getline呢
就直接从12后面开始。他不会跳过去空格。连着空格一起
一直读到函末,所以把空格以及abcd读到buf里面去。那我们输出结果大概就是就是空格abcd
但是如果你输入那个,程序运行的时候你输入一个12敲个回车
你正打算输入第二行的时候这个程序他就突然结束了
它会输出一个12然后后面这个buf输出的是什么呢,看上去什么都没有
那为什么会程序就立即结束,还没有等你输第二行就结束了呢。这是因为
你又cin又x读了一个12以后
然后你又敲了回车。他这个回车实际上它是位于输入流里面的
它并不会由于执行了cin又一x而被读出来
那回车还在输入流里面的时候你再执行cin.getline
那我们知道这个getline它是碰到回车
就立即结束了对不对,那12后面跟了一个回车再执行getline的时候
cin马上碰到了回车于是getline结束了。那这个时候不会有仍和字符被读到buf里面去
你尽管getline语句并没有读取仍和数据到buf,getline依然回到了buf
里面添加一个杠零,等于就说buf的里面的
头一个字符就是杠零。那也就是说buf是一个空串。在这里输出的时候就是一个空的东西
不会输出一大堆乱七八糟的内容
那关于输入输出还有一点
需要知道的东西就是所谓的流超重算值。那这部分内容呢这边繁琐
讲起来又没意思又啰嗦,听起来也很无聊
还不如让大家自己看,所以这部分关于流超重算值的内容我们就只提供PPT,就不在
讲述了。大家自己回去