01-从 0 开始:变量、条件、循环(含练习)¶
目录页:见 C++ 小白教程目录
目标¶
- 写出并跑通最小 C++ 程序(能输入/输出)
- 存数据(变量)
- 做判断(条件)
- 重复做事(循环)
0. 先跑起来:你的第一个 C++ 程序¶
一个最小的 C++ 程序长这样:
如果你想“所有细节都知道”,我们就把这段代码拆成一张“零件清单”。先提醒一句:第一次写程序时,你不需要把下面每一条都背下来;但你随时可以回来查,慢慢就会熟。
0.1 #include <iostream>:把工具搬进来¶
- 专业名称:预处理指令(preprocessor directive)。
#include做的事很像“装配工在开工前把说明书夹进工程文件里”:它会把<iostream>这个头文件(header)里声明的东西“带进来”,让你能用输入输出相关的名字。<iostream>里最常见的就是标准输入输出流:std::cout(标准输出)和std::cin(标准输入)。
类比: - 头文件像“工具清单/接口说明书”,告诉编译器“有哪些工具可以用、叫什么名字、怎么用”。真正的实现通常在标准库里,由编译器/链接器把它们接上。
0.2 int main():程序入口¶
- 专业名称:主函数(entry point)。
main是程序的“正门”。系统启动你的程序时,会从这里开始执行。int表示main的返回类型是整数。返回值会交给操作系统:通常0表示正常结束,非 0 表示出错(可以理解为“结束时给系统的回执码”)。()是参数列表。这里为空,表示这个版本的main不接收命令行参数。你以后会看到另一种常见写法:int main(int argc, char* argv[])。
类比:
- main 像电影的第一幕:观众(操作系统)放映时,永远从第一幕开始。
0.3 { ... }:代码块(block)¶
{和}之间是一段代码块,表示这些语句属于main。- 你可以把它当作“一个房间”:房间里的东西(变量)通常只在这个房间里有效(后面讲作用域会细说)。
0.4 std::cout << "Hello, C++!" << std::endl;:输出一行文字¶
这一行信息量很大,我们继续拆:
std:专业名称:命名空间(namespace)。- 类比:像“姓氏/门牌”。C++ 里同名的东西很多,用
std::就是在说“标准库这一家(standard library)里的 cout”。 cout:专业名称:标准输出流对象(standard output stream)。- 类比:像一个“水龙头/喷嘴”,你把数据喂给它,它就把内容输出到终端(控制台)。
<<:专业名称:流插入运算符(stream insertion operator)。- 类比:像传送带,把右边的东西“送进”左边的输出流里。
- 你看到连续多个
<<,就理解为“把很多东西依次送进同一个水龙头”。 "Hello, C++!":专业名称:字符串字面量(string literal)。- 类比:像一张写着固定文字的小纸条,程序直接拿来输出。
std::endl:专业名称:操纵符(manipulator)。- 作用:输出一个换行,并且通常会刷新缓冲区(flush)。
- 类比:换行像“写完这一行按回车”;刷新像“强制把草稿箱里的内容立刻投递出去”。(很多时候你也可以用
'\n'换行,它更轻量;我们后面会讲差异。) - 行尾的
;:专业名称:语句结束符(statement terminator)。 - 类比:像一句话的句号,告诉编译器“这句话说完了”。
0.5 return 0;:告诉系统“我正常结束了”¶
return:从函数返回,把一个值交给调用者(这里调用者是操作系统)。0:惯例表示成功。
0.6 这段程序从运行到输出,中间发生了什么(理解流程就够)¶
从“写下代码”到“屏幕出现 Hello”,大致分几步:
- 预处理:处理
#include之类的指令,把需要的声明“拼进来”。 - 编译:把 C++ 源码翻译成机器能理解的目标文件(你可以理解成“翻译成半成品零件”)。
- 链接:把你的代码和标准库等拼在一起,生成最终可执行程序(“把零件装成整机”)。
- 运行:操作系统找到
main,执行其中语句,std::cout把内容输出到终端。
1. 输出与输入:cout / cin¶
1.1 输出:cout¶
这一行里 std::cout / << / std::endl 的拆解(术语+类比)在 0.4 已经讲过,这里只补充你会经常用到的两条规则:
你会看到连续 << 的写法非常常见:
这里的 '\n' 是换行字符(newline character)。它只负责换行,通常不会强制刷新,输出效率更高;std::endl 更像“写完这一行立刻按下发送”。
1.2 输入:cin¶
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
std::cout << "age=" << age << std::endl;
return 0;
}
把这一行当成“从键盘收货到变量的仓库里”:
std::cin:标准输入流(standard input stream),可以理解为“键盘进货口/漏斗”。>>:流提取运算符(stream extraction operator),像“筛子/吸管”,把输入内容按类型解析后放进变量。age:一个int变量(变量到底是什么,放到第 2 章统一讲)。
输入时有几个新手一定会踩到的规则(这里把规则讲全):
cin >> age会跳过前导空白(空格、换行),然后尽量读出一个整数。- 如果你输入了
18abc:会先把18读进age,abc留在输入缓冲里等下一次读取。 - 如果你输入了
abc:解析失败,cin会进入失败状态(fail state),后续读取会一直失败,直到你清除状态并丢弃错误输入。
类比:
- cin 像快递分拣:你说“我要一个 int”,它就按 int 的规则拆箱;拆不出来就打上“失败”标签。
2. 变量:给数据起名字¶
2.1 最常用的几种类型¶
int:整数(例如 0、10、-3)double:小数(例如 3.14)char:单个字符(例如 'A')bool:真假(true/false)std::string:字符串(例如 "hello")
例子:
#include <iostream>
#include <string>
int main() {
int count = 10;
double pi = 3.14159;
char c = 'Q';
bool ok = true;
std::string name = "qtcraft";
std::cout << count << " " << pi << " " << c << " " << ok << " " << name << std::endl;
return 0;
}
把“类型 + 变量名”理解成“贴标签的盒子”:
- 专业名称:C++ 是静态类型语言(statically typed language)。你在写代码时就要告诉编译器“这个盒子里装什么类型的东西”。
- 类比:
int count就像写了“整数专用”的盒子,之后你往里放的东西必须像整数;double pi是“小数专用”的盒子。
几个细节也一起讲清楚:
char c = 'Q';:单引号'Q'表示字符字面量(character literal),是“一个字符”;双引号"Q"是字符串字面量,是“一串字符”(哪怕只有 1 个)。bool ok = true;:bool只有true/false两种值。默认用cout输出时常见结果是1/0(这是输出格式的默认表现,不是bool变成了数字)。std::string name = "qtcraft";:std::string是标准库提供的字符串类型,所以需要#include <string>,并且用std::前缀表示来自标准库命名空间。
2.2 变量初始化(很重要)¶
推荐写法:
这里其实包含两种初始化方式:
int a = 1;:拷贝初始化(copy initialization)。类比:拿一个“值 1 的小盒子”,把它复制/放进a这个盒子里。int b{2};:列表初始化(list initialization / brace initialization)。类比:用大括号{}把值“严丝合缝地装进去”,它更严格,能避免一些危险的“窄化转换”(narrowing conversion),比如把小数硬塞进整数导致丢精度。
你现在阶段记住一个结论就够用:
- 新手写代码优先用 type name{value}; 或 type name = value;,两者都能用;{} 更严格更安全。
2.3 常量:const¶
maxRetry 之后不能再改。
更精确一点说:
- 专业名称:
const表示只读(不可修改)(read-only / const-qualified)。 - 类比:像“封条”。贴了封条的盒子你可以看、可以用,但不能再往里改内容。
- 好处:减少意外修改;编译器也更容易做优化与检查。
3. 运算符:加减乘除与比较¶
3.1 算术运算¶
+ - * /%:取余数(只用于整数)
#include <iostream>
int main() {
int a = 7;
int b = 3;
std::cout << a / b << std::endl;
std::cout << a % b << std::endl;
return 0;
}
上面这段输出是 2 和 1:整数除法会丢掉小数部分。
补充几个关键细节(以后写程序经常踩坑):
/在整数之间做的是整数除法(integer division),结果向 0 截断:7/3==2,-7/3==-2。- 如果你希望得到小数,需要至少一边是浮点数:
7 / 3.0或static_cast<double>(7) / 3。 %是取余运算符(modulus operator),只对整数有定义。
3.2 比较与逻辑¶
- 比较:
== != < <= > >= - 逻辑:
&&(且)、||(或)、!(非)
这里的 score >= 60 的结果是一个 bool:要么 true,要么 false。
==:相等比较(equality)。新手最常犯错是把==写成=。=是赋值(assignment),==才是比较。&&、||:短路逻辑(short-circuit)。A && B:如果 A 已经是 false,就不会再算 B(因为结果必然 false)。A || B:如果 A 已经是 true,就不会再算 B(因为结果必然 true)。- 类比:像“安检口”:已经不合格就不用走下一道,已经合格也不用再检查。
4. 条件判断:if / switch¶
4.1 if / else if / else¶
#include <iostream>
int main() {
int score = 85;
if (score >= 90) {
std::cout << "A" << std::endl;
} else if (score >= 80) {
std::cout << "B" << std::endl;
} else if (score >= 60) {
std::cout << "C" << std::endl;
} else {
std::cout << "D" << std::endl;
}
return 0;
}
把 if 想成“岔路口指示牌”:
- 专业名称:
if语句(selection statement / conditional statement)。 if (条件)里括号的内容最终要能当成bool来判断。{}建议新手阶段全部都写上:这样不容易出现“以为有多行,其实只有一行受 if 控制”的错误。
4.2 switch(适合“某个值等于哪个”)¶
#include <iostream>
int main() {
int day = 3;
switch (day) {
case 1:
std::cout << "Mon" << std::endl;
break;
case 2:
std::cout << "Tue" << std::endl;
break;
case 3:
std::cout << "Wed" << std::endl;
break;
default:
std::cout << "Unknown" << std::endl;
break;
}
return 0;
}
把 switch 想成“按号码分流的分拣机”:
- 专业名称:
switch语句(switch statement)。 case 3:里的3必须是编译期可确定的常量(比如字面量、枚举值)。break:跳出 switch。没有break会发生贯穿(fallthrough),也就是继续执行下一个 case 的代码。
新手阶段的使用建议:
- 每个 case 末尾都写 break,除非你非常确定要故意 fallthrough。
5. 循环:for / while / do-while¶
5.1 for:最常用的循环¶
#include <iostream>
int main() {
for (int i = 1; i <= 5; i++) {
std::cout << i << std::endl;
}
return 0;
}
把 for 想成“带计数器的流水线”:
- 专业名称:
for循环(for loop / iteration statement)。 - 结构是:
for (初始化; 条件; 迭代): - 初始化:只在循环开始前执行一次(这里是
int i = 1)。 - 条件:每一轮开始前检查,false 就停(这里是
i <= 5)。 - 迭代:每一轮结束后执行(这里是
i++)。
类比: - 像工厂班次:先上班打卡(初始化),每小时看一次是否到下班点(条件),做完一件加一格计数(迭代)。
5.2 while:先判断,再执行¶
#include <iostream>
int main() {
int x = 1;
while (x <= 5) {
std::cout << x << std::endl;
x++;
}
return 0;
}
把 while 想成“门口保安先检查再放行”:
- 专业名称:
while循环(while loop)。 - 先判断条件,再决定要不要执行循环体;所以如果一开始条件就是 false,循环体可能一次都不会执行。
5.3 do-while:先执行一次,再判断¶
#include <iostream>
int main() {
int x = 10;
do {
std::cout << x << std::endl;
x++;
} while (x < 5);
return 0;
}
把 do-while 想成“先进去做一次,再看是否继续”:
- 专业名称:
do-while循环(do-while loop)。 - 它保证循环体至少执行一次,因为判断在末尾。
5.4 break / continue¶
break:立刻结束整个循环continue:跳过本轮,进入下一轮
类比:
- break 像“直接下班回家”,后面都不做了。
- continue 像“这一件不合格,扔掉继续下一件”,但班次还没结束。
常见坑¶
-
错误:把比较写成赋值
if (x = 3)
结果:条件几乎总为真/行为异常
正确:比较用==:if (x == 3) -
错误:以为
7 / 3会得到2.333...
结果:整数除法直接截断成2
正确:至少一边用浮点数:7 / 3.0 -
错误:
switch忘记写break
结果:贯穿到下一个case,输出不符合预期
正确:新手阶段每个case都写break -
错误:for 循环边界写错(比如少算/多算一轮)
结果:输出少一次/多一次,或者越界
正确:先用纸算清楚循环要跑几轮,再写条件(常见是i <= n或i < n) -
错误:输入不是数字时还继续
cin >> x
结果:cin进入失败状态,后续读取一直失败
正确:检测输入是否成功,必要时清除状态并丢弃错误输入
小练习(建议每个都亲手敲一遍)¶
练习 1:摄氏度转换¶
- 题目:输入华氏度 F,输出摄氏度 C:
C = (F - 32) / 1.8 - 输入/输出:输入
double F,输出double C - 约束:保留小数
- 提示:用
double;公式里的1.8必须是浮点数 - 目标:练
cin/cout与浮点运算
练习 2:1..n 求和¶
- 题目:输入整数 n,输出
1 + 2 + ... + n - 输入/输出:输入
int n,输出和(建议用long long) - 约束:n 可能比较大,避免用
int溢出 - 提示:用
sum从 0 开始累加;先写 for,再写 while - 目标:练循环与累加
练习 3:判断素数(入门版)¶
- 题目:输入整数 n(n >= 2),判断 n 是否是素数
- 输入/输出:输入
int n,输出prime=1或prime=0 - 约束:先写能跑通的版本即可
- 提示:从 2 到 n-1 试除;用
%判断整除:n % i == 0;加分:试到i*i <= n - 目标:练循环 + if 判断 +
%
练习 4:乘法表(1~9)¶
- 题目:输出标准 9x9 乘法表
- 输入/输出:无输入;输出乘法表
- 约束:使用双重循环
- 提示:外层控制行 i(1..9),内层控制列 j(1..i)
- 目标:练双重循环与输出
练习 5:猜数字(综合练习)¶
- 题目:程序随机产生 1~100 的数字,你不断输入猜测,提示“小了/大了/猜对了”
- 输入/输出:多次输入猜测值;输出提示与最终次数
- 约束:随机范围必须是 1..100;直到猜对才结束
- 提示:
std::rand()生成随机数;std::srand((unsigned)time(nullptr))设随机种子;头文件<cstdlib>、<ctime> - 目标:综合练输入输出 + 循环 + if/else + 计数器
小结¶
- 写出一个可以输入/输出的控制台程序
- 声明变量并做简单计算
- 用 if / switch 处理分支
- 用 for / while 写循环与小练习
下一篇会把重复代码封装成函数:输入是什么、输出是什么,怎么写得更干净。