CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
C++ 语言入门/课时/基础语法
RawBlame
课时目录12 节

C++ 语言入门

  1. 01C++ 是什么
  2. 02基础语法
  3. 03指针与引用
  4. 04面向对象
  5. 05内存与 RAII
  6. 06STL 容器与算法
  7. 07模板基础
  8. 08现代 C++ 特性
  9. 09多线程
  10. 10构建与依赖
  11. 11调试与测试
  12. 12综合练习

基础语法

data-types、operators、control flow、functions。

35 分钟

基础语法

这一课你将能做到

  1. 声明 C++ 的基本类型与 std::string,并说清整型溢出、浮点精度这类 Java 里同样存在的坑
  2. 用 if / switch / while / for 写出判分逻辑,理解 C++ 条件必须是布尔值的严格性
  3. 编写并调用自由函数,区分值传递与 const std::string& 传参,知道为什么大对象要传引用

为什么要学

任何判题逻辑的骨架都是「读输入 → 判断 → 循环测试点 → 输出结论」,拆开全是变量、控制流、函数三件套。你之后要读判题沙箱源码、刷算法题、写评测脚本,全都建立在这一课的地基上。

和 Java 对着学最快:C++ 的类型系统、运算符、控制流语法和 Java 几乎同源(都继承了 C 的衣钵),但 C++ 更「较真」——Java 里 if (score = 60) 因为类型不符直接编译报错,C++ 里它会把 60 赋给 score 再当真值判断,埋一颗闷雷。本课会带你在真实代码里躲开这些差异点。

先建立图像

一道题的评测流程,就是基础语法的全景图:

读入用户 ID(字符串)→ 变量
逐个测试点比对输出 → 循环
全对算 AC,否则算 WA → 分支
把「比对一个测试点」抽成函数 → 函数
int score = 87;
┌────────────┬─────────┐
│ 类型  int  │ 名字    │
│ 告诉编译器 │ score   │
│ 占4字节、  │ 指向那块│
│ 按整数解释 │ 内存    │
└────────────┴─────────┘
C++ 变量 = 一块有类型的内存,类型错了不悄悄转换(对比 Java 的自动装箱)

跟着做

步骤 1:变量与基本类型

新建 basics.cpp,写一个「提交信息卡片」:

#include <iostream>
#include <string>

int main() {
    std::string user = "nihao_2024";   // 字符串:std::string,对应 Java 的 String
    int score = 87;                    // 整型:Java 的 int
    double ratio = 0.875;              // 双精度浮点:Java 的 double
    bool accepted = false;             // 布尔:Java 的 boolean
    char level = 'B';                  // 单字符:用单引号,Java 的 char

    std::cout << user << " 得分 " << score
              << ",通过率 " << ratio << "\n";

    const int MAX_SCORE = 100;         // const = Java 的 final,不可再赋值
    std::cout << "满分 " << MAX_SCORE << "\n";
    return 0;
}
g++ -std=c++17 basics.cpp -o basics && ./basics

常用整型一览(面试与工程都会遇到):

类型典型大小Java 近似使用场景
int4 字节int一般计数,约 ±21 亿
long long8 字节long算法题防溢出首选
size_t8 字节无容器大小、数组下标(无符号)
double
8 字节
double
浮点计算

步骤 2:控制流——给提交定级

#include <iostream>

int main() {
    int score = 87;

    if (score >= 90) {
        std::cout << "AC:全部通过\n";
    } else if (score >= 60) {
        std::cout << "PA:部分通过\n";
    } else {
        std::cout << "WA:答案错误\n";
    }

    // switch:按评测结果码分流
    int verdict = 2;   // 0=CE 编译失败 1=TLE 超时 2=WA 答案错 3=AC 通过
    switch (verdict) {
        case 0: std::cout << "编译失败,检查语法\n"; break;
        case 1: std::cout << "超出时间限制\n"; break;
        case 2: std::cout << "答案错误\n"; break;
        case 3: std::cout << "通过!\n"; break;
        default: std::cout << "未知状态\n"; break;   // 忘写 break 会「贯穿」到下一分支
    }
    return 0;
}

步骤 3:循环——跑完所有测试点

#include <iostream>

int main() {
    // 10 个测试点的用户耗时(毫秒)
    int costs[] = {12, 8, 45, 30, 22, 19, 60, 3, 11, 7};
    int n = 10;

    // 经典 for:下标遍历
    int total = 0;
    for (int i = 0; i < n; ++i) {
        total += costs[i];
    }
    std::cout << "总耗时 " << total << "ms\n";

    // while:找到第一个超时的测试点
    int limit = 40;
    int idx = 0;
    while (idx < n && costs[idx] <= limit) {
        ++idx;
    }
    if (idx < n) {
        std::cout << "第 " << idx + 1 << " 个测试点超时,耗时 "
                  << costs[idx] << "ms\n";
    }
    return 0;
}

输出:

总耗时 217ms
第 3 个测试点超时,耗时 45ms

步骤 4:函数——把「判定单个测试点」抽出来

#include <iostream>
#include <string>

// 返回 bool 的自由函数(不属于任何类的函数,Java 没有「类外函数」概念)
// expected / actual 用值传递:各复制一份,函数内改动不影响外面
bool judgeCase(const std::string& expected, const std::string& actual) {
    // const std::string& :常量引用传递——不复制字符串,只「借」过来看
    // 字符串越长,引用传递省下的复制开销越大;判题对输出逐字节比对时全是这种写法
    return expected == actual;
}

int maxOf(int a, int b) {
    return a > b ? a : b;   // 三目运算符,和 Java 相同
}

int main() {
    if (judgeCase("42\n", "42\n")) {
        std::cout << "测试点通过\n";
    }
    std::cout << "最大耗时 " << maxOf(120, 87) << "ms\n";
    return 0;
}

步骤 5:函数要先声明后使用

C++ 编译器是「从上往下」读文件的,调用前必须见过这个函数。拆成声明 + 定义:

#include <iostream>

int square(int x);            // 声明(原型):只告诉编译器签名,不写实现

int main() {
    std::cout << square(9) << "\n";   // 可以先调用
    return 0;
}

int square(int x) {           // 定义:真正的实现
    return x * x;
}

Java 方法不用提前声明,因为编译器会扫整个类;C++ 的多文件工程全靠头文件里的声明互相认识——这就是上一课说 .hpp 放声明的原因。

讲清楚要点

  1. if 条件必须是布尔语境:if (score) 在 Java 里直接编译错误,在 C++ 里任何非零值都算真。整数当条件用是 C++ 世纪 bug 之源(if (x = 5) 是赋值且恒真)。好习惯:比较一律写 ==,编译时加 -Wall 让警告全开。
  2. 整型溢出是未定义行为:Java 的 int 溢出会安静回绕,C++ 的有符号整型溢出是 UB(Undefined Behavior)——编译器可以生成任何行为。算法题里两个 10^9 相乘必须换 long long。
  3. std::string 是值类型:std::string b = a; 会复制一份新字符串,两个对象互不影响;Java 的 String 是引用,赋值只是共享。想要 C++ 也共享,得用引用或指针(下一课)。
  4. 值传递 = 复制:函数参数默认按值复制。小对象无所谓,std::string、std::vector 这类大对象用 const T& 传参避免复制——这是 C++ 代码评审里最常见的意见。
  5. 初始化风格:现代 C++ 推荐花括号初始化 int x{42};,它能拦截窄化转换(int x{3.14} 直接报错,而 int x = 3.14 静默丢精度)。

你可能会懵的地方

  • int 到底多少字节? 标准只保证 int 至少 16 位,主流平台是 32 位。要确定性宽度用 <cstdint> 里的 int32_t、int64_t,判题沙箱计量字节数时全用定宽类型。

  • std::string 和 C 风格 char* 什么关系? std::string 内部管理一块字符内存,自动扩容、自动释放;char* 是裸指针,指向一块要自己管的生命周期。跟 C 库交互时才需要 s.c_str() 拿到 const char*。日常一律用 std::string。

  • 为什么 0.1 + 0.2 != 0.3? 和 Java 一样,浮点遵循 IEEE 754 二进制表示,十进制小数大多不能精确表示。浮点比较要写成 std::abs(a - b) < 1e-9,判题里「浮点答案误差容忍 1e-6」就是这个原理。

  • ++i 和 i++ 有区别吗? 结果一样,但 ++i 不产生临时对象,对迭代器(后面 STL 课会讲)有性能差异。C++ 圈的习惯是循环里都写 ++i。

  • C++ 有三元运算符之外更优雅的条件写法吗? C++17 if 初始化语句:if (int r = compute(); r > 60) { ... }——把临时变量的作用域锁死在 if 里,Java 没有这个能力。

错法对照

错法问题正解
if (x = 5)赋值表达式恒为真,逻辑悄悄跑偏if (x == 5),并开 -Wall 警告
for (int i = 0; i <= n; ++i) 配下标 n-1数组越界,UB循环边界用 i < n,多一次自测
char c = "A";双引号是字符串(指针),不是字符单引号 char c = 'A';
函数定义写在调用之后且无声明编译报错「未声明」先声明或调整定义顺序
大对象参数写 void f(std::vector<int> v)每次调用整体复制void f(const std::vector<int>& v)

卡点急救

  1. 程序「闪退」看不到输出:终端窗口运行而不是双击 exe;或在 return 0; 前加一行 std::cin.get(); 等待回车。
  2. 计算结果变成负数/巨大数:整型溢出。把相关变量改 long long,乘法前先 1LL * a * b 强制按 64 位算。
  3. switch 每个分支都执行了:漏了 break,分支发生贯穿。每个 case 结尾都写 break,唯一例外是故意贯穿并加注释说明。

面试常问

  • C++ 的值传递和引用传递有什么区别?什么时候用哪个? 值传递复制实参,函数内修改不影响外部,小对象用;引用传递是实参的别名,无复制开销,函数内修改会反映到外部,大对象只读用 const T&、需要修改用 T&。输出型参数现代 C++ 更倾向返回值或结构化对象。

  • 什么是有符号整型溢出?C++ 和 Java 行为一样吗? Java 规定 int 溢出按二进制回绕(补码环绕);C++ 把有符号溢出定义为未定义行为,编译器可基于「假设不溢出」做激进优化,导致结果不可预测。工程上用定宽类型并在关键计算前检查范围。

  • const 在 C++ 里有哪些用法? 修饰变量(不可修改,类似 Java final)、修饰指针(指向常量 / 指针本身常量)、修饰函数参数(承诺不修改)、修饰成员函数(承诺不改对象状态)。面试常考 const int* p(指向的值不可改)与 int* const p(指针本身不可改)的区别。

自测三问

  1. 为什么函数参数推荐 const std::string& 而不是 std::string?
  2. C++ 有符号整型溢出会发生什么?和 Java 的差异是什么?
  3. switch 里漏写 break 会发生什么?

小结一句话

C++ 基础语法和 Java 同源但更较真:类型是真实的内存布局、条件必须布尔、溢出是 UB、大对象传参用 const 引用——把这几个差异点刻进肌肉记忆,后面的路就顺了。

延伸

  • cppreference:C++ 语言基础
  • cplusplus.com:控制结构教程
  • 下一课:指针与引用——C++ 内存世界的钥匙。
加载本节练习…
← 上一课C++ 是什么下一课 →指针与引用