11 KiB
C++ 格式化输入与输出 讲义
一、 引言
问题引入:数字反转
【书本P21页 例2-7】我们来看一个问题:
输入一个三位浮点数,例如
123.4,要求把这个数字彻底翻转过来,变成4.321并输出。
乍一看,这个问题似乎很难下手。我们熟悉的 cin 只能整个地读取这个数字,cout 也只能整个地输出。我们如何能把——1、2、3、.、4——拆开,再按新的顺序重新组合呢?
二、 解法一:数学运算
在揭晓新工具之前,我们先用已有的知识尝试解决。
思路铺垫
对于 123.4,最碍事的就是那个小数点。如果我们能先把它变成整数 1234,问题就简化成了“整数拆分”。
核心工具:提取器与削减器
我们回顾一下拆分整数的两个工具:
-
个位的提取器 (
% 10)- 作用:获取一个整数的最右边一位。
- 原理:任何整数除以10的余数,正好就是它的个位数。
- 示例:
1234 % 10结果是4。
-
数字的削减器 (
/ 10)- 作用:砍掉一个整数的最右边一位。
- 原理:在C++中,
整数 / 整数的结果会直接舍弃小数部分。 - 示例:
1234 / 10结果是123。
步骤拆解
- 第一步(提取):使用 提取器 (
% 10) 获得当前数字的个位数。 - 第二步(削减):使用 削减器 (
/ 10) 砍掉个位数,得到一个更小的数,为下一次操作做准备。
具体案例
让我们来手动拆解整数 479。
分步演示:
-
初始状态: 我们有一个整数
n = 479。 -
第一轮操作 (处理
479):- 提取:
479 % 10-> 我们得到了数字9。 - 削减:
479 / 10->n现在变成了47。
- 我们成功地把
9从479中分离了出来,并且得到了一个更简单的问题:如何拆解47。
- 提取:
-
第二轮操作 (处理
47):- 提取:
47 % 10-> 我们得到了数字7。 - 削减:
47 / 10->n现在变成了4。
- 小结:我们又分离出了
7,问题变得更简单了:如何拆解4。
- 提取:
-
第三轮操作 (处理
4):- 提取:
4 % 10-> 我们得到了数字4。 - 削减:
4 / 10->n现在变成了0。
- 小结:我们分离出了最后的
4,n变成了0,说明拆解工作已全部完成!
- 提取:
而对于我们的题目:输入一个三位浮点数,例如 123.4,要求把这个数字彻底翻转过来,变成 4.321 并输出。
我们就也能通过整数拆分的办法来解决了。
- 预处理:
double num = 123.4; int n = num * 10;-> 得到整数1234。 - 逐位拆分:
int d = n % 10;// d = 4int c = (n / 10) % 10;// c = 3int b = (n / 100) % 10;// b = 2int a = n / 1000;// a = 1
- 重新组合输出:
cout << d << "." << c << b << a;
结论:通过整数拆分的方法可以解决本问题,且一定要掌握通过数学运算拆分整数的办法。
常见问题
- 问:对一个个位数(比如
8)使用这两个工具会怎样?- 答:完全符合规则,不会出问题!
- 提取器:
8 % 10的结果是8。(8除以10,商0余8,成功提取出了最后一位数字 8) - 削减器:
8 / 10的结果是0。(8除以10,整数商是0,成功削减了最后一位数字 8)
- 提取器:
- 答:完全符合规则,不会出问题!
- 问:如果数字里有
0呢?比如205?- 答:规则同样适用!
- 第一轮:
205 % 10->5;205 / 10->20。 - 第二轮:
20 % 10->0;20 / 10->2。 - 第三轮:
2 % 10->2;2 / 10->0。
- 第一轮:
- 答:规则同样适用!
要点回顾
- 个位的提取器 (
% 10):它的作用就是帮你看到并取走一个整数最右边的那一位。 - 数字的削减器 (
/ 10):它的作用就是砍掉一个整数最右边的那一位,让数字变小。 - 而且“提取”后必须“削减”,这样才能为处理下一位数字做准备。它们总是成对出现。
**三、 printf **
核心概念与语法
printf 的全称是 Print Formatted(格式化打印)。
它的作用是:先写好一段带有“空位”的模板句子,然后再把变量按顺序填入这些空位中。
语法格式:
printf("包含格式说明符(占位符)的字符串", 变量1, 变量2, ...);
printf 的使用方法
-
打印纯文本
printf("Hello, World!\n"); // \n 代表换行 -
打印单个变量
printf在于用格式说明符(以%开头的占位符)去指定“空位”的类型,也就是先挖个坑占个座,之后我来告诉你什么数据会放在这里你进行输出就可以了。int age = 30; // %d 是专门用来放整数的占位符 printf("我的年龄是 %d 岁。\n", age);逻辑解释:
"我的年龄是%d岁。\n"是输出的模板字符串。%d是一个占位符。printf会在输出时,自动按照顺序用后面age变量的值(30)去替换%d的位置。
-
混合打印多个变量
printf也可以极其方便地在一句话中同时输出多个、多种类型的变量,而不需要像cin或cout那样反复使用<<拼接。int age = 15; double height = 168.5; char rank = 'S'; // 依次使用 %d, %lf, %c 作为占位符 printf("我今年%d岁,身高是%lf厘米,综合评级:%c\n", age, height, rank);核心规则:
- 一一对应: 字符串里有 3 个坑(
%d,%lf,%c),后面就必须跟着 3 个变量(age,height,rank)。 - 按顺序入座:
printf会严格按照从左到右的顺序,把第一个变量填入第一个占位符,第二个变量填入第二个占位符,以此类推。 - 类型必须匹配: 第一个是整数类型
age,所以必须用%d;第二个是小数类型height,必须用%lf/%f;第三个是字符类型rank,必须用%c。
- 一一对应: 字符串里有 3 个坑(
常用格式说明符(书本P24页,重要!)
占位符的顺序必须与后面变量的顺序一一对应,且数据类型必须兼容!
| 占位符 | 对应数据类型 | 说明 |
|---|---|---|
%d |
int |
打印整数 |
%f |
float、double |
打印浮点数 (默认保留6位小数) |
%lf |
float、double |
输出时与 %f 相同;小数位数由精度指定 |
%c |
char |
打印单个字符 |
%.mf |
float/double |
技巧: 打印浮点数,并精确保留m位小数。例如 %.2f 就是保留两位。 |
cout 与 printf 写法对比
| 操作目标 | cout 写法 |
printf 写法 |
|---|---|---|
| 打印纯文本 | cout << "输出的内容"; |
printf("输出的内容"); |
| 打印单个变量 | cout << num1; |
printf("%d", num1); |
| 混合打印多个变量 | cout << num1 << "和" << num2; |
printf("%d和%d", num1, num2); |
**四、 scanf **
概念与语法
scanf 的全称是 Scan Formatted(格式化扫描/输入)。
它的逻辑和 printf 基本一致,只不过从输出数据 变成了 输入数据:它会根据你提供的格式字符串模板,去键盘的输入中抓取对应的数据。
语法格式:
scanf("格式控制字符串", &变量1, &变量2, ...);
要注意 scanf 必须加 &(取地址符)
原理:
cin很智能,你告诉它抽屉的名字(如age),它就能自己找到。scanf是一位老员工,你必须把这个抽屉在内存中的具体物理地址交给它,它才能把数据放进去。
那么在变量名前加上 &,就相当于提取了这个变量的地址,所以这个符号也被称为取地址符!
警告: 如果忘记写
&,程序在运行到输入阶段时会直接崩溃!
基础使用示例:
int age;
printf("请输入您的年龄:");
scanf("%d", &age); // 从键盘输入获取一个整数,存入 age 所在的内存地址
// 现在 age 中就储存了输入的数据
scanf 的使用技巧
-
一次性读取多个数据
int a; double b; scanf("%d%lf", &a, &b); // 从键盘输入中读取一个整数和一个double类型的数据用户输入时用空格、Tab或回车 (空白字符) 隔开即可,
scanf会自动跳过它们。 -
易错点:不要在格式字符串里乱加标点,除非题目格式明确要求了
- 错误写法:
scanf("%d,%d", &a, &b); - 后果:那么用户输入时必须严格按照格式输入:[一个整数 逗号 一个整数] 的格式,例如
5, 10。如果不带逗号输入[5 10]的话就会读取失败。 - 正确、安全的写法:
scanf("%d%d", &a, &b);保持格式字符串的干净,只保留占位符。
- 错误写法:
五、 实战演练
实战1:数字反转
解题思路:我们不把 123.4 看作数字,而是看作“3个字符 + 1个小数点 + 1个字符”。利用 scanf 的格式匹配能力,将它们分离到不同的char变量中!
#include <cstdio>
int main() {
char a, b, c, d;
// 输入格式为 %c%c%c.%c,匹配 [字符 字符 字符 小数点 字符] 的格式将4个字符分离出来
scanf("%c%c%c.%c", &a, &b, &c, &d);
// 按照 d.cba 的倒序格式输出
printf("%c.%c%c%c\n", d, c, b, a);
return 0;
}
用 scanf 和 printf问题就会变得非常简单!
实战2:再分肥宅水(书本P23页)
题目要求:t 毫升水均分给 n 名同学。输出每人获得多少毫升(严格保留3位小数)以及一共需要多少个杯子(每人2个)。
#include <cstdio>
int main() {
double t;
int n;
// 用 %lf 读 double, 用 %d 读 int
scanf("%lf%d", &t, &n);
// t/n 对应 %.3f (保留三位小数), n*2 对应 %d,中间用 \n 换行
printf("%.3f\n%d\n", t / n, n * 2);
return 0;
}
六、 总结
cin/cout:语法简单直观,能自动识别类型,是我们日常编程的常用选择。scanf/printf:- 优点:执行效率更高;拥有强大的格式控制能力,能实现精准的输入匹配和带精度的输出。
- 缺点:语法稍显复杂,需要手动匹配占位符和变量类型,并且
scanf必须带&。
- 如何选择? 在需要精确控制输入输出格式(如本讲的例题),就非常推荐使用
scanf/printf。