跳转至

01-从 0 开始:变量、条件、循环(含练习)

目录页:见 C++ 小白教程目录

目标

  • 写出并跑通最小 C++ 程序(能输入/输出)
  • 存数据(变量)
  • 做判断(条件)
  • 重复做事(循环)

0. 先跑起来:你的第一个 C++ 程序

一个最小的 C++ 程序长这样:

#include <iostream>

int main() {
    std::cout << "Hello, C++!" << std::endl;
    return 0;
}

如果你想“所有细节都知道”,我们就把这段代码拆成一张“零件清单”。先提醒一句:第一次写程序时,你不需要把下面每一条都背下来;但你随时可以回来查,慢慢就会熟。

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

#include <iostream>

int main() {
    std::cout << "A" << "B" << 123 << std::endl;
    return 0;
}

这一行里 std::cout / << / std::endl 的拆解(术语+类比)在 0.4 已经讲过,这里只补充你会经常用到的两条规则:

你会看到连续 << 的写法非常常见:

std::cout << "x=" << x << ", y=" << y << '\n';

这里的 '\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 读进 ageabc 留在输入缓冲里等下一次读取。
  • 如果你输入了 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;
int b{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

const int maxRetry = 3;

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;
}

上面这段输出是 21:整数除法会丢掉小数部分。

补充几个关键细节(以后写程序经常踩坑):

  • / 在整数之间做的是整数除法(integer division),结果向 0 截断:7/3==2-7/3==-2
  • 如果你希望得到小数,需要至少一边是浮点数:7 / 3.0static_cast<double>(7) / 3
  • % 是取余运算符(modulus operator),只对整数有定义。

3.2 比较与逻辑

  • 比较:== != < <= > >=
  • 逻辑:&&(且)、||(或)、!(非)
int score = 85;
bool pass = score >= 60;

这里的 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 <= ni < 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=1prime=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 写循环与小练习

下一篇会把重复代码封装成函数:输入是什么、输出是什么,怎么写得更干净。