news 2026/10/14 23:55:24

C++编程实战:模拟支票输出与中文金额转换详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++编程实战:模拟支票输出与中文金额转换详解

1. 项目背景与需求拆解

1.1 题目到底在说什么

如果你正在自学C++,大概率会在第一章遇到一道让人摸不着头脑的习题:模拟支票输出。我第一次看到这个题时还在纳闷,支票不是银行的事吗,跟我一个刚开始写C++的人有什么关系?后来把题目读完才明白,这其实是一道非常典型的综合应用题——既要处理日期、姓名、金额这三种完全不同的输入,又要按固定格式输出,还要处理中文大写金额这种规则麻烦的东西。小题目里埋着一堆基础知识点,练完它,C++里跟输入输出、字符串处理、函数封装相关的功夫算是扎实了一截。

题目本身不难理解:程序要求用户输入日期、姓名和支票的数量,这里说的“数量”其实就是“金额”,英文里 amount 既可以翻译成数量,也可以翻译成金额。然后程序需要在控制台模拟出一张支票的样子,把日期、收款人、金额小写、金额大写这些关键信息按位置放好。很多教材的原始题目描述就到这里为止,并没有把“以下信息”具体列全,所以做题时要自己补全:一张支票至少要包含出票日期、收款人、金额小写、金额大写,再加一个用途和模拟银行信息,才像那么回事。

初学者容易犯的毛病是,一看到“模拟输出”就觉得只要用一堆 cout 拼字符串就行。但实际上,日期怎么格式化、姓名怎么读完整、金额怎么从 123.45 变成“壹佰贰拾叁元肆角伍分”,每一个环节都是独立的逻辑分支。如果一开始不把需求和步骤理清楚,写出来的代码往往是只有自己能看懂的“面条代码”。

1.2 一个支票输出程序背后有哪些考点

别小看这道第一章的题,它至少踩中了五个基础知识点。第一是输入流的处理,cin 读取不同类型数据时的行为不一样,尤其是字符串读取,cin >> 遇到空格会停,getline 才会把整行读进来,这中间还有一个容易被忽略的换行符残留问题。第二是格式化输出,控制台输出支票需要对齐,所以要知道 setw、setfill、fixed、setprecision 这些头文件里的工具。第三是字符串拼接,中文大写金额是由数字和单位拼接出来的,拼错了顺序,整个金额就读不通。第四是函数封装思维,虽然第一章可能还没正式讲函数,但这道题天然适合拆成“输入函数”“金额转换函数”“输出函数”,是一颗很好的面向过程编程的种子。第五是边界条件处理,负数、零、小数部分为零、日期非法,这些问题看起来小,实际运行时会直接决定程序是“能用”还是“只能跑”。

把这些考点拆开看,就会发现这道题一点都不“水”。它比你做十道“打印九九乘法表”更能锻炼按需求拆解问题的能力。很多同学在学到指针、类之前,觉得C++就是语法堆砌,其实早期最应该练的就是这种“把现实场景翻译成代码”的敏感度。

1.3 适合什么样的人来做这道题

如果你刚开始学C++,刚学会变量、输入输出、基本运算符,这道题完全可以做。不需要等学到循环和函数之后再回头,可以先在 main 里按顺序写,程序能跑起来再考虑拆函数。给它定位成“第一章结束后的自测题”比较合适。

如果你已经学到函数和字符串处理,这道题就是一次很好的综合练习。尤其是金额转大写这部分,你会用到字符串拼接、数组、循环、条件判断,还会被迫思考浮点数精度问题。这些问题在许多入门项目里接触不到,但实际做起来收获非常大。

如果你是带学生、带助教的人,也可以用这道题当课堂案例。它比纯语法练习更有画面感,学生容易理解需求,做完之后也能明显感觉到代码能力的提升。接下来我按自己当时做这道题的过程,把思路、代码、踩坑点都放出来,你可以直接照着走一遍。

2. 程序设计思路与模块划分

2.1 先画一张支票草图,再反推程序要做什么

拿到这类模拟类题目,我习惯先不写代码,而是先在纸上画一张最简单的支票。支票上从左往右、从上往下大致有这些信息:出票日期、收款人、金额小写、金额大写、付款行名称、用途、出票人账号。题目明确要输入的只有日期、姓名和金额,那程序输出的重点就是让这三样信息在固定位置上清晰可见,其余部分可以用“模拟银行”“模拟账号”这样的占位文字填充,让它看起来像一张票据。

把草图画出来之后,整个程序的输出格式就定了。我当时设计的是这样一个控制台界面:

-------------------------------------------------- 模拟转账支票(仅供学习演示) 出票日期:2025年01月15日 收款人:张三 人民币(大写):壹佰贰拾叁元肆角伍分 小写金额:¥123.45 用途:货款 付款行名称:某模拟银行 --------------------------------------------------

有了这个目标,程序要做什么就清楚了:接收键盘输入,把日期拆成年月日;把姓名完整读出来;把金额变成小写字符串和中文大写字符串;最后按固定格式输出。到这里,需求从“写一个支票程序”变成了“完成四项具体任务”,后面的代码就是围绕这几个任务展开。

2.2 把程序拆成四个小模块

按照上面的草图,我习惯把程序拆成四个部分。第一部分是输入模块,负责读取并用简单规则校验日期、姓名和金额。第二部分是日期格式化模块,把“2025 1 15”这样的输入变成“2025年01月15日”。第三部分是金额转大写模块,这是全题的核心难点,负责把 123.45 这种数字变成中文大写。第四部分是支票排版输出模块,把前面处理好的数据按固定顺序打印出来。

模块划分看起来是“多此一举”,但对学习和后期调试特别关键。比如金额转大写写错了,只需要检查那一个函数,不用在 main 的一百行代码里翻来翻去找。第一章阶段虽然还不要求写多优雅的代码,但从一开始养成“一个函数只干一件事”的习惯,后面学面向对象、学分离接口实现时都会轻松很多。

这种拆法还有一个好处:每个模块都可以单独测试。你可以在 main 里临时只调用金额转换函数,传几个边界值进去,看输出对不对。等每个模块都测过了,再合在一起做整体测试,定位问题的范围就大大缩小。

2.3 为什么把“金额转大写”单独拎出来

原因很简单,它是整道题里最容易写乱的部分。中文大写的读法规则比英文复杂得多:壹贰叁肆伍陆柒捌玖这套数字还好办,麻烦在于“零”什么时候读、什么时候不读。一千两百三十四写成“壹仟贰佰叁拾肆”,但一千零一就要写成“壹仟零壹”,而一千二百整又应该写“壹仟贰佰”,不能把末尾零读出来。到了万元、亿元层面,还要处理“万”“亿”这两个节位单位,以及跨节时的补零问题。

如果把这些规则全部塞进主流程里,main 函数会变得又长又乱,一旦出错你很难知道是输入的问题还是转换的问题。所以我在写代码时,把金额转大写的逻辑集中成一个独立函数,函数的输入是一个数字,输出是一个字符串。这样我在写主程序时,只需要关心怎么调用它,不需要关心它内部是怎么拼中文的。这个思路对于区域比较广的问题非常通用,本质上就是把“做什么”和“怎么做”分开。

还有人会问,第一章还没学函数,怎么办?其实即使不写独立函数,也必须逼着自己先把“金额转中文大写的规则”在纸上列清楚,再开始写代码。把复杂逻辑在头脑里圈定一个边界,这是比语法更重要的编程能力。

3. 核心实现:三类输入的读取与处理

3.1 日期输入:用空格分隔的年份月份日子最省事

日期输入有很多方式,有人要求用户输入“2025-01-15”,有人要求输入“2025/01/15”,还有人要求输入“20250115”。第一种最简单的做法,是让用户直接输入三个数字,命令提示写清楚格式就行:

int year, month, day; cout << "请输入日期(年 月 日,用空格分隔):"; cin >> year >> month >> day;

用这种写法,用户输入“2025 1 15”,三个变量就分别被赋上值了。cin 遇到空格会自动把数据切分开,这正好符合我们的需求。如果你的题目要求必须支持斜杠或短横线,那就要把日期当成字符串读进来,再按分隔符去拆分,第一章阶段可以不用做到那么完善。

日期输入有一个值得注意的坑:cin 把数字读走后,换行符还留在输入缓冲区里。如果紧接着用 getline 读姓名,会直接把残留的换行符当成一个空行读走,姓名还没来得及输入,程序就已经继续往下跑了。所以我通常会在日期读取之后写一句 cin.ignore();,把缓冲区里的换行符清掉。这个小细节不解决,后面姓名读取一定会出问题。

3.2 姓名输入:cin >> 和 getline 之间差一个换行符

姓名是典型的字符串输入。最简单的写法是:

string name; cout << "请输入收款人姓名:"; getline(cin, name);

为什么用 getline 而不是 cin >> name?因为姓名可能包含空格。输入“欧阳 明”时,cin >> name 只会读到“欧阳”,后面的“明”会被丢弃,程序看起来就像只录入了半个名字。支票上的收款人姓名当然要完整,所以这里必须用 getline 读取一整行。

但 getline 本身也有脾气。如果在这行之前用过 cin 读取数字,那么数字后面的换行符还留在缓冲区里,getline 读到它就直接结束了。所以我常说,cin.ignore() 和 getline 往往是成对出现的。正确顺序是先读年月日,然后 cin.ignore() 清掉换行,再 getline 读姓名。如果顺序错了,程序会表现出一种很诡异的现象:姓名永远为空,或者还没输入就跳到下一步。这个错我在很多同学代码里都见过。

同样地,如果后面又要读取数字金额,那 getline 不会留下换行符问题,因为 getline 会把换行符读走并丢弃。真正要注意的是“数字之后读字符串”这个方向,其它组合一般没有这个坑。

3.3 金额输入:double 不是万能的,但入门阶段够用

金额显然要支持小数,而且一般精确到分。很多人第一反应是用 double 存:

double amount; cout << "请输入支票金额:"; cin >> amount;

这样写确实简单,运行起来也像那么回事。但如果你在程序里直接用 amount 做浮点数运算,比如 amount * 100 再取整,会遇到经典的 0.1 + 0.2 不等于 0.3 问题。比如用户输入 0.1,计算机内部并不是精确的 0.1,而是一个很接近但不完全相等的二进制小数。转成角分时,可能得到 10 分,也可能得到 9.999... 分。所以真正严谨的做法,是把金额按“分”来读,或者把 double 乘以 100 后四舍五入成整数再处理。

在第一章阶段,我建议先保留 double 输入,但在代码里加上一行四舍五入处理:

long long cents = (long long)(amount * 100 + 0.5);

这样 0.1 元会被变成 10 分,误差被收在可控范围。你还可以在后面加上一个判断,如果金额超过某个范围或者为负数,就提示用户重新输入。虽然一个练习程序不完全处理所有异常也能跑,但早早养成“面对金额这种类型时警惕浮点误差”的意识,后面做支付相关项目时会少踩很多坑。

金额的数据范围也要设置。一张模拟支票没必要支持特别离谱的大数,比如超过亿就把金额转大写函数搞复杂。我下面的代码把金额限制在一亿以内,超过部分直接提示不支持,这样做是为了把精力集中在字符串拼接和规则处理上,而不是为了兼容所有超大数字。

4. 支票最核心的部分:人民币大写金额转换

4.1 先把“数字”和“单位”变成两张表

中文大写金额的基础是两组映射:数字映射和单位映射。数字方面,0 到 9 分别对应零壹贰叁肆伍陆柒捌玖。单位方面,十、百、千是每个四位分组内部的单位,万、亿是四位分组之间的节位单位。我写代码时习惯先把它们变成数组,这样后面按索引取用比较方便:

const string digitCn = "零壹贰叁肆伍陆柒捌玖"; const string unitCn = "拾佰仟"; const string sectionCn[] = {"", "万", "亿"};

这里有一个小设计值得提一下:我没有给“个”准备单位,因为个数位本身就是数字,不需要额外单位。单位数组 unitCn 的下标 0、1、2 分别对应十、百、千。如果你在写一个四位小组内的数,从右往左数第几位,就用对应的单位补在数字后面。把表先准备好,后面的拼接逻辑就会清楚很多。

4.2 整数部分按四位分组处理一个比一个稳

把整数部分转成中文,最简单的思路不是一位一位扫,而是把数字从右往左每四位分成一组,再给每组补上“万”“亿”这样的节位单位。比如 12345678,分组就是 1234 和 5678,读的时候先读高位的 1234 再读低位的 5678,中间加一个“万”,得到“壹仟贰佰叁拾肆万伍仟陆佰柒拾捌”。

组内转换的规则相对固定:从高位到低位分别判断千位、百位、十位、个位。如果某一位是 0,就要记住“这里有个零”,等到后面出现非零数字时,在该数字前面补一个“零”。但连续的零只读一个零,末尾的零不读,所以“1001”是“壹仟零壹”,“1200”是“壹仟贰佰”,“1010”是“壹仟零壹拾”。这些规则一开始听上去绕,其实只要抓住“零只在非零数字前出现而且只出现一次”这个原则,就不会乱。

跨组时还有一个容易漏掉的零。比如 10001,分组后是“1万”和“1”,如果直接拼,会得到“壹万壹”,明显错了,正确是“壹万零壹”。区别在于万组和个组之间的千位、百位、十位都是零,也就是说低位组前面有“空位”,这些空位需要用一个“零”来占位。所以在程序里判断非零组是否要补零,不能光看当前组本身,还要看它前面是否有连续的零组,以及当前组是否小于一千。这个细节是金额转大写最容易错的地方,多测几个数字就能发现。

4.3 小数部分:角和分的处理不能含糊

人民币金额最多精确到分,小数部分只关心角和分。做法是把金额乘以 100 转成“分”,然后分别取出角位和分位。比如 123.45 元,换算成分是 12345 分,角位就是 4,分位就是 5,对应“肆角伍分”。如果分位是 0,那只说“肆角”;如果角位是 0 而分位不是 0,要写成“零伍分”,不能写成“伍分”。比如 123.05 元,标准写法是“壹佰贰拾叁元零伍分”。

如果角和分都为 0,也就是整数金额,那不用写角和分,而是直接在“元”后面加一个“整”字。“整”在这里表示金额到此结束,是财务书写习惯,也是对格式的一种补全。我一开始忘了加这个“整”,输出“壹佰贰拾叁元”,看起来不像完整的大写金额。后来对照银行写法才补上。

还有一个细节是“元”前面的连接。如果整数部分是 0,比如 0.45 元,大写金额应该读作“零元肆角伍分”,而不是直接“肆角伍分”。因为支票上金额大写必须完整,前面补一个“零元”让格式统一。这个小边界看一眼容易忽略,但打印出来就会发现少写“零元”很别扭。

4.4 边界情况:这些数字最容易出错

我自己做这个程序时,整理了一张金额转换测试表,每一个都是专门用来刁难逻辑的:

输入金额期望输出容易错成什么样
0.00零元整直接输出“零”或空白
10.00壹拾元整多写“壹拾零元整”
1001.00壹仟零壹元整把中间零漏掉
1010.00壹仟零壹拾元整读成“壹仟零壹拾零元”
10001.00壹万零壹元整漏掉跨组零,读成“壹万壹元整”
100000001.00壹亿零壹元整少了亿和个位之间的零
123.05壹佰贰拾叁元零伍分写成“壹佰贰拾叁元伍分”
123.40壹佰贰拾叁元肆角多写“零分”或者漏“角”
0.05零元零伍分读成“零元伍分”

这些数字不是随机选的,它们分别对应组内连续零、组间跨零、小数部分缺位、整数部分为零等各种分支。如果你写的函数能把这九个测试用例全部通过,那这个模块基本就是可靠的。我在调试时把这张表直接写成了注释放在代码旁边,每改动一次就去跑一遍,比临时想数字去测靠谱得多。

5. 完整程序与运行效果

5.1 可直接运行的C++代码

下面是我整理出来的一份可运行版本。它没有用到任何第三方库,只要支持C++11及以上标准的编译器就能编译过。main 函数保持简短,核心逻辑拆成了两个函数:integerToChinese 处理整数部分,amountToChinese 处理完整金额。日期校验和金额范围检查也加上了,虽然写成的是简单 if,但比什么都不管要稳得多。

#include <iostream> #include <string> #include <iomanip> #include <cmath> using namespace std; const string digitCn = "零壹贰叁肆伍陆柒捌玖"; const string unitCn = "拾佰仟"; const string sectionCn[] = {"", "万", "亿"}; // 将一个0~9999的数字转换为中文读法 string groupToChinese(int n) { if (n == 0) { return "零"; } string result; bool needZero = false; int qian = n / 1000; int bai = n / 100 % 10; int shi = n / 10 % 10; int ge = n % 10; if (qian != 0) { result += digitCn[qian]; result += "仟"; needZero = false; } else if (bai != 0 || shi != 0 || ge != 0) { needZero = true; } if (bai != 0) { if (needZero) { result += "零"; needZero = false; } result += digitCn[bai]; result += "佰"; } else if (shi != 0 || ge != 0) { needZero = true; } if (shi != 0) { if (needZero) { result += "零"; needZero = false; } result += digitCn[shi]; result += "拾"; } else if (ge != 0) { needZero = true; } if (ge != 0) { if (needZero) { result += "零"; needZero = false; } result += digitCn[ge]; } return result; } // 将整数部分转换为中文大写 string integerToChinese(unsigned long long n) { if (n == 0) { return "零"; } string s = to_string(n); int len = s.size(); string result; bool needZero = false; bool groupHasNonZero = false; for (int i = 0; i < len; ++i) { int digit = s[i] - '0'; int posInGroup = (len - 1 - i) % 4; int groupIndex = (len - 1 - i) / 4; if (digit == 0) { needZero = true; } else { if (needZero && !result.empty()) { result += "零"; needZero = false; } result += digitCn[digit]; if (posInGroup > 0) { result += unitCn[posInGroup - 1]; } groupHasNonZero = true; } if (posInGroup == 0) { if (groupHasNonZero && groupIndex < 3) { result += sectionCn[groupIndex]; } groupHasNonZero = false; needZero = false; } } return result; } // 将完整金额转换为中文大写 string amountToChinese(double amount) { if (amount < 0) { return "金额不能为负"; } if (amount >= 100000000.0) { return "超过本版本支持范围(亿以下)"; } long long cents = (long long)(amount * 100 + 0.5); unsigned long long intPart = cents / 100; int jiao = (cents / 10) % 10; int fen = cents % 10; string result = integerToChinese(intPart); result += "元"; if (jiao == 0 && fen == 0) { result += "整"; } else if (jiao == 0) { result += "零"; result += digitCn[fen]; result += "分"; } else if (fen == 0) { result += digitCn[jiao]; result += "角"; } else { result += digitCn[jiao]; result += "角"; result += digitCn[fen]; result += "分"; } return result; } int main() { int year, month, day; cout << "请输入日期(格式:年 月 日,用空格分隔):"; cin >> year >> month >> day; cin.ignore(); if (month < 1 || month > 12 || day < 1 || day > 31) { cout << "日期输入不合法,程序退出。" << endl; return 1; } string name; cout << "请输入收款人姓名:"; getline(cin, name); if (name.empty()) { cout << "姓名不能为空,程序退出。" << endl; return 1; } double amount; cout << "请输入支票金额:"; cin >> amount; if (amount < 0) { cout << "金额不能为负,程序退出。" << endl; return 1; } cout << "--------------------------------------------------" << endl; cout << " 模拟转账支票(仅供学习演示)" << endl; cout << "出票日期:" << year << "年" << setw(2) << setfill('0') << month << "月" << setw(2) << setfill('0') << day << "日" << endl; cout << "收款人:" << name << endl; cout << "人民币(大写):" << amountToChinese(amount) << endl; cout << "小写金额:¥" << fixed << setprecision(2) << amount << endl; cout << "用途:货款" << endl; cout << "付款行名称:某模拟银行" << endl; cout << "--------------------------------------------------" << endl; return 0; }

第一眼看上去代码有点长,但它没有用任何“高深”的语法。核心就是一个循环扫描每个数字、拼接字符串,另外再加几个简单的条件判断。你如果第一章还没学循环,可以先跳过 integerToChinese 的循环细节,直接从 main 开始理解整体流程,之后再回头攻读转换逻辑。

5.2 运行效果

假设用户依次输入以下内容:

2025 1 15 张三 123.45

程序的输出应该是:

-------------------------------------------------- 模拟转账支票(仅供学习演示) 出票日期:2025年01月15日 收款人:张三 人民币(大写):壹佰贰拾叁元肆角伍分 小写金额:¥123.45 用途:货款 付款行名称:某模拟银行 --------------------------------------------------

这里值得注意两个输出细节。一个是日期的月份和日使用了 setw(2) 和 setfill('0'),所以 1 月会被输出成 01 月,这样日期显示更规范。另一个是小写金额使用了 fixed << setprecision(2),强制保留两位小数,所以 123.4 会打印成 123.40,123 会打印成 123.00。这两个格式化工具是控制台模拟票据时的好帮手。

5.3 代码里几个容易被忽略的小细节

第一个细节是 setfill('0') 一旦设置,会影响后面所有整数输出,所以我在设置之后没有再改变回空格。如果后面还有其他对齐输出,记得要重新设置,否则可能出现意外的前导零。

第二个细节是 integerToChinese 里 groupHasNonZero 这个变量。它的作用是记录当前四位分组内是否出现过非零数字。如果一整组都是零,那就不应该在该组末尾加上“万”或者“亿”。例如 100000001,中间的一组全是零,程序不能输出“亿万”这种错误结果,groupHasNonZero 就是用来挡这个逻辑的。

第三个细节是加上范围判断。代码里限制了金额必须小于一亿元,其实是给 sectionCn 数组兜底。数组里只有“万”和“亿”两个节位单位,如果传入万亿级别的数,groupIndex 会超过数组下标,造成越界。明确范围限制后,函数行为就确定多了。如果你想让程序支持更大的金额,需要把 sectionCn 继续扩充到“兆”“京”等单位,同时把上限判断改掉。

6. 常见问题、调试技巧与后续扩展

6.1 常见问题速查表

我在跑这个程序时,把平时大家最容易遇到的情况整理成了一张速查表:

现象大概率原因处理方法
姓名还没输入,程序就跳过了用 cin 读数字后没有清掉换行符在 getline 之前加 cin.ignore()
姓名只能读到第一个字用了 cin >> name,遇到空格停止改成 getline(cin, name)
金额小写输出不对没有设置 fixed 和 setprecision输出前加 fixed << setprecision(2)
中文大写输出一堆乱码控制台编码和源文件编码不一致保证源文件保存为 UTF-8,或调整编译器/控制台编码
10001 转换成了壹万壹跨组补零逻辑没做专门测试 10001,并检查低位组是否小于1000
0.45 输出了“零元肆角伍分”之外的错误小数分支没处理好单独测试 jiao == 0 且 fen != 0 的分支
编译报 string 相关错误缺少头文件或命名空间确保 #include 并写了 using namespace std

这张表里最容易被忽视的是编码问题。如果你在 Windows 控制台运行,源文件保存成 UTF-8,有时候控制台默认用 GBK 显示,就会出现中文乱码。这不是代码逻辑错误,但也需要知道怎么调整。一般可以把源文件另存为 ANSI 或 GBK,或者在程序开头加一些控制台编码切换的代码。不同环境处理方式不一样,最好先看环境再决定。

6.2 调试思路:用一组“刁钻”的输入自测

这个程序最耐用的调试方法不是反复试正常输入,而是准备一组边界输入,一次跑完。我建议你准备几组数据:0.00、10.00、1001.00、10001.00、100000001.00、123.05、123.40、0.05。正常运行后,把每一组输入进程序,对照上一章整理好的期望输出表检查。

如果你发现某一条输出和预期不一样,先缩小范围。比如发现 10001 的转换有问题,那就单独在 main 里调用 integerToChinese(10001),把返回值打印出来,判断是整数部分拼接错,还是小数部分补零错。这种“拆开测”的习惯,比盯着整个 main 函数猜测高效得多。程序员大部分时间并不是在写新代码,而是在做这种二分定位式的排查。

另外,我自己调试时习惯把 amountToChinese 写成可以直接接收 double 的测试函数,而不一定非要从控制台输入。你可以在 main 里临时写几行:

cout << amountToChinese(0.00) << endl; cout << amountToChinese(10001.00) << endl;

这样跑一次就能看到多个用例的结果,不用每次重新输入。等测试通过后再把这些临时代码删掉,恢复成面向用户的输入提示。这个方法对任何用函数封装的功能都适用。

6.3 扩展方向:别只停留在控制台

这道题如果到此为止,已经是一个能完整运行的控制台小项目。但你完全可以把它再往前推几步,变成更有意思的东西。第一个扩展是把支票输出保存到文本文件。不需要引入额外库,用 fstream 就能做到。把原本输出到 cout 的内容,同时写进一个 txt 文件里,这样就有了“打印票据”的感觉。

第二个扩展是加入金额非法输入的重新提示逻辑。目前代码遇到非法输入会直接退出,这在考试里没问题,但真正实用时应该用 do-while 循环让用户重新输入,直到正确为止。这个扩展能让你熟练循环和输入校验。

第三个扩展是做一个带菜单的小系统,支持多张支票连续录入,最后统一打印所有记录。这一步自然就会用到数组或者 vector,虽然第一章还没讲,但你会对“为什么需要数组”有非常直观的理解。我当时就是在这道题之后,第一次觉得 C++ 的变量不是孤立存在的,而是可以组合在一起描述现实对象的。

我个人在实际操作中的体会是,模拟支票输出这类题,最好的学习方式不是抄一遍代码,而是先在自己机器上把它跑通,然后试着改一个功能。比如把“日期用斜杠分隔”改成“日期用中文年、月、日输入”,或者把用途从固定值改成输入项。每一个小改动都会逼你去理解原有代码的数据流。等你把某一处改成功之后,这道题才真正变成了你自己的作品。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 23:53:32

大模型推理提速300%:推测解码原理与生产落地指南

只要部署过大模型推理服务的人&#xff0c;一说起“慢”这个字&#xff0c;八成都有点条件反射。用户那边发来一句话&#xff0c;服务端吭哧半天才吐出第一个字&#xff0c;后面虽然流畅些&#xff0c;也跟老式打字机似的&#xff0c;一个token一个token地往外蹦。我在某数据业…

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

wxapkg拆包实战:wxappUnpacker还原小程序源码与避坑指南

简介&#xff1a;wxappUnpacker 是一款面向微信小程序开发者与安全研究人员的反编译工具&#xff0c;可将小程序二进制包还原为可读的 WXML、WXSS、JS 与 JSON 源码&#xff0c;支持主包与分包分别处理&#xff0c;便于分析业务逻辑、优化代码结构或开展安全审计。资源包共 780…

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

小程序反编译工具wxappUnpacker:从.wxapkg到可读目录的完整指南

简介&#xff1a;wxappUnpacker 是一款面向微信小程序开发者与安全研究人员的反编译工具&#xff0c;用于将小程序二进制包还原为可读源码&#xff0c;支持主包与分包处理&#xff0c;便于分析业务逻辑、优化代码及开展安全审计。资源包共 780 个文件&#xff0c;约 1.97MB&…

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

Go sync.Map源码解析:从并发安全到性能边界

从一次线上事故说起吧。当时我维护的一个服务&#xff0c;高峰期突然大量goroutine并发读写一个全局的map&#xff0c;用的还是最原始的map[string]int&#xff0c;结果不出意外地抛出了fatal error: concurrent map read and map write&#xff0c;整个进程直接崩溃。好在那次…

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

Socket原理与实战:从TCP连接到高并发网络编程

1. 什么是socket&#xff1a;从“打电话”说起的底层通信真相你有没有想过&#xff0c;当你在浏览器里输入一个网址&#xff0c;几秒钟后页面就完整加载出来&#xff0c;这背后到底发生了什么&#xff1f;不是魔法&#xff0c;也不是服务器“主动推”过来的——而是你的电脑和远…

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

CentOS 7.6 SSH端口修改与密码策略加固实战指南

1. 为什么改SSH端口不是“多此一举”&#xff0c;而是运维基本功在某高校实验室维护一批用于教学演示的CentOS 7.6服务器时&#xff0c;我接手的第一台机器上线不到48小时&#xff0c;/var/log/secure里就刷出了237条来自不同IP的Failed password for root记录——全是暴力扫描…

作者头像 李华