CS106L 04 学习笔记

191 阅读4分钟

CS106L 04 stream

recap

Uniform Initialization: Using {}

References: to use same memory


Stream Input/Output(IO)

最重要的图!!!!!! 屏幕截图 2024-12-28 213544.png

  • cout and cin: Standard iostreams 标准输入输出流

  • cerr and clog:被用来使用输出错误,或者日志

    std::cerr << "the message" << std::endl;
    std::clog << "What are we doing here" << std::endl;
    

对于如下代码:

std::cout << "Hello world" << std::endl;
// "<<" insertion operator
double pi;
std::cin >> pi; //3.1415926...
// ">>" extraction operator 

[!note]

std::coutstd::ostream中的一种,输出流,可以音译为"See out",看到的内容,就是输出的内容。

[!note]

std::cin是如何处理我们在控制台中输入的3.145926?这不是字符串吗?是,其会在程序中进行类型转换为double。这表明流允许以通用方式处理数据

ps:iostream 为 ostream 与 istream的集合


stringstreams

stringstreams 经常用于处理混合数据,是basic_iostream的组成成分

std::string mixText = "Liu kk 23203 19 hai KongKong";
std::stringstream ss; 
ss << mixText; // or 在上一步 ss(minText)

std::string first, second;
int no, age; std::string last;

ss >> first >> second >> no >> age >> last;
std::cout << first << " " << second << " 学号:" << no << " 年龄:" << age << " 剩余的部分 " << last << std::endl;
//Liu kk 学号:23203 年龄:19 hai

[!note]

">>" 提取运算符,从ss中提取元素,遇到空格结束提取,不包含空格,遇到\n结束istream没有。从而ss没有读取kongkong,如何完全读取剩余的部分?使用getline

istream &getline(istream& is, string& str, char delim) // 读取input流,分隔符delim(default='\n'),并储存在str中

std::getline(ss, last);
std::cout << last << std::endl; // hai KongKong

ps:fstream 为 basic_fstring


Out streams

"<<" 符号意思把内容送到输出流,输出流中的字符存储在中间缓冲区中在被冲到目的地之前。缓存区是为了提高效率,防止过多的IO操作。

我们熟悉的std::cout是行缓冲,缓冲区中的内容不显示在外部源上,直到冲洗发生。

double tao = 6.28;
std::cout << tao; // 这一步没有flush在控制台
std::cout << std::flush; // flush冲洗在控制台,控制台的实际类型为string
std::cout << std::endl; // 也flush冲洗在控制台same '\n' + flush;
for (int i=1; i <= 5; ++i) {
	std::cout << i << std::endl;
}

其过程如下,切记std::endl可以flush中间缓冲区,是'\n' + flush操作 。

1'\n'

...

2'\n'

.......

5'\n'

观察过程,浪费了那么大的中间缓冲区,而且过多flush操作消费是昂贵的。std::cout << endl;'\n' + flush操作,每一次冲洗操作的花费是昂贵的。那么直接存入字符即可。

for (int i=1; i <= 5; ++i) {
    std::cout << i << '\n';
}
1'\n'2'\n'3'\n'

[!note]

C++ 会采用自动冲洗,当中间缓存区满了,自动冲洗操作。但是在没有禁用同步流的情况下,依然会冲洗操作,采用禁用同步流可以达到目的。如果没有禁用同步流,\n依然会类似 C 中的操作flush呈现在 C++ 中。


同步流操作

一般情况下,C、C++I/O操作是同步的,这保证了输入输出的顺序性。采用如下代码可以禁用同步流,也就是禁用Cstdio.h标准库来禁用同步操作。

std::ios::sync_with_stdio(false);
std::cout << YES!MORE FAST! << '\n'; //Right!

[!WARNING]

特别注意,这将会导致一些出错,尤其是混合使用C和C++的输入输出流,特别是并发输出顺序。


File stream

  • is_open() 检查是否打开文件
  • open() 打开文件
  • close() 关闭文件
  • fail() 检查是否坏掉

如下代码,文件只读入了test,发生了截断Truncate

  std::ofstream ofs("truncate.txt");
  if (ofs.is_open()) {
    ofs << "Hello CS106L!" << '\n';
  }
  ofs.close();
  ofs << "this will not get written"; // 不会响应失败
  // to append instead of truncate!
  ofs.open("truncate.txt");
  ofs << "test";

如何解决,采用std::ios::app:Basically app always seeks to the end before writing anything

  std::ofstream ofs("append.txt");
  if (ofs.is_open()) {
    ofs << "Hello CS106L!";
  }
  ofs.close();
  ofs << "this will not get written";

  // to append instead of truncate!
  ofs.open("append.txt", std::ios::app);
  ofs << "this will though! It’s open again";

  ofs.close();

cin stream

输入缓存区,当遇到如下冲刷缓存区并保留:

  • ' ' // 单个空格
  • \t // 制表符
  • \n 换行字符

如何读取人名,带有空格的,如下:

double pi;
std::cin >> pi;
std::string name;
std::getline(std::cin, name); // 默认deilm是 '\n'

[!note]

当我们输入pi时,缓存区留下\n这与getline操作相遇会进行清除换行符,进而结束操作,没有任何读入到变量name中。getline会清除\n

解决方案如下:双getline

double pi;
std::cin >> pi;
std::string name;
std::getline(std::cin, name);
std::getline(std::cin, name); // 默认deilm是 '\n'

Don’t use getline() and std::cin() together, unless you really really have to!


End...