Ⅳ. C++的输入与输出
0x00 库的展开
我们刚才之所以讲解命名空间,就是为了让大家能够慢慢地看懂本篇一开始写的 HelloWorld。
但是在讲解C++的输入与输出之前,我们还需要再对命名空间做一个小小的补充。
📚 库也是会用命名空间的,C++库的实现定义包含在了一个叫 std 的命名空间中。
我们加上 using namespace std 是为了把 std 空间中所有的内容都展开,
这样我们就可以直接使用它们了。
❓ 为什么C++要把它封装到一个叫 std 的命名空间中呢?
💡 因为这样就不容易冲突了,有效放置了冲突命名。
📌 注意事项:这里要提一下,有些老的教材上有 #include <iostream.h>
这个在老的编译器上是可以的,比如 VC6.0 ,比较老的版本的库,没有命名空间。
早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件 即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文 件不带.h;旧编译器(vc 6.0)中还支持 <iostream.h> 格式,后续编译器已不支持,因此推荐使用 <iostream> +std 的方式。
【问题来自读者评论:20220612更新】
iostream.h过时了,是早期vs用的,我记得以前 vc6.0 的时候还是用 iostream.h的。
现在的新标准库是用 iostream 的。
文章里说的 "为了和C头文件区分,规定c++头文件不带.h” 是因为新的c++摈弃了.h形式的头文件。现在是标准c的头文件是.h,标准c++头文件不带.h。
所以不建议用iostream.h了。
头文件用尖括号引入,和用引号引入的区别:
首先,< > 和 " " 包含头文件的本质区别是查找策略区别。
① " " 的查找策略:先在源文件所在的目录下查找。如果该头文件未找到,则在库函数的头文件目录下查找
② < > 的查找策略:直接去标准路径下去查找。
所以库文件也是可以使用 " " 包含的。
#include <iostream.h> 是库文件,你用引号形式引入 #include "iostream.h" 也是可以的,
但是这样查找的效率就会低些。
而且这样也不容易区分是库文件还是本地文件。
(看到尖括号引入就知道是库文件,看到引号引入的就知道是本地文件,还是很香的)
因此不建议库文件用 " " 形式引入。
0x01 输入和输出
cout 标准输出(控制台)和 cin 标准输入(键盘)时,必须包含 <iostream> 头文件。
并且需要使用 std 标准命名空间,这里我们下面会详细探讨。
0x02 流插入运算符 <<
📚 cout 后面的 << ,我们称之为 "流插入运算符" 。就像水流的流向一样。
💬 cout 用法演示:
#include <iostream> using namespace std; int main() { cout << "Hello"; // 等同于 printf("Hello"); return 0; }
🚩 运行结果: Hello
📜 上面的代码,我们之所以可以直接用 cout,是因为我们已经把 std 这块库命名空间展开了。
我们下面会对专门对展开方式进行一个探讨。
📚 此外,如果我们想换行,我们可以使用 endl 。它就"相当于" \n,都可以起到一个换行的效果。
💬 endl 用法演示:
#include <iostream> using namespace std; int main() { cout << "Hello" << endl; return 0; }
当然,如果你不喜欢用 endl,完全可以用 \n 替代它:
#include <iostream> using namespace std; int main() { cout << "Hello\n"; return 0; }
📚 使用 C++ 的输入输出是很方便的,它最大的特点就是可以自动识别类型。
#include <iostream> using namespace std; int main() { int i = 10; double d = 3.14; cout << i << " " << d << endl; // 相当于 printf("%d %f\n", i, d); return 0; }
🚩 运行结果: 10 3.14
📌 注意事项:
大量输入输出时尽量少用或者不用 endl ,每次 endl 会刷新缓冲区,这增加了 io 次数,
在数据非常大的时候尽量不要用endl,转义字符不存在刷新缓冲区的问题。
即 —— 需要大量输入输出时建议用 \n 替换 endl 。
0x03 流提取运算符 >>
📚 cin 后面的 >> ,我们称之为 "流提取运算符" 。
#include <iostream> using namespace std; int main() { int i = 0; double d = 0.0; cout << "请输入一个整数和一个小数:> "; cin >> i >> d; cout << "你输入的是:> "; cout << i << " 和 " << d << endl; return 0; }
🚩 运行结果如下:
❓ 可以改变流的流向吗?
💡 可以!
#include <iostream> using namespace std; struct Student { char name[20]; int age; }; int main(void) { // cin - 流提取运算符 struct Student s = {"xiaoming", 18}; cin >> s.name >> s.age; cout << "姓名:" << s.name << endl; cout << "年龄:" << s.age << endl << endl; scanf("%s%d", &s.name, &s.age); printf("姓名:%s\n年龄:%d\n", s.name, s.age); return 0; }
0x04 学会因地制宜
我们好像可以在 C++ 里用 printf 欸!
#include <iostream> int main() { printf("Hello!\n"); return 0; }
因为 <iostream> 有些平台间接的包了 printf 等 C语言中的函数。
有人这时候就会觉得,C++的输入和输出可以自动识别类型,这也太爽了吧,既然 C++ 的输入输出这么好用,那我们是不是就用不上 C语言里的输入输出了?
并不是,我举个简单的栗子:
💬 如果我们想打印某个浮点数,如何控制小数点后的位数呢?在 C++ 的输入中,这是一件比较麻烦的事情。如果想控制小数点的位数,我们完全可以使用C语言的输入:
printf("%.2f", d);
因此,并不是说学了C++的输入输出,我们就不用C语言的输入输出了。
C++ 和 C语言的输入输出可以混在一起写,混在一起用。
什么时候用 C++ 的,什么时候用 C语言的,看情况就可以了。
💬 我们再来举个例子:
// 因地制宜! struct Student { char name[20]; int age; }; int main(void) { // 这种情况C++ 就不方便了 struct Student s = {"xiaoming", 18}; cout << "姓名:" << s.name << endl; cout << "年龄:" << s.age << endl << endl; // 用c呢? printf("姓名:%s\n 年龄:%d\n", s.name, s.age); // 所以说C语言也是有它的优势的嗷 return 0; }
🔺 总结:哪一个方便就用哪一个,具体谁方便需要看情况,要学会因地制宜。
0x05 对于展开方式的探讨
上面我们讨论过使用 using namespace 展开的缺陷,会失去隔离的效果。这样写好吗?不好。这么一来就全展开来了,所以我们可以这么写:
(不裂开了,我合上)
💬 采用方式一:空间名 + 作用域限定符
#include <iostream> //using namespace std; int main(void) { // cout << "Hello, World!\n" << endl; std::cout << "Hello, World!" << std::endl; // 指定命名空间 return 0; }
💬 采用方式二:使用 using namespace 命名空间名称引入 (会破坏隔离效果)
#include <iostream> using namespace std; int main() { cout << "Hello,World!" << endl; return 0; }
📌 虽然 using namespace 会破坏隔离效果,但是我们平时写练习还是可以这么去做的。因为我们平时不需要这么过分地讲究命名空间,但是以后在写项目或干正事的时候就得讲究讲究了。
💬 采用方式三:使用 using 将命名空间中成员引入
#include <iostream> using std::cout; // 把常用的展开 using std::endl; int main(void) { cout << "Hello, World!" << endl; return 0; }
Ⅴ. 再看 HelloWorld
深入浅出 —— 浅出
📚 现在我们再来回头看之前的 HelloWorld:
#include <iostream> using namespace std; int main() { cout << "Hello,World!" << endl; return 0; }