前
Let it known,don’t let it go.
操场上,看见一个在练习滑板的女孩,不小心摔倒。婉然微笑,撑起身来。是如此的优雅(graceful)。
一语言,只是一种工具,任何一门编程语音都是。数据结构和算法才是他的灵魂
标准输入输出
平日里,使用C/C++在Coding时,C中的printf,scanf
和C++里面的cout,cin
显然我们时十分的熟悉了
int printf ( const char * format, ... );int scanf ( const char * format, ... );extern istream cin;str >> cin;extern ostream cout;cout << str;
Q&A
Q:为什么S函数需要&, 而P不需要?
A:& 在C中时作为单目运算符时,时寻址作用。这里在S写入时需要一个指针指向一个真实的分配的对象空间,用来存储他的相应的数据类型。在P函数中,时写这个C字符串的格式化内容到stdout中。在字符串的响应位置,是用后面的参数直接对内容进行替换,所以不必使用&对其真实的内存空间进行操作。
事实上,这些输入输出函数,底层进行操作的就是我们的输入输出流。
执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。
所以这里我们可以把输入和输出看作一个文件,使用操作文件的方法,对这些文件指针进行操作。
FILE * stdin;FILE * stdout;FILE * stderr;
上面是着三个文件值指针的定义,在stdion.h 中
#include <stdio.h>int main(int argc, char** argv){ int num; fscanf(stdin, "%d", &num); fprintf(stdout, "%d\n",num); getchar(); return 0;}
可以看到,上面的stdin和stdout是直接进行操作的,没有打开的过程。因为在这个控制台程序运行起初,就已经打开了这三个流文件。
流缓冲
看看这段代码会发生什么?会一秒一次的打印字符串对吧?实际上不然。真正的结果是。在程结束之后,会打印一堆的blah
int main(int argc, char **argv){ for (int i = 0; i < 10; i++){ printf("%s", "balabala"); sleep(1); } return 0;}
C++ 程序中把输入输出是看作了字节流。在io过程中,程序只负责检查字节流,而完全不用知道是从哪里来的。
所以在流处理的过程中,一个重要的过程就是缓冲。当发生一次打印的条件是
- 缓冲区满- 遇到换行符(EOF)- 程序正常结束
stdout,和stderr 都是输出流,前者存在缓冲,后者是没有缓冲的。
我们可以用int fflush(FILE *stream);
函数进行强制的缓冲区刷新。
cout << flush;flush(cout);
或者使用 steambuf 类里面的方法进行。如果直接进行setbuf(stdout,Null)
,把他的缓冲区设为0。这样stdout也是成为了无缓冲的流了
Q&A
Q:缓冲区的好处?
A:使用缓冲区是可以更高效的处理输入和输出。缓冲区是作为中介的内存空间。我们可以一撮进行大量的读取或者写入。之后再进行整块的字节操作。这样会比单字节操作快得多。
iostream类库
在C++中,iostream是作为流管理的。在其中有创建4个流对象。
(实际上可以讲8个,四个是用于窄字节char,四个用于宽字节wchar)。
-
cin 标准输入流对象(stdin) wcin
-
cout 标准输出流对象(stdout) wcout
-
cerr 标准错误流对象(stderr) wcerr 无缓冲
-
clog 标准错误流对象。 wclog 缓冲
流的一端和程序相连,另一端和标准IO相连。
Q&A
Q:重定向?
A:实际上在iostream这个类库里, <<,>>
这两个本来是作为移位运算的操作符,被重载。在这个情况下 << 是应该被成为插入运算符。
在cout << "hello"
,中,由于我们的运算符重载,可以使之识别C++里面的所有的基本类型。
运算符重载
除了类属关系运算符”.”、成员指针运算符”.*”、作用域运算符”::”、sizeof运算符和三目运算符”?:”以外,C++中的所有运算符都可以重载。
这里给出了运算符重载的一般格式。这样通过这个功能,我们可以实现自己的运算操作
<返回类型说明符> operator <运算符符号>(<参数表>){ <函数体>}
在iostream类库中的 << 就已经被重载为了插入运算符。而且实现的相当的巧妙。
cout << 88;//实际上对应的原型是ostream & operator << (int);
这样就实现了 <<
对int
的重载,使得我们可以输出。从上面的形式分析,其参数是int ,其返回的类型是一个ostream的引用。这个引用。是这个结构极为精妙的存在。
拼接输出
cout << "buzz" << "fuzz" << endl;
这一段代码,当然十分熟悉,拼接输出。可是具体是怎么实现的呢???这里的拼接,就是这个雷克十分精妙的地方
ostream & operator << (ostream &);
当我们使用这个重载的运算符之后,返回的是一个ostream的引用。这样,我们可以继续使用 << 运算符,实现一个拼接的输出。