C/C++ 语言基础 (-std=c++14)
章节概要
- 程序结构
- 1.1 程序框架(注释、头文件、命名空间、
main、语句与语句块) - 1.2 选择结构(
if语句、switch语句、综合示例:闰年判定) - 1.3 循环结构(
while、do while、for、跳转控制、综合示例:阶乘) - 1.4
goto语句 - 1.5 C 与 C++ 的主要区别
- 数据类型
- 2.1 基本数据类型与 C++11 固定宽度整数类型
- 2.2 变量与常量、字面量后缀与数字分隔符 (C++14)
- 2.3 数组与字符串(一维/多维数组、寻址、越界警告)
- 2.4 指针(取地址、取值、常见操作)
- 2.5 引用
- 2.6 结构体
- 运算符
- 3.1 运算符优先级表
- 3.2 常用运算符的作用(算术、比较、位运算、逻辑、自增自减、赋值)
- 3.3 真值表
- 3.4 类型强制转换
- 函数
- 4.1 定义和使用函数(返回值、内联函数
inline) - 4.2 传递实参(按值传递、指针传递、引用传递)
- 4.3 Lambda 表达式(C++11/C++14 匿名函数、递归 Lambda)
- 输入和输出
- 5.1 标准输入/输出(
<cstdio>、格式字符、修饰符) - 5.2 流输入/输出(
<iostream>、<iomanip>、性能优化) - 库函数/宏定义
- 6.1 常用库函数(数组操作、字符处理、最值、交换、排序、计时、随机数、数学函数、
std::gcd/std::lcm) - 6.2 C++11/14 容器与算法便利特性(范围
for、auto、统一初始化、decltype、pair、nullptr) - 6.3 宏定义与
const/constexpr - 字符串操作
- 7.1 C 风格字符串处理函数(
<cstring>) - 7.2 格式化输入输出与 C++11
to_string() - 文件操作
- 8.1 输入/输出重定向 (
freopen) - 8.2 文件流 (
ifstream/ofstream) - 8.3 FILE 指针 (
fopen/fclose) - 简单的算法分析和优化
- 9.1 时间与空间复杂度
- 9.2 常用算法的时空复杂度与 C++14
constexpr - 9.3 简单的优化方法与原则
- 代码编辑器
- 10.1 Windows 平台
- 10.2 macOS 平台
- 10.3 Linux 平台
- 10.4 工具详解(小熊猫 C++、CP Editor)
- 10.5 竞赛选手推荐
- 10.6 编译器与标准
详细内容
1. 程序结构
第一个 C++ 程序
#include <iostream>
using namespace std;
int main() { // 程序入口
int a, b;
cin >> a >> b;
cout << a + b << "\n";
return 0;
}
1.1 程序框架
- 注释:有两种,一种是
//(必须单独一行或位于代码行后),另一种是/* … */(成对存在,可插入任意位置)。 - 引用头文件:使用
#include <头文件名>。引用自定义头文件时,尖括号(仅从系统目录搜索)需换成双引号(先从当前文件夹搜索,再到系统文件夹搜索)。 - 命名空间:许多 C++ 标准库组件依赖
std命名空间,因此常用using namespace std;。 main():所有程序从main()开始。在算法竞赛中,main()必须返回0,否则视为异常结束。- 语句和语句块:
- 语句:一般以分号
;结尾。 - 语句块:用
{和}包围的代码段,在语法上整体视为一条语句。
1.2 选择结构
if语句:cpp if (条件) { 语句或语句块 } else if (条件2) { 语句或语句块A } else { 语句或语句块B }-
switch语句:cpp switch (表达式) { case 值1: 代码段A; break; case 值2: 代码段B; break; default: 代码段N; break; }注意:不使用
break会导致程序顺序执行后面的case(即“穿透”现象),switch结尾必须有分号。 -
例:闰年判定 ```cpp #include using namespace std;
int main() { int year, month, day; bool b = false; cin >> year >> month >> day;
// 判断是否为闰年
if (year % 400 == 0)
b = true;
else if (year % 100 != 0 && year % 4 == 0)
b = true;
if (b)
cout << year << "是闰年。\n";
else
cout << year << "不是闰年。\n";
// 判断所在月份的天数
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 << "这个月有" << (b ? 29 : 28) << "天。\n"; break;
}
return 0;
} ```
1.3 循环结构
while语句:条件成立时循环。cpp while (条件) { 循环体; }do while语句:循环体至少执行一次。cpp do { 循环体; } while (条件);-
for语句:cpp for (初始条件; 继续循环条件; 状态转移条件) { 循环体; }在循环内使用
break可跳出当前循环,continue可跳过当前轮次剩余代码。 -
例:求多个数的阶乘值 ```cpp #include using namespace std;
int main() { int n; long long r = 1; cin >> n; while (n > -1) { r = 1; for (int i = 1; i <= n; i++) { r *= i; } cout << n << "! = " << r << "\n"; cin >> n; } return 0; } ```
1.4 goto 语句
用于无条件跳转,通常用于从多层嵌套循环中直接跳出:
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (满足某种条件) goto __exited;
}
}
__exited:
1.5 C 与 C++ 的重要区别
- C++ 支持流式输入输出(
cin/cout),C 语言主要依赖scanf/printf。 - C++ 支持面向对象编程及强大的
string类。 - C++ 拥有功能强大的 STL(标准模板库)。
- C 的头文件在 C++ 中应去掉
.h并以c开头(如<stdio.h>改为<cstdio>)。 - C 程序运行速度在极微观层面上通常略优于 C++。
2. 数据类型
2.1 基本数据类型
| 名称 | 占用空间(字节) | 数据范围 |
|---|---|---|
int |
4 | $-2,147,483,648 \sim 2,147,483,647$ |
unsigned int |
4 | $0 \sim 4,294,967,295$ |
char |
1 | $-128 \sim 127$ |
unsigned char |
1 | $0 \sim 255$ |
short |
2 | $-32,768 \sim 32,767$ |
unsigned short |
2 | $0 \sim 65,535$ |
long long |
8 | $-9,223,372,036,854,775,808 \sim 9,223,372,036,854,775,807$ |
unsigned long long |
8 | $0 \sim 18,446,744,073,709,551,615$ |
bool |
1 | true 或 false |
float |
4 | $3.4E\pm38$ (7位有效数字) |
double |
8 | $1.7E\pm308$ (15位有效数字) |
C++11 固定宽度整数类型(头文件 <cstdint>):
- int8_t / uint8_t、int16_t / uint16_t、int32_t / uint32_t、int64_t / uint64_t。竞赛中推荐使用 int64_t 替代 long long。
2.2 变量与常量、C++14 新特性
- 变量定义:
变量类型 标识符;(未初始化时值不确定)。 - 常量定义:
const 变量类型 标识符 = 初始值; - C++11/14 字面量与分隔符:
- 整数字面量后缀:
123LL、123ULL。 - 二进制字面量 (C++14):
0b1010(十进制 10)。 - 数字分隔符 (C++14):
123'456'789等价于123456789。
2.3 数组与字符串
- 一维数组:
int a[10];下标范围0 ~ 9。 - 二维数组:
int b[5][3]; - 字符串:以
'\0'结尾的char数组。数组不能整体赋值,需借助memcpy或strcpy。 - 警告:C++ 不检查数组下标越界,越界会导致程序崩溃或未定义行为。
2.4 指针
&:取地址运算符。*:取值运算符。- 示例:
cpp int a = 0, b = 1; int *p = &a; // p指向a *p = 3; // a变为3 p = &b; // p指向b p = nullptr; // C++11空指针
2.5 引用
引用是变量的别名,创建时必须初始化,且初始化后不可更改绑定对象:
int x = 10;
int &p = x; // p 是 x 的引用
p = 20; // x 变为 20
2.6 结构体
struct pack {
int value, weight;
};
pack p; // 定义结构体变量
p.value = 10;
3. 运算符
3.1 运算符优先级(自上而下优先级递减)
::.->[]()++--sizeof!~+-(一元)*&*/%+-<<>><<=>>===!=&^|&&||?:(条件运算符)=+=-=等赋值运算符
3.2 常用运算符要点
- 除法:整数除以整数结果仍为整数(截断小数)。
- 浮点数比较:严禁直接用
==,应设定精度const double eps = 1e-6; if (abs(a - b) < eps)。 - 位运算:
&,|,^,~,<<,>>。a << n相当于 $a \times 2^n$。 - 短路求值:
&&,||,?:具有短路特性,避免在其中放置带副作用的函数调用。
4. 函数
4.1 定义和使用
inline int square(int x) {
return x * x;
}
inline(内联函数)建议编译器在调用点展开代码以减少函数调用的开销。
4.2 传递实参
- 按值传递:传递副本,函数内修改不影响外部变量。
- 传递指针:通过地址修改外部变量。
- 传递引用:
int foo(int &n),既能直接修改外部变量,又免去了指针的繁琐语法。
4.3 Lambda 表达式 (C++11/14)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> v = {3, 1, 4, 1, 5};
// 示例1:自定义排序降序
sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
// 示例2:捕获外部变量
int threshold = 2;
auto cnt = count_if(v.begin(), v.end(), [threshold](int x) { return x > threshold; });
// 示例3:递归 Lambda (C++14 万能引用)
auto dfs = [&](auto&& self, int u, int fa) -> void {
for (int v_node : v) {
// 递归逻辑
}
};
return 0;
}
5. 输入和输出
5.1 标准输入/输出 (<cstdio>)
#include <cstdio>
using namespace std;
int main() {
int n;
scanf("%d", &n);
printf("n = %05d\n", n); // 5位数,右对齐,不足补0
return 0;
}
5.2 流输入/输出 (<iostream>)
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
// 开启流加速
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
cout << "Value: " << n << "\n";
return 0;
}
6. 库函数/宏定义
6.1 常用库函数
- 内存操作 (
<cstring>):memset(a, 0, sizeof(a));、memcpy(b, a, sizeof(a)); - 算法 (
<algorithm>):sort(begin, end)、reverse(begin, end)、max()、min()、swap() - C++17 数值 (
<numeric>):std::gcd(12, 18)、std::lcm(12, 18) - 随机数 (
<random>):推荐使用 C++11 的std::mt19937。
#include <random>
#include <chrono>
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<int> dist(1, 100);
int random_val = dist(rng); // 生成 [1, 100] 随机数
6.2 C++11/14 容器与算法便利特性
- 范围
for循环:cpp vector<int> v = {1, 2, 3}; for (const auto& x : v) { cout << x << " "; } auto与decltype类型推导- 结构化绑定 (C++17):
auto [x, y] = make_pair(1, 2); - 空指针
nullptr
6.3 宏定义与 const/constexpr
建议在 C++ 中尽量弃用 #define 常量和宏函数,改用 const、constexpr 以及 inline 函数以保证类型安全:
constexpr int N = 5000;
constexpr int SQUARE(int x) { return x * x; }
7. 字符串操作
头文件:<cstring>。printf 和 scanf 在 <cstdio> 中,cin 和 cout 在头文件 <iostream> 中且位于 std 命名空间内。
假设待处理的字符串为 str 和 str2,即:char str[MAX], str2[MAX];
- 注意事项:字符串的最后一个字符一定是
'\0'。如果字符串内没有'\0',进行输出等操作时可能会造成严重错误。 - 输出字符串
str:cpp cout << str; printf("%s", str); // 输出到文件:fprintf(fout, "%s", str); - 输入字符串
str:cpp scanf("%s", str); // 输出到文件:fscanf(fin, "%s", str); cin >> str;以上两种方法在输入时会忽略空格、回车、TAB 等字符,并且在一个或多个非空格字符后面输入空格时,会终止输入。
cpp
fgets(str, MAX, fin);
每调用一次,就会读取一行的内容(即不断读取,直到遇到回车停止)。
- 求字符串长度:
strlen(str)(不包括末尾的'\0')。 - 连接字符串:
strcat(str, str2)(将str2连接到str末尾,str空间必须足够大)。strncat(str, str2, n)表示连接前 $n$ 个字符。 - 复制字符串:
strcpy(str, str2)。 - 比较字符串:
strcmp(str, str2)(若 $\text{str} > \text{str2}$ 返回1,相等返回0,小于返回-1)。 - 查找字符/子串:
strchr(str, c):返回字符c第一次出现位置的指针。strstr(str, str2):返回子串str2第一次出现位置的指针。- 数值与字符串转换:
sscanf(str, "%d", &i);/sprintf(str, "%d", i);- C++11 便利函数:
to_string()(头文件<string>或<iostream>)cpp string s = to_string(123); // s = "123" string s2 = to_string(3.14159); // s2 = "3.141590" - C++17 引入
std::string_view(头文件<string_view>),支持零拷贝访问字符串,适合作为只读字符串参数类型。
8. 文件操作
在 OJ(Online Judge)中通常不需要文件操作,但在正式竞赛中,数据多从 .in 文件读入,结果需输出到 .out 文件。
8.1 输入/输出重定向
头文件:<fstream> 或 <cstdio>
freopen("XXXXX.in", "r", stdin);
freopen("XXXXX.out", "w", stdout);
调用两次
freopen后,scanf、printf、cin、cout用法完全不变,操作对象自动变更为指定文件。注意重定向后屏幕键盘输入将失效。
8.2 文件流
头文件:<fstream>
ifstream fin("XXXXX.in");
ofstream fout("XXXXX.out");
fin >> a;
fout << b;
也可以通过 #define cin fin 和 #define cout fout 简化代码。
8.3 FILE 指针
头文件:<cstdio> 或 <fstream>
FILE *fin, *fout;
int main() {
fin = fopen("XXXXX.in", "r");
fout = fopen("XXXXX.out", "w");
fprintf(fout, "%d", ans);
fclose(fin);
fclose(fclose); // 竞赛中切记关闭文件
return 0;
}
9. 简单的算法分析和优化
9.1 复杂度
- 时间复杂度:算法主要运算次数的数量级,用大 $O$ 表示。保留最大项并忽略系数。
- 空间复杂度:算法执行时主要占用的内存空间大小。
9.2 常用算法的时空复杂度
1秒内计算机大约能执行 $5,000,000$ 次基本运算。
| 数量级 | 能承受的大致规模 | 常见算法 |
|---|---|---|
| $O(1)$ | 任意 | 直接输出结果 |
| $O(\log n)$ | 任意 | 二分查找、快速幂 |
| $O(n)$ | 以百万计 | 贪心、扫描遍历 |
| $O(n \log n)$ | 以十万计 | 排序、分治 |
| $O(n^2)$ | 以千计数 | 简单枚举、双重循环 DP |
| $O(n^3)$ | 不到两百 | 三重循环 DP |
| $O(2^n)$ | $24$ 左右 | 递归搜索 |
| $O(n!)$ | $10$ 左右 | 全排列 |
- C++11/14:
constexpr编译时常量与函数cpp constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1); } constexpr int N = factorial(5); // 编译时完成计算C++14 放宽了限制,constexpr函数中允许使用循环、条件判断等。
9.3 简单的优化方法
- 时间优化:
- 整型运算远快于浮点型。
- 位运算速度极快。
- 除法
%和/运算非常耗时。 - 减少不必要的函数调用(可考虑
inline)。 - 空间优化:
- 压缩存储、合理开辟数组大小。
- 使用滚动数组优化空间复杂度。
- 优化原则:不重复计算、不做无用功、不解决无用子问题。
10. 代码编辑器
10.1 Windows 平台
| 名称 | 编辑器体验 | 编译器 | 调试功能 | 单文件编译 | 适合人群 |
|---|---|---|---|---|---|
| 小熊猫 C++ (RedPanda) | 好 | MinGW(内置) | 好 | ✓ | 信奥初学者首选,专为 OI 设计 |
| Dev-C++ | 一般 | MinGW(自带) | 差 | ✓ | 初学者(已停止更新,不推荐) |
| Code::Blocks | 好 | 需自行安装 | 好 | ✓ | 进阶选手,跨平台 |
| CP Editor | 好 | 需自行安装 | 好(需配置) | ✓ | 竞赛专业户,自动获取样例/测试 |
| VS Code | 极好 | 需自行安装 | 好(需配置) | ✓ | 进阶选手 |
| CLion | 极好 | 自带 | 极好 | ✓ | 专业选手(付费/教育免费) |
| Visual Studio | 好 | MSVC(自带) | 极好 | ✗ | Windows 专业开发 |
10.2 macOS 平台
| 名称 | 编辑器体验 | 编译器 | 调试功能 | 单文件编译 | 适合人群 |
|---|---|---|---|---|---|
| 小熊猫 C++ (RedPanda) | 好 | 内置 | 好 | ✓ | macOS 信奥首选,开箱即用 |
| Code::Blocks | 好 | 需自行安装(Xcode Clang) | 好 | ✓ | 跨平台用户 |
| CP Editor | 好 | 需自行安装 | 好(需配置) | ✓ | 竞赛专用,功能强大 |
| Xcode | 好 | Clang(自带) | 极好 | ✓ | Apple 官方工具,偏重,不适合竞赛 |
| VS Code | 极好 | 需自行安装 | 好(需配置) | ✓ | 进阶选手 |
10.3 Linux 平台
| 名称 | 编辑器体验 | 编译器 | 调试功能 | 单文件编译 | 适合人群 |
|---|---|---|---|---|---|
| 小熊猫 C++ | 好 | 内置 | 好 | ✓ | 新手友好,开箱即用 |
| CP Editor | 好 | 系统 GCC | 好 | ✓ | 竞赛神器,强烈推荐 |
| Code::Blocks | 好 | 系统 GCC | 好 | ✓ | 经典选择 |
| VS Code | 极好 | 系统 GCC | 好(需配置) | ✓ | 进阶选手 |
| 终端 + g++ | 无 | GCC(系统自带) | gdb | ✓ | 高手/赛前模拟 |
| Vim / Emacs | 极好(需学习) | 系统 GCC | gdb | ✓ | 资深选手 |
10.4 工具详解
- 小熊猫 C++ (RedPanda C++):专为信息学竞赛(NOI 系列赛事)打造的轻量级 IDE,基于 Dev-C++ 深度优化。开箱即用(内置 MinGW),原生支持中文字符,界面现代。
- CP Editor:专为算法竞赛设计的开源跨平台 IDE。自动爬取样例数据,一键编译运行并比对,大幅提升刷题效率。
10.5 竞赛选手推荐
- 初学阶段:小熊猫 C++(专为 OI 设计,开箱即用,免去环境配置烦恼)。
- 进阶/刷题阶段:CP Editor(自动处理样例测试,刷题神器)。
- 赛前适应:终端命令行 +
g++(提前适应比赛评测环境)。
10.6 编译器与标准
- 编译器:竞赛通常使用 GCC(
g++)。 - C++ 标准:NOIP / NOI 系列竞赛统一支持
-std=c++14(部分赛事已支持 C++17),请严格按 C++14 标准编写代码。 - 命令行编译示例:
bash g++ -std=c++14 -O2 -o program program.cpp
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com