火龙信奥
  • 首页
  • 课程
  • 题库
  • 打卡
    • 代码对战
    • 快速对战
  • 题单
  • 团队
  • 荣誉墙
  • 商城
  • 登录 / 注册

语言基础 C++14

作者: 作者的头像   huolong , 时间:2026-08-07 18:51:26 , 所有人可见, 阅读  10

C/C++ 语言基础讲义(-std=c++14)

1. 程序结构与控制流程

1.1 程序框架

#include <iostream>
using namespace std;

int main() {                 // 程序入口
    int a, b;
    cin >> a >> b;
    cout << a + b << "\n";
    return 0;
}
  • 注释有 // 与 /* ... */ 两种形式;前者用于单行或行尾,后者必须成对出现。
  • 使用系统头文件写作 #include <头文件名>;自己的头文件使用双引号,先在当前目录搜索。
  • 流、容器和算法通常位于 std 命名空间,原文示例使用 using namespace std;。
  • 程序从 main() 开始;竞赛程序应以 return 0; 正常结束。
  • 语句通常以分号结束;由 {} 包围的语句块整体也视为一条语句。

1.2 选择结构

if 在条件为真时执行后续语句或语句块,否则执行 else 分支(如存在)。

if (condition) {
    // A
} else if (anotherCondition) {
    // B
} else {
    // C
}

switch 根据表达式的值选择 case。default 可省略;若漏写 break,会继续执行后续 case,直到遇到 break 或 switch 结束。原文强调:switch 结束后有分号。

switch (month) {
    case 1: case 3: case 5: case 7: case 8: case 10: case 12:
        cout << "这个月有 31 天。\n";
        break;
    case 4: case 6: case 9: case 11:
        cout << "这个月有 30 天。\n";
        break;
    case 2:
        cout << "这个月有 " << (leap ? 29 : 28) << " 天。\n";
        break;
    default:
        break;
};

闰年规则:能被 400 整除,或能被 4 整除但不能被 100 整除。

1.3 循环结构

while (condition) {
    // 循环体
}

do {
    // 循环体至少执行一次
} while (condition);

for (initialization; condition; update) {
    // 循环体
}

for 可等价改写为初始化后执行 while,每轮末尾执行状态转移。三个表达式可以省略,但两个分号必须保留。

  • break 跳出当前层循环;continue 跳过本轮余下代码,进入下一轮;二者只影响所在的一层循环。
  • 写循环时重点检查计数变量、边界使用 </<= 等,以及逆序循环的 --。
int n;
long long result;
cin >> n;
while (n > -1) {
    result = 1;
    for (int i = 1; i <= n; ++i) result *= i;
    cout << n << "! = " << result << "\n";
    cin >> n;
}

1.4 goto 与 C/C++ 差异

goto 可跳至标签,原文给出其跳出多层循环的用途;但它会破坏程序结构,通常不提倡使用。

for (int i = 0; i < 9; ++i)
    for (int j = 0; j < 9; ++j)
        for (int k = 0; k < 9; ++k)
            if (/* 满足条件 */) goto exited;
exited:

竞赛中 C 与 C++ 的主要差异:C++ 支持流输入输出、面向对象、string 与 STL;C 的头文件在 C++ 中宜改为如 <cstdio> 而非 <stdio.h>。

2. 数据类型与复合数据

2.1 基本数据类型、变量和常量

常用整型包括 int(通常 4 字节)、long long(8 字节)及其无符号形式;char 通常 1 字节,bool 表示 true/false;float、double 分别约有 7 位、15 位有效数字。对固定宽度有要求时,可包含 <cstdint> 并使用 int8_t、int16_t、int32_t、int64_t 等;原文推荐竞赛中以 int64_t 代替 long long,以保证位宽一致。

变量定义形式为“类型 + 标识符”,未初始化的局部变量值不确定。常量可使用:

const int N = 90;
long long x = 123'456'789'012LL;  // C++14 数字分隔符
int y = 0b1010'1010;              // C++14 二进制字面量,值为 170

标识符只能包含字母、数字、下划线,不能以数字开头,不能与关键字冲突,必须先定义后使用;C++ 区分大小写。

2.2 数组与 C 风格字符串

int a[10];
int b[5][3];
  • 数组下标从 0 开始,a[10] 的最后一个元素是 a[9]。
  • 多维数组本质是数组的数组,内存中元素连续存放;原文建议竞赛中尽量回避复杂的指针算术。
  • C++ 不会检查数组越界,越界可能导致崩溃或错误结果。
  • C 风格字符串是 char 数组,末尾必须有空字符 \0。
  • 原生数组和 C 风格字符串不能直接整体赋值、比较;分别使用 memcpy/memcmp 或 strcpy/strcmp。

2.3 指针、引用与结构体

& 取变量地址,* 取得指针所指向的值。未初始化的指针指向未知位置,错误解引用可能崩溃。

int a = 0, b = 1;
int c[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int* p = &a;
*p = 3;
p = &b;
p = c + 6;
cout << *p;       // c[6]
p = nullptr;      // C++11,替代 NULL/0,更类型安全

引用是变量别名:创建时必须初始化并关联合法存储单元,之后不能改变绑定关系;指针则可以改指向。引用适合在函数参数中直接修改实参。

int& ref = b[0][2];

struct Pack {
    int value, weight;
};

结构体成员通过 . 访问,结构体指针通过 -> 访问;C++ 中结构体可定义构造函数、成员函数和运算符重载。

3. 运算符与类型转换

  • 算术运算符:+ - * / %。整数除法会直接截断小数部分;C++ 没有乘方运算符,^ 是按位异或。
  • 比较运算符:> >= < <= == !=,结果为布尔值。警惕把 == 错写成 =。
  • 不应直接以 ==/!= 比较浮点数,应给定精度范围:
const double eps = 0.000001;
if (d >= 2 - eps && d <= 2 + eps) {
    // 近似等于 2
}
  • 位运算:& | ^ ~ << >> 分别表示按位与、或、异或、取反、左移、右移。原文将移位类比为乘、除以 2^n,使用时需注意位运算语义和边界。
  • 逻辑运算:&& || !;条件运算符为 A ? B : C。||、&&、?: 具有短路性质,避免在其中做函数调用或赋值等有副作用的操作。
  • 前缀 ++i 先改变再取值,后缀 i++ 先取值再改变;不要在同一行混用自增、自减与其他修改变量的操作。
  • 比较、位移、逻辑、条件运算符优先级较低,必要时多加括号。
int i = 0, j = 8, k = 5;
j = j + (++i);  // i=1, j=9
k = k + (i++);  // k=6, 随后 i=2

double value = 6.4 / static_cast<double>(i);

原文以 C 风格强制转换说明类型转换;在 C++ 中也可采用 static_cast<double>(i) 表达目标类型。

4. 函数与 Lambda 表达式

4.1 函数和参数传递

double foo(int i, float j) {
    // ...
    return 0.0;
}

函数若无返回值使用 void。定义应在调用前,或预先写函数声明。函数返回指针或引用时,不能返回函数内部局部变量的地址/引用;可使用静态变量或全局变量等合法对象。

  • 按值传递会复制参数,函数内修改不影响实参;大数组复制代价高。
  • 指针传递可修改实参,修改其指向的值需要解引用。
  • 引用传递可直接修改实参,且无指针解引用的书写负担,但不能传入常量或表达式。
  • 短小函数可用 inline 提示编译器内联展开。

4.2 Lambda(C++11/14)

基本形式:[捕获列表](参数列表) -> 返回类型 { 函数体 },常用于 STL 算法和排序比较器。

vector<int> v = {3, 1, 4, 1, 5};
sort(v.begin(), v.end(), [](int a, int b) { return a > b; });

int threshold = 3;
auto count = count_if(v.begin(), v.end(),
    [threshold](int x) { return x > threshold; });

常见捕获:[] 不捕获;[x] 按值捕获;[&x] 按引用捕获;[=] 默认按值;[&] 默认按引用;也可混合使用。

C++14 可用泛型 Lambda 递归,原文示例如下:

auto dfs = [&](auto&& self, int u, int parent) -> void {
    for (int v : graph[u]) {
        if (v != parent) self(self, v, u);
    }
};
dfs(dfs, 1, 0);

5. 输入与输出

5.1 C 标准输入输出

<cstdio> 提供 printf、scanf、fprintf、fscanf 等。常见格式字符:%d(整数)、%u(无符号整数)、%f(浮点)、%e/%E(科学计数法)、%c(字符)、%s(字符数组)、%o(八进制)、%x/%X(十六进制)。

  • %5d 右对齐并占 5 位,%-5d 左对齐,%05d 用 0 补齐,%.2f 保留两位小数。
  • scanf/fscanf 传入变量地址,勿遗漏 &(字符数组除外)。返回值是成功读入的变量个数;fscanf 返回 EOF 表示文件结束。
  • 这些格式化读取默认忽略空格、制表符、换行;读取单个字符时可使用 fgetc 并判断 EOF。

5.2 C++ 流输入输出

<iostream> 提供 cin、cout,可链式读写,换行常用 "\n"。<iomanip> 可配合 width、fill 格式化输出;oct、hex 可输出八进制、十六进制。

大数据量下,原文建议在输入输出前关闭 C/C++ 流同步:

ios::sync_with_stdio(false);

6. 库函数、C++11/14 特性与宏

6.1 常用库函数

  • <cstring>:memset(a, 0, sizeof(a)) 初始化数组;memcpy 复制;memcmp 比较。memset 按字节填充,原文特别说明填 0x7F 后 int 元素为 0x7F7F7F7F。
  • <cctype>:tolower、toupper,以及 isdigit、isalpha、isupper、islower、isalnum 等字符判定。
  • <algorithm>:max、min、swap、sort(begin, end)、sort(begin, end, cmp)、reverse(begin, end);排序区间采用半开区间 [begin, end)。
  • <cstdlib>:exit(0) 立即结束程序,调用前应已输出结果。
  • <ctime>:clock() 可用于记录时间点并计算时间间隔。
  • <cassert>:assert(condition) 在条件为假时使程序中止,用于发现代码错误,而非处理用户输入错误。
  • <random> 与 <chrono>:原文建议不用分布不均、周期较短的 rand(),改用 mt19937 与分布对象。
#include <random>
#include <chrono>
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<int> dist(0, 99);
int r = dist(rng);
  • <cmath>:abs、三角函数、sqrt、ceil、floor、exp、log、log10、pow、fmod。pow 有精度问题,整数幂场景仍应掌握快速幂。

6.2 容器与算法便利特性

vector<int> v = {1, 2, 3, 4, 5};
for (int x : v) cout << x << ' ';       // 只读副本
for (int& x : v) x *= 2;                // 修改元素
for (const auto& x : v) cout << x;      // 避免复制且只读,推荐

auto a = 5;
decltype(a) b = 5;
pair<int, string> p = {1, "apple"};
int* ptr = nullptr;
  • 范围 for 是 C++11 特性;const auto& 可避免复制大型元素并防止意外修改。
  • auto 从初始化表达式推导类型;decltype 从已有变量或表达式推导类型。
  • 统一初始化可写作 int x{5};、vector<int> v{1, 2, 3};。
  • pair 位于 <utility>;nullptr 是类型安全的空指针。

6.3 宏与 const/constexpr

宏是预处理阶段的文本替换。条件编译如 #ifdef DEBUG 是原文认可的少数合理用途之一。表达式宏应给参数和整体加括号,但原文明确建议:常量优先用 const/constexpr,类函数宏优先用 inline,竞赛中不要定义影响可读性的复杂宏。

constexpr int MAXN = 100000;
constexpr int square(int x) { return x * x; }

constexpr int fib(int n) {
    int a = 0, b = 1;
    for (int i = 0; i < n; ++i) { // C++14 允许 constexpr 中使用循环
        int t = a + b;
        a = b;
        b = t;
    }
    return a;
}

const 可以在运行时或编译时初始化;constexpr 必须能在编译时求值,可用于数组大小和编译时计算。其优势包括类型检查、作用域与可调试性。

7. 字符串操作

本章主要讨论 C 风格字符串,使用 <cstring>。始终保证字符数组末尾有 \0。

目的 函数/方式 要点
输出/读取 cout << str、printf("%s", str)、scanf("%s", str)、cin >> str 后两类读到空白即停止
读取整行 fgets(str, MAX, fin) 读取到换行停止
长度 strlen(str) 不计末尾 \0
拼接 strcat、strncat 目标数组必须有足够空间
复制/比较 strcpy、strcmp strcmp 按字典序比较
查找 strchr、strstr 返回指针,可减去 str 得索引
格式转换 sscanf、sprintf、to_string 可在数值与字符串间转换

原文提及 strstr 的更复杂问题可用 KMP 算法处理;并给出 C++11 的 to_string 作为便利函数。

8. 文件操作

正式比赛是否读写文件必须以题目说明为准;在线评测通常不需要文件操作。

// 重定向标准输入输出
freopen("XXXXX.in", "r", stdin);
freopen("XXXXX.out", "w", stdout);

// 文件流
ifstream fin("XXXXX.in");
ofstream fout("XXXXX.out");
fin >> a;
fout << b;

// FILE 指针
FILE* fin = fopen("XXXXX.in", "r");
FILE* fout = fopen("XXXXX.out", "w");
fprintf(fout, "%d", ans);
fclose(fin);
fclose(fout);

使用 FILE* 时,fprintf、fscanf、fgets 的首个参数是文件指针。若要改回屏幕输入输出,可将 fin、fout 设为 stdin、stdout。

9. 算法分析与优化

9.1 时间与空间复杂度

时间复杂度表示主要运算次数,用大 O 表示,只保留最高数量级并忽略常数系数;空间复杂度表示主要内存占用,同样用大 O 表示。多个输入规模都会显著影响运行时间时,应同时写入表达式,例如遍历 m × n 数组为 O(mn)。

原文给出 1 秒大致可承受约 5,000,000 次运算的经验估计,并列出增长趋势:

O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(n³) < O(2ⁿ) < O(n!)

对应的大致适用规模:O(n) 可达数百万,O(n log n) 可达数十万,O(n²) 通常约数千,O(2ⁿ) 常在 24 左右,O(n!) 常在 10 左右。实际可承受规模依机器、常数和实现而变化。

9.2 简单优化原则

  • 时间:少做运算,尤其减少循环体、递归体内的工作;原文指出整型通常比实型快,位运算快,除法和取模相对慢,函数调用有额外开销。
  • 空间:缩小数组、降低维数,使用压缩存储或覆盖旧数据(如滚动数组)。
  • 原则:不重复做已完成的事;不做显然无必要的事;不解决无用子问题;不做无意义引用。

10. 编辑器、编译器与标准

原文按 Windows、macOS、Linux 列举了小熊猫 C++(RedPanda)、Code::Blocks、CP Editor、VS Code、CLion、Visual Studio、Xcode、终端与 Vim/Emacs 等工具,核心建议如下:

  • 初学者可选择面向 OI、开箱即用的工具;进阶刷题可使用便于样例测试的竞赛编辑器。
  • 赛前应熟悉命令行与 g++,许多竞赛评测环境为 Linux 命令行。
  • 竞赛通常使用 GCC(g++);NOIP/NOI 系列常使用 -std=c++14,部分环境支持 C++17,应按指定标准编写。
g++ -std=c++14 -O2 -o program program.cpp

复习清单

  1. 能写出包含头文件、main、输入输出和正常返回的基本程序。
  2. 能正确选择 if、switch、三种循环,并控制循环边界。
  3. 避免数组越界、未初始化指针、返回局部变量引用/地址、浮点直接相等比较。
  4. 理解值、指针、引用三种传参方式的影响。
  5. 熟练使用 sort、范围 for、auto、nullptr、Lambda 及 C++14 的 constexpr。
  6. 根据数据范围估算时间/空间复杂度,选择可承受的算法。

—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com

关于火龙

  • 关于我们
  • 预约试听
  • ACM课程
  • CSP课程
  • 学习指南

帮助中心

  • 用户协议
  • 打字练习
  • 在线画图
  • DevC++下载
  • CSP报名
  • GESP官网

推荐课程

  • C++零基础入门(可试看)
  • C++进阶提升
  • GESP考级辅导
  • GESP打卡
  • CSP-J/S打卡

公众号

火龙信奥公众号二维码

抖音号

火龙信奥抖音号二维码

地址:义乌市北门街188号新天地商厦二楼2F 邮箱:wdlok305@126.com

© 2017-2026 义乌市睿码科技有限公司版权所有 浙ICP备2021013995号

火龙信奥
请输入登录信息


请完成安全验证
验证码底图 滑块
向右拖动滑块完成验证
请输入用户名 / 绑定的手机号码



请输入注册信息(手机号验证码注册)





验证码5分钟有效,60秒内不可重复获取,每日最多3次

微信登录

微信登录二维码

正在生成二维码...

账号已过期,请续期。
去续期

绑定手机号

📱

为了更好地保护您的账号安全,享受完整的平台服务

请您尽快绑定手机号码