剑指offer (1)

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的引用。这样,我们可以继续使用 << 运算符,实现一个拼接的输出。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注