news 2026/10/23 2:52:11

第三章 C++基本输入/输出

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第三章 C++基本输入/输出

第三章 C++基本输入/输出

一、标准输入/输出

1.1 流是什么

流可以想成一条传送带。数据一件件放上去,从这头送到那头。程序不用关心传送带另一头接的是键盘、屏幕还是文件,拿到手里都是同一套读法。这也是这一章两节能放在一起学的原因,标准输入输出和文件输入输出,说到底是一条传送带的两段。

┌─────────────────────────────────────────────────────────┐ │ 输入输出四个现成对象 │ ├─────────────────────────────────────────────────────────┤ │ 程序不直接碰键盘和屏幕,中间隔着一层 │ │ │ │ +------------+------------+------------+------------+ │ │ |对象 |方向 |接哪 |缓冲 | │ │ +------------+------------+------------+------------+ │ │ |cin |往程序流 |键盘 |有 | │ │ |cout |往屏幕流 |屏幕 |有 | │ │ |cerr |往屏幕流 |屏幕 |无 | │ │ |clog |往屏幕流 |屏幕 |有 | │ │ +------------+------------+------------+------------+ │ │ │ │ 四个都是标准库给好的,include iostream 就能用 │ │ cerr 不攒货,崩溃前的最后几句话交给它 │ └─────────────────────────────────────────────────────────┘

四个对象都在 std 里住着,不用创建,拿来就用。前两章一直 using namespace std 图省事,工程里建议写清楚 std::,理由和第二章说 const 一样,写得显眼,搜得到。

对象方向默认接哪缓冲
cin流进程序键盘有
cout流出程序屏幕有
cerr流出程序屏幕无
clog流出程序屏幕有

cerr 和 cout 都接屏幕,差别在缓冲。cout 攒着送,cerr 立刻走,这个差别 1.3 节专门说。

1.2 cout 与链式输出

<< 叫插入运算符,把右边的东西递进左边的流。第一章见过它的面,这里补一句,为什么它能一路接下去。

┌──────────────────────────────────────────────────────────┐ │ 链式输出怎么接起来 │ ├──────────────────────────────────────────────────────────┤ │ cout << a << b 是一轮轮接起来的 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ cout << a 把 a 递出去,cout 把自己还回来 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ cout << b 拿到的还是 cout,接着往后递 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ cout << endl 一路递到缓冲区,等刷新 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ 每个 << 只干一件事,递出去,再把自己还回来 │ │ 所以能写成一条长龙,从左往右读就行 │ └──────────────────────────────────────────────────────────┘

关键在于还回来的还是 cout 自己,所以右边能接着接。一条输出写多长都行,读的时候从左往右,跟读句子一样。

cout << "学号 " << id << " 姓名 " << name << "\n";

字符串、变量、常量混着排,编译器按类型各自找递法。有个细节,相邻的两个字符串会并成一条,"abc" "def"编译出来就是"abcdef",长字符串折行写靠它。

cout << "第一行内容" << "接在上一行后面拼" << "\n";

单引号包字符,双引号包字符串,第二章讲过,这儿只提个醒。cout << 'A'送出去一个字母,cout << "A"送出去一个字母加一个结尾标记,后者在文件里是多出一个字节的。

1.3 endl 和 \n 的区别

endl 这个名字听着像换行,它其实干两件事。不少人只把它当换行用,白刷了性能还不知道。

┌──────────────────────────────────────────────────────────┐ │ 缓冲与刷新 │ ├──────────────────────────────────────────────────────────┤ │ cout 递出去的东西先攒着,不立刻上屏 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ cout << 字 内容进流的缓冲区 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 缓冲区 攒着,等一个刷新的时机 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 屏幕 刷新那一刻才看见 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ endl 是换行加刷新两个字,\n 只管换行 │ │ 循环里刷几万行,endl 能把速度拖慢一截 │ │ 程序正常走完会自己刷,崩溃才丢最后几行 │ └──────────────────────────────────────────────────────────┘

缓冲存在的理由很简单,屏幕慢。程序跑一次能吐几万行,行行都等屏幕确认,一天什么都干不完。先攒在缓冲区,攒够了或者时机到了,一次性倒过去。

必须刷新的场合有三种。交互提示语,问完话得让人看见,不然对方对着黑框框干等。崩溃前的最后遗言,这时候不刷,话就跟着程序一起没了。多个线程同时往终端写,不刷容易串行。

别用的场合就一种,大循环。写日志、刷表格、批量输出,用\n,攒着一路倒完。cout 在程序正常结束时会自己把剩下的刷掉,结尾不用操心。真正会丢的只有崩溃那一下,所以崩溃现场的遗言都交给 cerr,它不攒货,说了就走。

for (int i = 0; i < 100000; ++i) { cout << "第 " << i << " 行\n"; // 循环里用这个 } cerr << "配置文件读不到,先用默认值\n"; // 这个立刻走

重定向可以把两路分开收。跑程序的时候在命令行后面加 > 和 2>,一路输出进一个文件,一路错误进另一个。

./tool > result.txt 2> error.txt

写个同时往两路输出的程序,跑一遍重定向,两个文件里的内容对得上号,这事就算记住了。clog 也是往屏幕去,有缓冲,定位是日志,日常用得少,知道有它就行。

1.4 cin >> 的规矩

叫提取运算符,从流里按类型取东西。int 变量只认数字,double 认小数点,string 认到空白为止。取之前先把前导空白吃掉,空格、tab、回车都算。

┌──────────────────────────────────────────────────────────┐ │ >> 怎么跳过空白 │ ├──────────────────────────────────────────────────────────┤ │ cin >> 伸手之前,先把前面的空白吃掉 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 缓冲区 躺着空格 1 空格 2 换行 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 第一次 >> 跳过空白,拿走 1,停住 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 第二次 >> 空白和换行都拦不住,拿走 2 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ 所以 cin >> a >> b 分两行敲,一样读得进去 │ │ 代价是读字符串遇到空格就停,复姓只录半个 │ └──────────────────────────────────────────────────────────┘

回车被当空白跳掉,所以怎么换行敲都读得进去。方便是真方便,雷也埋在这儿,读字符串遇到空格就停,开篇那个欧阳 修 正撞上。

读个数不确定的一批数字,拿流本身当循环条件,读到文件尾自动停。

int x; int sum = 0; int cnt = 0; while (cin >> x) { sum += x; ++cnt; } cout << "共 " << cnt << " 个数,和是 " << sum << "\n";

命令行里敲 Ctrl+Z 再回车,Linux 和 macOS 是 Ctrl+D,告诉程序输入到头了。这个写法以后写实战反复用,现在先混个脸熟。

1.5 getline 读一整行

的短板在空格,一整行文本它读不动。这种场合交给 getline,自由函数,住在 string 头文件里,读到换行为止,换行符吃掉,行内的空格全留下。

string line; cout << "说点什么: "; getline(cin, line); cout << "你说了 " << line.size() << " 个字符\n";

三个参数的版本能换分隔符,读分号分隔的数据正好用。

string field; getline(cin, field, ';');

和 getline 分工明确,数字和单个词找 >>,一行文本找 getline。麻烦出在前后脚用的场合,前面 >> 留下的换行没人管,getline 上来就捡走,当成一整行。

┌──────────────────────────────────────────────────────────┐ │ 换行被谁捡走了 │ ├──────────────────────────────────────────────────────────┤ │ >> 和 getline 轮流上岗,中间要清场 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 键盘 敲下 25 回车 欧阳 修 回车 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ cin >> age 拿走 25,回车留在原地 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ getline 看见回车,捡走就当一整行 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 结果 姓名是空的,修 字没人管 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ 残留的换行,一句 ignore 捡走 │ │ 拿不准就统一用一种,别混着来 │ └──────────────────────────────────────────────────────────┘

开篇那个程序就这么修,在 >> 之后补一句。

cin >> id; cin.ignore(); // 把 >> 留下的换行丢掉 getline(cin, name); cout << id << "\t" << name << endl;

ignore() 默认只丢一个字符,正好是换行。想丢到行尾,写cin.ignore(10000, '\n'),稳妥一点用numeric_limits<streamsize>::max(),那个数大到不可能先读完,limits 头文件要给面子。嫌这两行烦还有一条路,全程 getline,拿到的字符串自己转数字,那是另一个话题,这里不展开。

四种输入方式放一张表里对照。

方式读到哪停留不留空白场合
cin >> x空白或类型不符丢数字、单个词
getline(cin, s)换行留一行文本
cin.getline(buf, n)换行留字符数组,老代码
cin.get(ch)一个字符留逐字符处理

后两种是给字符数组准备的,装不下会溢出,初学用前面两个就够。知道有它们,是以后读老代码不慌。

1.6 输入失败了怎么办

给 int 喂一个字母,程序不报错,它静静地把 failbit 置上,然后后面所有的读取直接失败,cin 变成一座雕像。

int n; cin >> n; cout << "你输入了 " << n << "\n"; // 输入 abc,这里打印 0 cout << "再读一个: "; cin >> n; // 这行直接跳过,问话都看不到

雕像的成因在流的状态位上。failbit 管类型对不上,eofbit 管读到尾,badbit 管流本身坏掉。状态不干净,流就一直装死。

┌────────────────────────────────────────────────────────┐ │ 流的状态位 │ ├────────────────────────────────────────────────────────┤ │ 流自己带着状态位,读挂了看得见 │ │ │ │ +------------+------------------------+------------+ │ │ |状态位 |什么时候置位 |后果 | │ │ +------------+------------------------+------------+ │ │ |failbit |字母喂给 int |之后全失败 | │ │ |eofbit |读到尾还接着读 |读到空内容 | │ │ |badbit |流本身出了故障 |基本没救 | │ │ +------------+------------------------+------------+ │ │ │ │ 修复三板斧,clear 清状态,ignore 倒垃圾,重读 │ │ 循环判断别用 eof,最后一行会被处理两遍 │ └────────────────────────────────────────────────────────┘

救活它有三板斧,代码里见分晓。

int n; while (!(cin >> n)) { cin.clear(); cin.ignore(10000, '\n'); cout << "要一个整数,请重输: "; } cout << "这次对了,是 " << n << "\n";

这个循环是控制台程序的标准件,输错就重问,直到给对为止。if (cin >> n)也能探状态,流在条件里会把自己变成真假,干净是真,脏了是假。

eofbit 单独说一句,它只在读过界之后才置位。所以while (!fin.eof())这种循环是经典错写法,2.3 节读文件还会碰见它。正确的判断方式是把流本身写进条件。

1.7 输出格式化

cout 默认输出不讲格式,数字挤数字,列对不齐。要列对齐,找 iomanip 头文件里的操纵器,用 << 递进去,跟递数据一个姿势。

操纵器作用粘不粘
setw(n)占满 n 列,不够补空格只管下一个
setfill(c)补什么字符粘
left / right靠哪边站粘
fixed小数写法,不用科学计数粘
setprecision(n)留几位小数跟着 fixed
hex / oct / dec换进制输出粘
boolalphatrue 和 1 之间切换粘

setw 只管下一个,是新手头号翻车点。设了一次以为一劳永逸,第二列开始全乱。

#include <iomanip> cout << setw(8) << 42 << "\n"; // 右边补空格,对齐到 8 列 cout << left << setw(8) << 42 << "\n"; // 靠左,之后都靠左 cout << fixed << setprecision(2) << 3.14159 << "\n"; // 3.14 cout << hex << 255 << "\n"; // ff

对齐一张表是个综合例子,setw 和 left 配着用,每一列都设一遍。

cout << left << setw(10) << "name" << setw(6) << "age" << "city" << "\n"; cout << left << setw(10) << "zhangsan" << setw(6) << 20 << "beijing" << "\n"; cout << left << setw(10) << "ouyangxiu" << setw(6) << 21 << "chuzhou" << "\n";

输出长这样。

name age city zhangsan 20 beijing ouyangxiu 21 chuzhou

全是英文和数字才对得齐,掺中文就歪。setw 按字符数补位,不管显示宽度,一个汉字占两列它不问。想对齐中文,自己写一个按显示宽度补位的小函数,这题留到课后练习。格式化还有 printf 一派的老写法,C++20 之后有了 std::format,这本书不展开,知道有它就行。

二、文件输入/输出

2.1 ofstream 写文件

文件的读写搬到 fstream 头文件,三个类按读写分工。

类能干什么默认打开方式
ofstream只写out 加 trunc
ifstream只读in
fstream读写都行in 加 out,不清空

最小示例,写三行进一个文件。

#include <fstream> using namespace std; int main() { ofstream fout("notes.txt"); fout << "第一行\n"; fout << "第二行\n"; fout << "第三行\n"; fout.close(); return 0; }

用法和 cout 一模一样,<< 递进去,东西进文件。长得一样,前面学的链式和操纵器,搬到文件流上照样好使。

两个坑先说在前头。第一,ofstream 默认带 trunc,文件原来有内容,一打开就清空,写完发现老朋友没了。要留着旧内容,用 app 追加,写日志的标配。第二,路径是相对于程序运行目录的,不是源码所在目录。在 IDE 里点运行和在命令行里跑,工作目录经常不是一回事,文件找不到,先怀疑这儿。

ofstream fout("log.txt", ios::app); fout << "又一次启动\n"; // 接在旧内容后面

关闭文件两种,显式 close,或者等对象析构自动关。忘关大概率没事,析构会兜底,但有两处要显式关,写完这份马上就要读回来,以及同一个流要换个文件重新开。

2.2 打开模式的组合

打开方式用标志位拼,六个标志,竖线相连。

┌────────────────────────────────────────────────────────┐ │ 打开模式的组合 │ ├────────────────────────────────────────────────────────┤ │ 六个打开标志,常用组合就四种 │ │ │ │ +------------+--------------------+----------------+ │ │ |标志 |干什么 |常见组合 | │ │ +------------+--------------------+----------------+ │ │ |in |开下来读 |ifstream 默认 | │ │ |out |开下来写 |ofstream 默认 | │ │ |app |写在末尾 |追加写日志 | │ │ |trunc |先清空再写 |默认就带它 | │ │ |ate |开完停末尾 |定位后再写 | │ │ |binary |按字节搬 |图片与音频 | │ │ +------------+--------------------+----------------+ │ │ │ │ 默认那套覆盖绝大多数场合 │ │ 文件默认文本模式,binary 放 2.5 节细说 │ └────────────────────────────────────────────────────────┘

常用组合就四种,只写覆盖、只写追加、只读、读写。读写两头占用 fstream,注意它默认不清空,这点和 ofstream 不一样。

fstream fs("data.txt", ios::in | ios::out);

文件不存在还想写,out 会顺带新建一个,in 不会,打不开就是打不开。这个差别 2.4 节要考。

2.3 ifstream 读文件

读文件的三种读法和标准输入同源,按词、按行、按字符。

┌────────────────────────────────────────────────────────┐ │ 三种读法各管一摊 │ ├────────────────────────────────────────────────────────┤ │ 读文件三种读法,按词按行按字符 │ │ │ │ +------------+------------------------+------------+ │ │ |读法 |写法 |适合场合 | │ │ +------------+------------------------+------------+ │ │ |按词 |fin >> word |数单词 | │ │ |按行 |getline(fin, s) |日志逐行看 | │ │ |按字符 |fin.get(ch) |数字符 | │ │ +------------+------------------------+------------+ │ │ │ │ 按词读最快,按行最常用,按字符最灵活 │ │ 读大文件按行走,内存吃得消 │ └────────────────────────────────────────────────────────┘

三种写法各配一个场合,数单词用 >>,逐行处理用 getline,数字符用 get。

ifstream fin("notes.txt"); string line; int no = 1; while (getline(fin, line)) { cout << no << ": " << line << "\n"; ++no; } fin.close();

循环条件直接写流,读到文件尾它自己变假,循环自然停。这比查 eof 优雅,也比它正确,1.6 节说过 eof 置位太晚。

整个文件原样拷到另一个文件,有一行搞定的写法。

ifstream fin("a.txt"); ofstream fout("b.txt"); fout << fin.rdbuf();

rdbuf 是流自带的缓冲区,倒过去连循环都省了。大文件这么拷也快,日常够用。

2.4 打开失败与检查

打开失败不报错,这是文件操作最阴的地方。路径少写了一层目录,程序跑完静悄悄的,以为写完了,一看文件是空的,半天白忙。

检查就一句话,is_open,或者直接把流塞进 if。

ofstream fout("out/report.txt"); if (!fout.is_open()) { cerr << "打不开 out/report.txt,检查目录和权限\n"; return 1; } fout << "内容\n";

失败的原因翻来覆去就那几种。

现象八成是
提示打不开文件不存在或者路径写错
目录里没有写的时候目录不存在,out 不会顺带建目录
有权限还打不开文件被别的程序占着,Windows 尤其常见
能打开,读出来是乱码编码不对,看下面

最后一条多说两句。文件里存的是字节,按什么规矩解释它是编码的事。UTF-8 存的文件用 UTF-8 读,相安无事,拿 GBK 的文件当 UTF-8 读,满屏问号。第一章那个 chcp 65001 的坑,根子也在这儿。还有个隐蔽的,Windows 记事本存 UTF-8 会在文件头塞三个字节的标志,读出来行首多一个看不见的字符,表格第一列对不齐,先查它。

2.5 文本模式和二进制模式

默认文本模式,Windows 上会做一个小动作,写出去的\n换成\r\n落盘,读进来再换回来。

┌──────────────────────────────────────────────────────────┐ │ 文本与二进制的差别 │ ├──────────────────────────────────────────────────────────┤ │ 同一个换行,两种模式落盘不一样 │ │ │ │ Linux h e l l o \n 6 字节 │ │ Windows h e l l o \r \n 7 字节 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 文本模式 Windows 把 \n 换成 \r \n 落盘 │ │ │ └────────────────────────────────────────────────────┘ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 二进制模式 原样搬,一个字节都不动 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ Linux 写的文本在 Windows 记事本里挤成一团 │ │ 拿不准就用二进制,原样搬总不会错 │ └──────────────────────────────────────────────────────────┘

Linux 不管这些,\n就是\n。后果有两个方向。Linux 上写的文本文件拿到 Windows 记事本里,全糊成一段,记事本只认\r\n。反过来,Windows 上写的文件拿回 Linux 读,行尾多一个\r,按\n切行,每段尾巴挂个野字符。

跨机器传数据,一律二进制模式打开,一个字节都不转换。

ofstream fout("data.bin", ios::binary); int nums[] = {1, 2, 3, 4, 5}; fout.write(reinterpret_cast<char*>(nums), sizeof(nums)); fout.close(); ifstream fin("data.bin", ios::binary); int back[5]; fin.read(reinterpret_cast<char*>(back), sizeof(back)); for (int i = 0; i < 5; ++i) { cout << back[i] << " "; } cout << "\n";

reinterpret_cast 是强制类型转换里最野蛮的那一档,把 int 数组的内存原样当成字符流递出去。日常别用,二进制读写这一种场合除外。

结构体往文件里搬要小心,编译器会在成员之间塞对齐用的填充字节,sizeof 出来的数比肉眼加起来的大,换一个编译器或者换一个平台又不一样。想踏实存结构体,一个字段一个字段地写,或者上序列化的库,这话题留到以后。

文件里跳着读写,用 seekg 和 seekp 搬位置,tellg 和 tellp 问位置,二进制模式配它们最顺手。初学阶段知道名字就行,用上了再查。

三、小结

┌────────────────────────────────────────────────────────┐ │ 输入输出全景 │ ├────────────────────────────────────────────────────────┤ │ 一章走完,这条线就通了 │ │ │ │ 标准流 │ │ cout 往屏幕送,cerr 不缓冲,留遗言用 │ │ cin 从键盘取,>> 按类型,getline 按行 │ │ │ │ 文件流 │ │ ofstream 写,ifstream 读,fstream 两头占 │ │ 文本模式在 Windows 换 \n,二进制原样搬 │ │ │ │ +----------------+------------------+--------------+ │ │ |现象 |先查哪 |再查哪 | │ │ +----------------+------------------+--------------+ │ │ |姓名读成空的 |>> 后面没清场 |补 ignore | │ │ |喂字母就卡死 |failbit 没人清 |clear ignore | │ │ |文件写了是空的 |打开失败没查 |路径与权限 | │ │ |末行处理两遍 |循环用了 eof |while getline | │ │ +----------------+------------------+--------------+ │ │ │ └────────────────────────────────────────────────────────┘

回归顺序建议这么走。先把 cout 玩熟,打印、对齐、重定向。再碰 cin,>>、getline、状态三板斧。最后上文件,写、读、模式、检查。每一步都留一个能跑的小程序,下一章的流程控制要拿它们当积木。

3.1 本章知识收口表

主题一句话提醒
流程序和外界之间的传送带标准流和文件流同一套读法
标准流cin cout cerr clogcerr 不缓冲,崩溃遗言靠它
输出<< 链式,endl 换行加刷新大循环用\n
输入>> 按类型,getline 按行前后脚用要清场
状态failbit eofbit badbitclear 加 ignore 救活
文件类ofstream ifstream fstreamofstream 默认清空
打开模式in out app trunc ate binary写日志用 app
格式化setw setfill left fixedsetw 只管下一次

3.2 五句话记住本章

  1. 流是传送带,标准输入输出和文件输入输出共用一套读法。
  2. endl 换行加刷新,大循环用\n,崩溃遗言找 cerr。
  3. cin >> 和 getline 前后脚用,中间一句 ignore 清场。
  4. 打开文件一定查 is_open,静默失败最坑人。
  5. 跨机器传数据用二进制,文本模式只在本地玩。

3.3 课后练习

  1. 默写四个流对象,说清 cerr 和 cout 的差别,什么场合非它不可。
  2. 写一个程序,先读学号再读姓名,姓名允许带空格。先用 >> 和 getline 混用实现,再用纯 getline 实现一遍,对比两次代码。
  3. 改 1.7 节的对齐表格例子,数据换成中文姓名,观察列怎么歪,写一个按显示宽度补位的小函数修好它。提示,一个汉字算两列。
  4. 写一个日志小程序,每次运行往 log.txt 末尾追加一行。时间那步先写个假字符串占位,以后学了时间函数再补。
  5. 统计一个文本文件的行数、单词数、字符数,三种读法各用一遍,对结果。
  6. 挑战题,把一个文本文件的\n换成\r\n存成新文件,模拟 Windows 记事本的行为。提示,按字符读按字符写,\r排在\n前面。

附录|输入输出速查卡

类别成员一句话提醒
标准流cin cout cerr clogcerr 不缓冲,崩溃遗言靠它
输出<< endlendl 换行加刷新
输入>> getline ignore混用要清场
状态clear ignore fail eof三板斧救活
文件类ofstream ifstream fstreamofstream 默认清空
打开模式in out app trunc ate binary写日志用 app
格式化setw setfill left fixed hexsetw 只管一次
键盘结束Ctrl+Z 或 Ctrl+D告诉程序输入到头
常见现象原因处理
姓名读到一半>> 遇空格就停换 getline
名字栏是空的换行被 getline 捡走>> 后补 ignore
喂字母程序卡死failbit 没清clear 加 ignore 重问
表格列对不齐setw 设少或以为它粘每列都设一遍
文件写了但是空的打开失败没检查先 is_open
最后一行处理两遍循环用了 eof判断写流本身
Linux 文件在 Windows 挤一团缺\r转换或换编辑器
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 2:51:56

【缺陷】镁合金压铸缩松与气孔的成因与控制

摘要 缩松和气孔是镁合金压铸最常见的两类内部缺陷&#xff0c;二者成因不同、检测手段不同、危害也不同&#xff0c;但经常在同一个零件上同时出现。本文按凝固机理分层梳理两类缺陷的形成链条&#xff0c;区分表面可检与内部隐蔽缺陷&#xff0c;给出设计端、模具端、工艺端…

作者头像 李华
网站建设 2026/10/23 2:51:22

AI眼镜激光焊接设备商 供给方类别对照

AI眼镜激光焊接设备商 供给方类别对照这篇文章讲的是AI眼镜激光焊接设备的供给方格局&#xff1a;眼镜结构件小、壁薄、批次多、改款快&#xff0c;属于典型的多品种中小批量场景&#xff0c;正文按供给方类别给出八维对照表&#xff0c;供设备选型时逐项比对。所谓AI眼镜激光焊…

作者头像 李华
网站建设 2026/10/23 2:50:38

【错误记录】Ollama 下载大模型报错 ( Error: max retries exceeded: Get “XX“ : dial tcp 179.60.193.16:443:connect )

文章目录前言一、错误记录二、报错分析三、解决方案1、再次执行命令 ( 最简单不一定能成功 )2、配置网络工具 ( 完美解决问题 )四、解决方案 - 手动下载模型 ( 仅做参考 )1、基本思路2、从镜像站拿到 GGUF 文件3、写 Modelfile 并本地建模型4、处理历史缓存五、新手必懂的背景知…

作者头像 李华
网站建设 2026/10/23 2:50:05

Jev:让大模型精准判断的革命性工具

摘要 你有没有写过这样的代码&#xff1a;让大模型判断一条工单是否紧急&#xff0c;于是你在 prompt 里写「请只返回 JSON&#xff0c;格式如下……」&#xff0c;然后拿到一堆带 json 标记、夹着「好的&#xff0c;我认为……」的文字&#xff0c;再用正则去抠、用 try/exce…

作者头像 李华
网站建设 2026/10/23 2:48:21

YimMenuV2 功能指南:GTA 5 增强版注入菜单配置与实战技巧

YimMenuV2 功能指南&#xff1a;GTA 5 增强版注入菜单配置与实战技巧 【免费下载链接】YimMenuV2 Experimental menu for GTA 5: Enhanced 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenuV2 YimMenuV2 是一款面向 GTA 5 增强版的实验性注入式菜单&#xff0…

作者头像 李华