C1-02 变量的输入输出
变量、输入、运算与结果输出
学习目标:理解变量就是程序中用来存放数据的“盒子”;学会定义变量、给变量赋值;掌握
cin输入和cout输出;能够完成“输入数据 → 计算处理 → 输出结果”的简单程序;知道如何根据题目数据范围选择合适的数据类型。
一、变量是什么
1. 为什么需要变量
第一课中,我们可以直接输出算式:
cout << "3 + 4 = " << 3 + 4 << endl;
这个程序只能计算 3 + 4。如果题目换成 5 + 8,就必须修改代码。
变量可以在程序运行时暂时保存数据,让程序先读入数据,再进行计算:
int a, b; // 准备两个盒子,名字叫 a 和 b
cin >> a >> b; // 从键盘读入两个整数
cout << a + b << endl;
输入 3 4,程序输出 7;输入 100 200,程序输出 300。同一份代码可以处理不同的数据,这就是变量的作用。
2. 把变量想象成一个盒子
变量是程序中用来存放数据的一块空间。可以把它想象成一个贴了名字的盒子:
┌─────────────┐
│ a = 10 │
└─────────────┘
- 盒子:程序中用来保存数据的空间。
- 标签:变量名,例如
a。 - 盒子里的内容:变量的值,例如
10。 - 盒子的类型:决定这个盒子可以装整数、小数、字符还是“是/否”。
3. 变量的值可以改变
变量之所以叫“变量”,是因为里面的值可以发生变化:
int a = 10;
cout << a << endl; // 输出 10
a = 20;
cout << a << endl; // 输出 20
第二次赋值后,原来的 10 被新的 20 覆盖了。
4. 定义、赋值和初始化
使用变量前,要先告诉计算机变量的类型和名字:
int score;
score = 100;
cout << score << endl;
= 是赋值运算符,意思是“把右边的内容放进左边的变量”:
int a;
a = 10; // 把 10 放进 a
a = 20; // 再把 20 放进 a,原来的 10 被覆盖
还可以把一个变量的值放进另一个变量:
int a = 10;
int b;
b = a;
cout << b << endl; // 输出 10
定义变量的同时给它一个初始值,叫作初始化:
int age = 10;
初始化的完整例子:
int age = 10;
double pi = 3.14;
char ch = 'A';
bool pass = true;
关键区别:
=在这里不是数学里的“等于”,而是“赋值”。所以a = a + 1;是合法的,意思是“把 a 加 1 后再放回 a”。
5. 变量必须先定义,再使用
下面的写法是错误的:
score = 100; // 错误:还没有定义 score
正确写法:
int score;
score = 100;
局部变量如果没有初始化,里面可能是内存中原来留下的随机内容:
int a;
cout << a << endl; // 不要这样写,结果不确定
如果变量马上要通过 cin 输入,也可以先定义、后输入:
int a;
cin >> a;
二、变量名的写法
变量名就是盒子上的标签。标签写得不符合规则,程序就无法编译。
1. 变量名的四条规则
| 规则 | 说明 | 合法示例 | 非法示例 |
|---|---|---|---|
| 只能使用字母、数字和下划线 | 不能有空格,也不能使用其他符号 | score、a1、student_score |
s core、a-b、a# |
| 不能以数字开头 | 第一个字符必须是字母或下划线 | a1、_x |
1a、2nd |
| 区分大小写 | 大写和小写是不同的字母 | a 和 A 是两个不同变量 |
不要把 score 和 Score 混用 |
| 不能使用保留字 | C++ 已经占用的词不能当普通变量名 | num、sum |
int、return、if |
2. 给变量名起名字的原则
给变量名起名字时,可以记住三个原则:
- 见名知义:变量名尽量让人一眼看懂用途。例如,分数用
score,长度用length,人数用count。 - 常用取简:很短、很常见的题目,可以使用
a、b、n、i这类简短名字。 - 专用取繁:程序较长、变量用途容易混淆时,变量名要写得更具体,例如
student_count、total_score。
示例:
int age; // 年龄
int score; // 分数
int student_count; // 学生人数
double price; // 价格
竞赛题中也经常使用简短的变量名:
int a, b, n;
3. 常见保留字
下面这些词有特殊作用,不能拿来当普通变量名:
int long long float double
char bool if else
for while return
main 是程序的主函数名称,也不要拿它当普通变量名。
三、用 cin 输入和 cout 输出
这一部分先统一使用 int 举例。学会流程后,再扩展到小数、字符等其他类型。
1. 程序的基本流程
写程序时经常遵循下面的顺序:
输入数据(Input) → 计算处理(Process) → 输出结果(Output)
例如,计算两个数的和:
输入 a 和 b → 计算 a + b → 输出 a + b
2. cin 是什么
cin 用来从键盘读取数据。>> 的中文正式名称是提取运算符,英文全称是 extraction operator,可以理解为“从输入流中提取数据,送进变量”。
cin >> 变量名;
数据方向可以画成:
键盘输入 → cin → 变量
3. 输入一个整数
int a;
cin >> a;
运行程序后,在键盘输入 10,然后按回车键结束本次输入,变量 a 的值就变成了 10。
注意: 自己在控制台运行时,输入完数据后要按回车。
4. 输入多个整数
int a, b;
cin >> a >> b;
程序会先把读到的第一个数据放进 a,再把读到的第二个数据放进 b。输入顺序必须和变量接收顺序一致。
输入:
3 4
结果是 a = 3、b = 4。如果输入 4 3,结果就会变成 a = 4、b = 3。
下面两种输入方式都可以:
3 4
3
4
空格和回车都可以用来分隔数据。输入完最后一个数据后,也要按回车键。
5. cout 输出变量
变量名不加引号,输出的是变量里的值:
int a = 10;
cout << a << endl; // 输出 10
如果加上双引号,输出的就是字母 a:
cout << "a" << endl; // 输出 a
| 写法 | 输出 |
|---|---|
cout << a; |
输出变量 a 里面的值 |
cout << "a"; |
输出字母 a |
6. 输出多个变量和文字
int a = 10, b = 20;
cout << "a = " << a << ", b = " << b << endl;
输出:
a = 10, b = 20
7. 输入两个数并输出它们的和
这是最经典的顺序结构程序:
#include <iostream>
using namespace std;
int main() {
int a, b;
cin >> a >> b; // Input:输入
cout << a + b << endl; // Process + Output:计算并输出
return 0;
}
输入:
3 4
输出:
7
在线评测题没有要求时,不要输出“请输入两个数:”之类的提示语,否则可能造成答案格式错误。
四、数据类型
1. 为什么变量要有类型
不同的数据需要不同的“盒子”:
12是整数;3.14是小数;'A'是一个字符;true和false表示“是”或“否”。
定义变量时,要先写出它的数据类型。
2. 常用的基本数据类型
下面的范围和精度以信奥常见的 64 位 Linux + g++ 环境为参考。不同平台可能略有差异。
| 类型 | 关键字 | 字节数 | 常见范围或精度 | 示例 |
|---|---|---|---|---|
| 整数型 | int |
4 字节 | -2147483648 ~ 2147483647,约 ±21 亿 |
12、-5 |
| 大整数型 | long long |
8 字节 | -9223372036854775808 ~ 9223372036854775807,约 ±9.22×10¹⁸ |
1000000000000 |
| 单精度小数型 | float |
4 字节 | 约 ±3.4×10^38,有效数字约 6~7 位 |
3.14 |
| 双精度小数型 | double |
8 字节 | 约 ±1.7×10^308,有效数字约 15~16 位 |
3.14 |
| 字符型 | char |
1 字节 | 通常占 1 字节;常见 ASCII 字符范围为 0~127 | 'A'、'+' |
| 布尔型 | bool |
1 字节 | 只有 true 和 false |
true、false |
初学阶段的选择口诀:
整数通常用
int,数字可能超过 21 亿时用long long;小数一般用double,需要明确使用单精度时用float;一个字符用char;只有“是/否”时用bool。
3. 整数:int 和 long long
int age = 12;
int score = 100;
long long population;
cin >> population;
int是最常用的整数类型。long long可以保存比int大得多的整数。
4. 小数:float 和 double
float rate;
cin >> rate;
double height = 1.52;
double price = 3.5;
float是单精度小数,通常有约 6~7 位有效数字。double是双精度小数,通常有约 15~16 位有效数字。- 信奥入门阶段遇到小数,通常直接使用
double,因为它更精确。
这里的“精度”是通常能可靠保留的有效数字位数,不是小数点后固定有多少位。float 和 double 都可能存在很小的表示误差。
5. 字符:char
char 只能保存一个字符,必须使用英文单引号:
char ch = 'A';
char op = '+';
char ch = 'A'; // 一个字符
cout << "A"; // 一个字符串
记忆: 一个字符用单引号,多个字符组成的文字用双引号。
6. 布尔值:bool
bool 只有两个值:
true:真,是;false:假,不是。
bool pass = true;
bool finished = false;
使用 cout 输出时,true 通常显示为 1,false 通常显示为 0。
7. sizeof:查看占用多少字节
C++ 可以使用 sizeof 查看类型或表达式占用多少字节:
cout << sizeof(int) << endl; // 类型名
int a = 10;
cout << sizeof(a) << endl; // 变量名
cout << sizeof(12) << endl; // 数字,12 默认是 int
cout << sizeof(12LL) << endl; // long long 类型的数字
cout << sizeof(3.14f) << endl; // float 类型的小数
cout << sizeof(3.14) << endl; // double 类型的小数
sizeof 查看的是“占用多少字节”,不是数值大小。1 字节等于 8 位,1 位表示一个二进制的 0 或 1。
| 数据类型 | 常见大小 |
|---|---|
int |
4 字节 |
long long |
8 字节 |
float |
4 字节 |
double |
8 字节 |
char |
1 字节 |
bool |
1 字节 |
五、算术运算符
1. 五个基本算术运算符
| 运算符 | 含义 | 示例 | 结果 | 适用类型 |
|---|---|---|---|---|
+ |
加法 | 3 + 4 |
7 |
整数、小数 |
- |
减法 | 10 - 3 |
7 |
整数、小数 |
* |
乘法 | 6 * 7 |
42 |
整数、小数 |
/ |
除法 | 15 / 4 |
见下文 | 整数、小数 |
% |
取余 | 15 % 4 |
3 |
只适用于整数 |
2. 整数除法
两个整数相除,结果仍然是整数,小数部分会直接丢掉,不会四舍五入:
cout << 15 / 4 << endl; // 输出 3,不是 3.75
cout << 7 / 2 << endl; // 输出 3,不是 3.5
cout << 1 / 2 << endl; // 输出 0
如果想得到小数,只要让其中一个数变成小数:
cout << 15.0 / 4 << endl; // 输出 3.75
cout << 7 / 2.0 << endl; // 输出 3.5
cout << 1.0 / 2 << endl; // 输出 0.5
3. 取余运算 %
% 求的是除法的余数:
cout << 15 % 4 << endl; // 15 除以 4,余 3
cout << 7 % 2 << endl; // 7 除以 2,余 1
cout << 10 % 5 << endl; // 10 除以 5,余 0
重要:
%只能用于整数。3.14 % 2会编译错误。
(1)取一个数的个位和十位
int n;
cin >> n;
cout << n % 10 << endl; // 个位
cout << n / 10 % 10 << endl; // 十位
(2)把秒数转换成时、分、秒
int total;
cin >> total;
int hour = total / 3600;
int rest = total % 3600;
int minute = rest / 60;
int second = rest % 60;
cout << hour << " " << minute << " " << second << endl;
这里使用了整数除法和取余:
小时 = 总秒数 / 3600
剩余秒数 = 总秒数 % 3600
分钟 = 剩余秒数 / 60
秒 = 剩余秒数 % 60
4. 运算顺序
C++ 的运算顺序和数学中很像,只不过多了一个取余%:
- 先算乘法
*、除法/和取余%; - 再算加法
+和减法-; - 同级运算,自左向右;
- 有小括号,先算小括号。
cout << 2 + 3 * 4 << endl; // 输出 14
cout << (2 + 3) * 4 << endl; // 输出 20
cout << 10 - 2 * 3 << endl; // 输出 4
拿不准时,主动加括号:
int result = (a + b) * c;
5. 长方形的周长和面积
输入长方形的长和宽,输出周长和面积:
int length, width;
cin >> length >> width;
int perimeter = 2 * (length + width);
int area = length * width;
cout << perimeter << " " << area << endl;
6. 平均分
输入三门课的整数成绩,输出平均分:
int a, b, c;
cin >> a >> b >> c;
double average = (double)(a + b + c) / 3;
cout << average << endl;
这里要注意:如果写成 (a + b + c) / 3,三个数都是整数,结果会进行整数除法。先把总和转换成 double,才能保留小数。
7. 常用的简写运算
| 写法 | 等价写法 | 含义 |
|---|---|---|
a += 5; |
a = a + 5; |
a 加 5 |
a -= 2; |
a = a - 2; |
a 减 2 |
a *= 3; |
a = a * 3; |
a 乘以 3 |
a /= 3; |
a = a / 3; |
a 除以 3 |
a %= 3; |
a = a % 3; |
a 对 3 取余 |
a++; |
a = a + 1; |
a 加 1 |
a--; |
a = a - 1; |
a 减 1 |
六、数据类型转换
当不同类型的数据一起运算,或者把一个值放进另一种类型的变量时,C++ 需要把数据从一种类型变成另一种类型,这叫类型转换。
类型转换主要分成两种:
| 类型 | 中文名称 | 谁来完成 | 是否需要写代码 |
|---|---|---|---|
| 隐式类型转换 | 自动类型转换 | 编译器自动完成 | 通常不需要额外写 |
| 显式类型转换 | 强制类型转换 | 程序员主动指定 | 需要写转换语法 |
1. 隐式类型转换
(1)混合运算时的自动提升
当整数和小数一起运算时,C++ 通常会把整数自动转换成小数:
cout << 7 / 2 << endl; // 3:两个 int 做整数除法
cout << 7 / 2.0 << endl; // 3.5:2.0 是 double,7 自动转成 double
cout << 3 + 0.14 << endl; // 3.14:3 自动转成 double
入门阶段可以先记住这个帮助理解的顺序:
bool / char → int → long long → float → double
实际转换还会受到数据范围和编译器规则影响,但做基础题时重点掌握 int 和 double 的混合运算即可。
(2)赋值时的自动转换
赋值时,右边的值会转换成左边变量的类型:
double x = 5; // int 5 自动转成 double 5.0
int a = 3.14; // double 3.14 转成 int,结果为 3
float f = 3.14; // double 3.14 转成 float,精度可能降低
如果从范围大、精度高的类型放入范围小、精度低的类型,就可能丢失信息:
int a = 3.99; // a 是 3,不是 4
小数部分会被直接截掉,不会自动四舍五入。
(3)char 和 bool 参与运算
char ch = 'A'; // 常见编码中 'A' 对应 65
cout << ch + 1 << endl; // 输出 66
bool ok = true; // true 按 1 参与计算
cout << ok + 10 << endl; // 输出 11
2. 显式类型转换
显式类型转换也叫强制类型转换,意思是程序员主动告诉 C++:“请把这个值按照某种类型来处理”。
本课先掌握两种常见写法:
double x = 3.14;
int a = (int)x; // C 风格写法
int b = int(x); // 函数风格写法
cout << a << " " << b << endl; // 3 3
| 写法 | 语法 | 示例 | 特点 |
|---|---|---|---|
| C 风格 | (目标类型)表达式 |
(int)x |
简短,信奥题中很常见 |
| 函数风格 | 目标类型(表达式) |
int(x) |
写法直观 |
3. 整数除法转换成小数除法
如果想让两个整数相除得到小数,必须在除法发生前先转换:
int a = 7, b = 2;
cout << (double)a / b << endl; // 3.5
cout << double(a) / b << endl; // 3.5
注意转换的位置:
cout << (double)(a / b) << endl; // 3.0:先算 7/2,再转小数
cout << (double)a / b << endl; // 3.5:先转小数,再做除法
关键区别:
(double)(a / b)是“先除后转”,(double)a / b是“先转后除”。要保留小数,必须先转再除。
4. 把小数转换成整数
cout << (int)3.14 << endl; // 3
cout << (int)3.99 << endl; // 3
cout << int(-3.7) << endl; // -3
转换为整数时通常是向零截断,也就是直接丢掉小数部分,不是四舍五入,也不是总向下取整。
5. 字面量和类型后缀
代码中直接写出的数字、字符和字符串叫作字面量。字面量可以通过后缀明确指定类型:
| 写法 | 类型或含义 | 说明 |
|---|---|---|
12 |
int |
整数常量默认优先按 int 处理 |
12LL |
long long |
LL 明确表示 long long |
3.14 |
double |
普通小数默认按 double 处理 |
3.14f |
float |
f 或 F 明确表示 float |
'A' |
char |
单引号中的一个字符 |
"hello" |
字符串 | 双引号中的一段文字 |
true、false |
bool |
真和假 |
例如:
int a = 12;
long long b = 12LL;
float c = 3.14f;
double d = 3.14;
当数字可能超过 int 范围时,给整数常量加 LL,可以明确告诉编译器从一开始就按 long long 处理:
long long a = 2000000000LL;
long long b = 2000000000LL;
long long sum = a + b;
七、数据范围与类型选择
写题时,定义变量的类型不是随便选的,要先看题目给出的数据范围,再看计算过程中可能出现的最大值。
1. 不只看输入,还要看中间结果
如果题目保证 a、b 都不超过 21 亿,单个数可以放进 int;但是 a + b 可能超过 int 的最大值,所以求和程序应使用 long long:
long long a, b;
cin >> a >> b;
cout << a + b << endl;
如果只把最终结果强制转换成 long long,但前面的计算已经使用 int 溢出,通常已经来不及补救:
int a = 2000000000, b = 2000000000;
long long ans = (long long)(a + b); // a+b 先按 int 计算,可能已经溢出
更安全的写法是让计算从一开始就使用 long long:
long long a = 2000000000LL;
long long b = 2000000000LL;
long long ans = a + b;
2. 选择类型的简单原则
| 题目数据 | 常用选择 |
|---|---|
| 一般范围内的整数,且计算结果也不大 | int |
| 输入或中间结果可能超过 21 亿 | long long |
| 小数(一般情况,信奥首选,精度约 15~16 位) | double |
| 小数(明确要求单精度,或精度要求极低,精度约 6~7 位) | float (信奥中极少使用) |
| 一个字符 | char |
| 只有真/假、是/否 | bool |
做题原则: 先看输入范围,再看计算结果可能多大,最后选择能够装下所有中间结果和最终结果的类型。
八、常见错误与注意事项
1. 有编译器提示(error / warning)
| 编号 | 错误 | 关键错误提示(g++ -std=c++11) | 后果 | 改正 |
|---|---|---|---|---|
| E1 | 变量未定义就使用 | error: 'x' was not declared in this scope |
编译错误,找不到变量 | 先定义变量,再使用 |
| E2 | 变量未赋值就读取 | 警告(非编译错误):warning: 'x' is used uninitialized in this function [-Wuninitialized] |
结果不确定,可能输出随机值 | 定义时初始化,或先用 cin 输入 |
| E3 | 变量名以数字开头 | error: expected unqualified-id before numeric constant |
编译错误 | 改成字母或下划线开头 |
| E4 | 变量名使用保留字 | error: expected unqualified-id before 'int'(以 int int; 为例) |
编译错误 | 换一个普通名字 |
| E5 | 同一个名字重复定义 | error: redefinition of 'int a' |
编译错误 | 一个作用范围内不要重复定义 |
| E6 | 大小写写错 | error: 'Score' was not declared in this scope |
score 和 Score 被当成不同变量 |
统一变量名大小写 |
| E7 | 字符使用双引号,如 "A" |
error: invalid conversion from 'const char*' to 'char' [-fpermissive] |
这是字符串,不是一个字符 | 单个字符使用 'A' |
| E8 | cin 使用 << |
error: no match for 'operator<<' (operand types are 'std::istream' and 'int') |
输入方向错误 | cin 使用 >> |
| E9 | cout 使用 >> |
error: no match for 'operator>>' (operand types are 'std::ostream' and 'int') |
输出方向错误 | cout 使用 << |
| E10 | 对小数使用 % |
error: invalid operands of types 'double' and 'double' to binary 'operator%' |
编译错误 | 求余只用于整数 |
2. 无编译器提示(非编译错误)
| 编号 | 错误 | 后果 | 改正 |
|---|---|---|---|
| E11 | 输入完不按回车 | 程序可能继续等待输入 | 最后一个数据输入后按回车 |
| E12 | 输入顺序和变量顺序不一致 | 变量得到错误的数据 | 按 cin 后面的变量顺序输入 |
| E13 | 7 / 2 以为是 3.5 |
实际输出 3 | 使用 7.0 / 2 或 (double)7 / 2 |
| E14 | int a = 3.99 以为得到 4 |
实际得到 3 | 赋值转换会直接截断 |
| E15 | 先除法、后转换 | 小数已经丢失 | 先转换,再做除法 |
| E16 | 只看输入范围,不看计算结果范围 | a + b 等中间结果可能溢出 |
让变量和中间结果使用足够大的类型 |
| E17 | 把 12、12LL、3.14、3.14f 当成完全一样 |
可能使用错误的类型和精度 | 记住常用字面量后缀 |
| E18 | 在线评测中输出多余提示语 | 可能格式错误 | 只输出题目要求的内容 |