C++ practical course · lesson 08

C++ 命令行输入输出与参数检查

程序不只是完成计算,还要能听懂用户输入、拒绝错误数据并给出清楚提示。本课从最简单的问答开始,逐步完成一个可靠的命令行工具。

Easy explanation

把命令行程序想成一个耐心的服务窗口。

在服务窗口里,工作人员不会只说一句“输入错误”就离开。他会告诉你需要填写什么、检查内容是否完整,并在错误时让你重新填写。命令行程序也应该这样:先提示,再读取,然后验证,最后才处理。只要少了其中一步,用户就容易不知道程序在等待什么,或者输入一个字母后整个程序再也读不到数字。

cin 适合读取用空格分开的单个数据,getline 适合读取可能包含空格的一整行文字。它们没有谁永远更好,关键是先确定输入的形状。读取年龄可以用 cin,读取“今天完成数学作业”应使用 getline。遇到错误输入时,还要清除输入流的错误状态并丢弃残留字符,否则下一次读取会立刻再次失败。

目标 1正确使用 cin、cout 和 getline
目标 2识别并修复输入流失败状态
目标 3设计可退出、可重复运行的菜单
目标 4读取 argc 和 argv 命令行参数
C++ 命令行输入输出与参数检查通俗学习插图
输入、验证、处理和输出是每个命令行程序都能复用的四步循环。

Core concepts

先把四个核心知识点说清楚。

01

提示与输出

cout << "请输入年龄:";

提示要写在读取之前,并说明单位、范围或允许的命令。清楚的输出是程序接口的一部分,不是装饰。

02

读取单个值

cin >> age;

运算符会跳过开头空白并读取一个匹配类型的值。若用户输入字母给整数,输入流会进入失败状态。

03

读取整行文字

getline(cin, name);

getline 一直读取到换行符,因此能保留句子中的空格。cin 之后紧接 getline 时,要先处理遗留换行。

04

命令行参数

int main(int argc, char* argv[])

argc 表示参数数量,argv 保存每个参数文字。它适合让程序直接接收文件名、模式或初始值。

cout << fixed << setprecision(2) << price;

金额通常固定显示两位小数,让输出更像真实工具。

if (!(cin >> age)) { ... }

直接检查读取是否成功,不要在失败后继续使用未更新的变量。

cin.ignore(numeric_limits<streamsize>::max(), "\n"[0]);

丢弃当前行剩余内容,再进行下一次 getline。

string command; getline(cin, command);

整行读取适合 add math homework 这类带空格的命令。

Complete examples

两个例子,把知识变成能运行的程序。

Example 1

例子一:不会被字母弄坏的年龄读取器

普通写法只读取一次,用户输错后程序就结束。更友好的做法是把读取放进循环:类型不对时修复输入流,范围不对时解释规则,只有合法值才离开循环。

这里把年龄限制在 1 到 120。这个范围检查不是 C++ 强制的,而是程序自己的业务规则。类型检查和业务检查要分开思考。

循环读取并检查范围
#include <iostream>
#include <limits>
using namespace std;

int main()
{
    int age;
    while (true)
    {
        cout << "请输入年龄(1-120):";
        if (cin >> age && age >= 1 && age <= 120)
            break;

        cout << "输入无效,请重新输入。\n";
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    cout << "记录成功,年龄:" << age << endl;
}
请输入年龄(1-120):abc输入无效,请重新输入。请输入年龄(1-120):14记录成功,年龄:14

Example 2

例子二:带启动参数的问候工具

命令行参数让用户在启动程序时就提供信息。例如 greet Mia 3 表示向 Mia 问候三次。argv 中所有内容一开始都是字符串,数字参数需要转换并检查。

argc 至少为 1,因为 argv[0] 通常是程序名。访问 argv[1] 之前必须确认参数数量,否则会读取不存在的位置。

读取 argv 中的名字和次数
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        cout << "用法:greet 名字 次数\n";
        return 1;
    }

    string name = argv[1];
    int times = stoi(argv[2]);
    if (times < 1 || times > 10)
    {
        cout << "次数必须在 1 到 10 之间\n";
        return 1;
    }

    for (int i = 0; i < times; ++i)
        cout << "你好," << name << "!\n";
}
命令:greet Mia 3你好,Mia!你好,Mia!你好,Mia!

Algorithm thinking

先设计输入协议,再写计算代码。

很多命令行错误并不出在计算公式,而是输入规则没有想清楚。写代码前先列出:用户要输入几个值、每个值是什么类型、允许范围是多少、怎样表示退出、错误后是重试还是结束。规则清楚后,代码结构自然会变成提示、读取、验证、处理和输出。

验证要靠近输入发生的位置。不要先把错误数据传过五个函数,最后才发现结果奇怪。对于菜单程序,可以让每一轮循环只处理一个命令,处理结束后回到菜单;退出命令则改变循环条件。这样新增功能时不会破坏原有流程。

  1. 1
    描述输入

    写出类型、范围、是否允许空格以及退出方式。

  2. 2
    读取并判断

    同时检查输入流状态和业务范围,失败时给出具体原因。

  3. 3
    只处理合法数据

    验证通过后再计算,避免错误值进入程序核心。

  4. 4
    准备重试路线

    清理错误状态、丢弃残留内容,并回到清楚的提示位置。

Common mistakes

这些错误很常见,学会自己排查。

1

cin 后 getline 得到空行

前一次数字读取留下换行符,getline 立刻把它读走。先 ignore 当前行剩余内容。

2

失败后无限循环

只重复 cin 却没有 clear 和 ignore,输入流一直保持失败状态。

3

直接访问 argv[2]

没有检查 argc 就访问参数,用户少传参数时可能越界。

4

提示过于模糊

只输出“错误”无法帮助用户修正,应说明需要数字、允许范围和示例。

本课通用调试法

先准备一个最小输入,只保留能够重现问题的几行数据;再在关键步骤输出变量值,确认程序究竟在哪一步偏离预期。编译错误从第一条开始处理,运行错误则比较“实际结果”和“期望结果”。修复后别只重跑原来的例子,还要增加空输入、边界值和错误输入,防止问题换一个形式再次出现。

Homework

第 8 课课后作业:从模仿到独立完成。

建议按顺序完成。前四题帮助巩固语法和基本操作,第五到第七题要求把多个知识点组合起来,第八题是小项目。每道题都要先写输入、处理、输出三行计划,再开始敲代码;程序运行后至少测试正常情况、边界情况和错误情况。

1

安全整数

编写 readInt 函数,持续读取指定范围内的整数。分别测试字母、小数、范围外数字和正确数字。

2

姓名与城市

用 getline 读取包含空格的姓名和城市,输出完整自我介绍,不能丢失中间空格。

3

温度转换器

让用户选择摄氏转华氏或华氏转摄氏,拒绝未知模式,并把结果显示到两位小数。

4

重复菜单

制作包含查看余额、存入、支出和退出的菜单。每次操作结束后重新显示选项。

5

密码尝试

允许用户最多输入三次密码,每次失败显示剩余次数,成功或次数用完后结束。

6

启动参数计算器

支持 calc 12 + 5 形式的参数,检查参数数量、运算符以及除数是否为零。

7

单位换算中心

把长度、重量和温度换算放进一个程序,每种模式都至少包含两个方向。

8

命令行问卷项目

完成五个问题的问卷,验证年龄和评分,允许名字含空格,最后输出整齐的汇总报告。

本课验收标准:程序面对错误类型和范围外数据不会崩溃或失去响应;所有提示都说明用户下一步该做什么;至少有一次使用 getline,并能解释 cin 与 getline 的区别。

提交内容应包括源代码、三组测试输入与输出、一个曾经出现的错误及修复方法。最后请用自己的话解释本课最重要的概念;如果只能照着代码念,还需要再独立重写一次核心例子。

Lesson 08 summary

可靠的命令行程序,会把错误输入当成正常情况处理。

cin / coutgetlinecin.clear()argc / argv输入验证

下一课会在可靠输入的基础上组织更复杂的选择规则。输入负责把信息带进程序,条件判断则决定程序接下来走哪条路。