C++ 基础教程

从零开始,系统学习 C++ 编程核心知识

开始学习 前往题库

C++ 简介

什么是 C++?

C++ 是一种通用编程语言,由 Bjarne Stroustrup 于 1979 年在贝尔实验室开发。它是 C 语言的扩展,增加了面向对象编程(OOP)、泛型编程等特性。

C++ 的特点
  • 高效性:C++ 编译后的代码执行效率极高,接近 C 语言
  • 面向对象:支持封装、继承、多态等面向对象特性
  • 跨平台:可以在多种操作系统上编译运行
  • 丰富的标准库:STL(标准模板库)提供了大量实用的数据结构和算法
C++ 是信息学奥林匹克竞赛(NOI/CSP/JSOI)的指定语言,也是 CCF GESP、蓝桥杯等编程竞赛的主要语言。

C++ 程序的开发流程

  1. 编写代码:使用文本编辑器或 IDE 编写 C++ 源代码(.cpp 文件)
  2. 预处理:处理 #include、#define 等预处理指令
  3. 编译:将源代码编译成目标代码(.obj 或 .o 文件)
  4. 链接:将目标代码与库文件链接成可执行文件
  5. 运行:执行生成的可执行文件

语法基础

第一个 C++ 程序

让我们从一个经典的 "Hello World" 程序开始:

#include <iostream>

int main() {
    std::cout << "Hello World" << std::endl;
    return 0;
}
程序解析
  • #include <iostream>:包含输入输出流头文件,使我们可以使用 cin 和 cout
  • int main():主函数,程序的入口点
  • std::cout:标准输出流对象,用于向屏幕输出内容
  • <<:插入运算符,将右侧的内容发送到左侧的流
  • std::endl:换行符,输出后换行并刷新缓冲区
  • return 0;:返回 0 表示程序正常结束
std 是标准命名空间,coutendl 都定义在这个命名空间中。使用 using namespace std; 可以省略 std:: 前缀。

注释

注释用于解释代码,不会被编译器执行。良好的注释习惯是编程的基本素养。

单行注释
// 这是单行注释,从 // 开始到行末都是注释
int a = 10;  // 也可以放在代码后面
多行注释
/*
   这是多行注释
   可以跨越多行
   用于较长的说明
*/

输入输出

C++ 提供了两种主要的输入输出方式:

cin 和 cout(C++ 风格)
#include <iostream>
using namespace std;

int main() {
    int x, y;
    cin >> x >> y;           // 读入 x 和 y
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "x + y = " << x + y << endl;
    return 0;
}
scanf 和 printf(C 风格)
#include <cstdio>

int main() {
    int x, y;
    scanf("%d%d", &x, &y);   // 读入 x 和 y
    printf("x = %d\n", x);
    printf("y = %d\n", y);
    printf("x + y = %d\n", x + y);
    return 0;
}
格式控制符
格式符说明示例
%d有符号整数printf("%d", 42);
%lld长整型 (long long)printf("%lld", n);
%f浮点数printf("%f", 3.14);
%lf双精度浮点数printf("%lf", 3.14);
%c字符printf("%c", 'A');
%s字符串printf("%s", "hello");
%.2f保留2位小数printf("%.2f", 3.14159);
在竞赛编程中,scanfprintf 通常比 cincout 更快,适合处理大量数据。

#include 指令

#include 是预处理指令,用于包含头文件:

头文件功能
<iostream>输入输出流 (cin, cout)
<cstdio>C 标准输入输出 (scanf, printf)
<cmath>数学函数 (sqrt, pow, sin 等)
<string>字符串类 string
<vector>动态数组 vector
<algorithm>算法库 (sort, max, min 等)
<cstring>C 字符串操作 (strlen, strcpy 等)

#define 宏定义

#define 用于定义宏,本质是文本替换:

#include <iostream>
using namespace std;

#define PI 3.14159265
#define MAX_SIZE 1000
#define SQUARE(x) ((x) * (x))

int main() {
    cout << "PI = " << PI << endl;
    cout << "MAX_SIZE = " << MAX_SIZE << endl;
    cout << "5的平方 = " << SQUARE(5) << endl;
    return 0;
}
宏定义是简单的文本替换,使用时要小心。例如 SQUARE(1+2) 会展开为 ((1+2) * (1+2)),如果没有括号保护,结果可能出错。

变量与数据类型

什么是变量?

变量是程序中用于存储数据的容器。每个变量都有:

  • 名称:用于标识变量的标识符
  • 类型:决定了变量可以存储什么类型的数据
  • :变量中存储的实际数据
  • 地址:变量在内存中的位置

基本数据类型

整型
类型字节数范围说明
int4-2,147,483,648 ~ 2,147,483,647最常用的整型
long long8-9.2×10¹⁸ ~ 9.2×10¹⁸大整数
short2-32,768 ~ 32,767短整型
unsigned int40 ~ 4,294,967,295无符号整型
unsigned long long80 ~ 1.8×10¹⁹无符号长整型
浮点型
类型字节数有效数字说明
float4约 7 位单精度浮点数
double8约 15 位双精度浮点数(推荐)
字符型和布尔型
类型字节数范围/值说明
char1-128 ~ 127 或 0 ~ 255字符型
bool1true / false布尔型
在竞赛中,intlong long 是最常用的整型。当数值可能超过 2×10⁹ 时,应使用 long long

变量声明与初始化

// 声明变量
int a;              // 声明一个整型变量 a
double x, y;        // 声明两个双精度浮点变量

// 初始化变量
int b = 10;         // 声明并初始化
int c(20);          // 构造函数初始化
int d{30};          // C++11 列表初始化(推荐)

// 多变量声明和初始化
int e = 1, f = 2, g = 3;

// 使用 auto 自动推导类型(C++11)
auto num = 100;     // num 是 int 类型
auto pi = 3.14;     // pi 是 double 类型
局部变量如果不初始化,其值是未定义的(可能是任意值)。全局变量和静态变量会自动初始化为 0。建议始终初始化变量!

变量命名规则

  • 只能包含字母、数字和下划线
  • 必须以字母或下划线开头
  • 不能使用 C++ 关键字(如 int, if, for, while 等)
  • 区分大小写(sumSum 是不同的变量)
命名规范建议
// 好的命名
int studentCount;      // 小驼峰命名法
int student_count;     // 下划线命名法
const int MAX_SIZE = 100;  // 常量用大写

// 不好的命名
int a, b, c;           // 无意义的名字
int x1, x2, x3;        // 难以理解
int 1stPlace;          // 错误:不能以数字开头
int my-var;            // 错误:不能包含连字符

类型转换

隐式类型转换
int a = 10;
double b = a;        // int 自动转换为 double,b = 10.0

double x = 3.7;
int y = x;           // double 自动转换为 int,y = 3(截断)
显式类型转换(强制转换)
double x = 3.7;

// C 风格转换
int y = (int)x;      // y = 3

// C++ 风格转换
int z = static_cast<int>(x);  // z = 3

// 四舍五入
int w = (int)(x + 0.5);  // w = 4

运算符

算术运算符

运算符功能示例结果
+加法5 + 38
-减法5 - 32
*乘法5 * 315
/除法7 / 23(整数除法)
%取模(求余数)7 % 21
整数除法会截断小数部分!如果需要精确结果,至少有一个操作数应为浮点数:7.0 / 2 结果为 3.5

自增自减运算符

int i = 5;

// 前置自增:先加1,再使用
int a = ++i;    // i = 6, a = 6

// 后置自增:先使用,再加1
int b = i++;    // b = 6, i = 7

// 前置自减:先减1,再使用
int c = --i;    // i = 6, c = 6

// 后置自减:先使用,再减1
int d = i--;    // d = 6, i = 5
在循环中,i++++i 效果相同。但 ++i 效率略高(不需要保存旧值),在 C++ 中推荐使用前置自增。

复合赋值运算符

运算符示例等价于
+=a += ba = a + b
-=a -= ba = a - b
*=a *= ba = a * b
/=a /= ba = a / b
%=a %= ba = a % b

比较运算符

运算符功能示例
==等于a == b
!=不等于a != b
>大于a > b
<小于a < b
>=大于等于a >= b
<=小于等于a <= b
常见错误:将 == 写成 =if (a = 5) 是赋值语句,结果总是为真!正确的写法是 if (a == 5)

逻辑运算符

运算符功能说明
&&逻辑与两个条件都为真时结果为真
||逻辑或至少一个条件为真时结果为真
!逻辑非取反,真变假,假变真
int age = 20;
bool hasID = true;

// 逻辑与:两个条件都要满足
if (age >= 18 && hasID) {
    cout << "可以进入" << endl;
}

// 逻辑或:满足一个条件即可
if (age < 12 || age > 60) {
    cout << "可以享受优惠" << endl;
}

// 逻辑非:取反
bool isRaining = false;
if (!isRaining) {
    cout << "天气不错" << endl;
}
短路求值:对于 &&,如果左边为假,右边不会计算;对于 ||,如果左边为真,右边不会计算。

位运算符

运算符功能示例
&按位与5 & 3 = 1
|按位或5 | 3 = 7
^按位异或5 ^ 3 = 6
~按位取反~5
<<左移5 << 1 = 10
>>右移5 >> 1 = 2
// 左移相当于乘以 2
int a = 5;
a = a << 1;     // a = 10 (5 * 2)
a = a << 2;     // a = 40 (10 * 4)

// 右移相当于除以 2
int b = 20;
b = b >> 1;     // b = 10 (20 / 2)
b = b >> 2;     // b = 2 (10 / 4)

// 判断奇偶
if (n & 1) {
    cout << "n 是奇数" << endl;
} else {
    cout << "n 是偶数" << endl;
}

条件运算符(三目运算符)

条件运算符是 if-else 的简写形式:

// 语法:条件 ? 表达式1 : 表达式2
// 如果条件为真,返回表达式1的值;否则返回表达式2的值

int a = 10, b = 20;
int max = (a > b) ? a : b;  // max = 20

// 实际应用:求绝对值
int x = -5;
int abs_x = (x >= 0) ? x : -x;  // abs_x = 5

逗号运算符

逗号运算符可将多个表达式分隔开来,整个表达式的值是最后的表达式的值。

int a = (1 + 2, 3 + 4, 5 + 6);  // a = 11

// 常用于 for 循环
for (int i = 0, j = 10; i < j; i++, j--) {
    // ...
}

数组

什么是数组?

数组是一种数据结构,用于存储相同类型的多个元素。这些元素在内存中连续存放,可以通过下标访问。

数组的特点
  • 所有元素类型相同
  • 元素在内存中连续存储
  • 可以通过下标快速访问任意元素
  • 数组大小在定义时确定,之后不能改变

一维数组

声明与初始化
// 声明数组
int arr[10];              // 声明长度为10的数组,元素值未初始化

// 声明并初始化
int nums[5] = {1, 2, 3, 4, 5};   // 完全初始化
int values[5] = {1, 2};          // 部分初始化,其余为0
int zeros[5] = {};               // 全部初始化为0
int data[] = {1, 2, 3, 4, 5};    // 自动推断长度为5

// 使用常量定义大小
const int N = 100;
int a[N];                 // 正确
访问元素
int arr[5] = {10, 20, 30, 40, 50};

// 访问元素(下标从0开始)
cout << arr[0] << endl;   // 输出 10
cout << arr[4] << endl;   // 输出 50

// 修改元素
arr[2] = 100;             // arr 变为 {10, 20, 100, 40, 50}

// 遍历数组
for (int i = 0; i < 5; i++) {
    cout << arr[i] << " ";
}
数组下标从 0 开始!访问越界(如访问 arr[5] 或 arr[-1])会导致未定义行为,可能程序崩溃或产生错误结果。

二维数组

二维数组可以看作"数组的数组",常用于表示矩阵、表格等。

声明与初始化
// 声明二维数组
int matrix[3][4];         // 3行4列

// 声明并初始化
int arr[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

// 部分初始化
int b[2][3] = {{1}, {4, 5}};  // b[0] = {1,0,0}, b[1] = {4,5,0}

// 全部初始化为0
int c[3][4] = {};
访问与遍历
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};

// 访问元素
cout << arr[0][1] << endl;  // 输出 2
cout << arr[1][2] << endl;  // 输出 6

// 遍历二维数组
for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) {
        cout << arr[i][j] << " ";
    }
    cout << endl;
}

数组在内存中的存储

一维数组:元素在内存中连续存储。
二维数组:按行存储,先存第一行,再存第二行,以此类推。
// 数组大小计算
int arr[10];
cout << sizeof(arr) << endl;        // 40 (10 * 4字节)
cout << sizeof(arr[0]) << endl;     // 4 (一个int的大小)
cout << sizeof(arr) / sizeof(arr[0]) << endl;  // 10 (元素个数)
局部数组过大(超过栈大小,通常几MB)会导致栈溢出。大数组应定义为全局变量或使用动态分配。

字符串

C 风格字符串

C 风格字符串是以空字符 '\0' 结尾的字符数组:

#include <cstring>

char str1[] = "Hello";        // 自动添加 '\0',长度为6
char str2[10] = "World";      // 剩余位置填充 '\0'
char str3[] = {'H', 'i', '\0'};  // 显式添加结束符

// 常用函数
cout << strlen(str1) << endl;    // 5(不含 '\0')
strcpy(str2, str1);              // 复制字符串
strcat(str1, " World");          // 连接字符串
strcmp(str1, str2);              // 比较字符串(相等返回0)

C++ string 类

C++ 的 string 类更加安全方便,推荐使用:

#include <iostream>
#include <string>
using namespace std;

int main() {
    // 创建字符串
    string s1 = "Hello";
    string s2("World");
    string s3(5, 'a');      // "aaaaa"
    
    // 字符串连接
    string s4 = s1 + " " + s2;  // "Hello World"
    s1 += "!";                  // s1 = "Hello!"
    
    // 访问字符
    cout << s1[0] << endl;      // 'H'
    cout << s1.at(0) << endl;   // 'H'(带边界检查)
    
    // 字符串长度
    cout << s1.length() << endl;  // 6
    cout << s1.size() << endl;    // 6
    cout << s1.empty() << endl;   // false(是否为空)
    
    // 子串
    string s = "Hello World";
    cout << s.substr(0, 5) << endl;  // "Hello"
    cout << s.substr(6) << endl;     // "World"
    
    // 查找
    cout << s.find("World") << endl;    // 6(找到返回位置)
    cout << s.find("abc") << endl;      // string::npos(未找到)
    
    // 输入
    string name;
    cin >> name;         // 读入一个单词(遇空格停止)
    getline(cin, name);  // 读入一行(包括空格)
    
    return 0;
}
使用 getline(cin, s) 可以读入包含空格的整行字符串。

分支语句

if 语句

// 基本 if 语句
if (条件) {
    // 条件为真时执行
}

// if-else 语句
if (score >= 60) {
    cout << "及格" << endl;
} else {
    cout << "不及格" << endl;
}

// if-else if-else 语句
if (score >= 90) {
    cout << "优秀" << endl;
} else if (score >= 80) {
    cout << "良好" << endl;
} else if (score >= 60) {
    cout << "及格" << endl;
} else {
    cout << "不及格" << endl;
}
当语句块只有一条语句时,花括号可以省略,但建议始终使用花括号,避免出错。

switch 语句

switch 语句用于根据一个整型表达式的值选择执行不同的分支:

int day = 3;
switch (day) {
    case 1:
        cout << "星期一" << endl;
        break;
    case 2:
        cout << "星期二" << endl;
        break;
    case 3:
        cout << "星期三" << endl;
        break;
    case 6:
    case 7:
        cout << "周末" << endl;
        break;
    default:
        cout << "无效的日期" << endl;
}
不要忘记 break 语句!如果没有 break,程序会继续执行下一个 case 的语句(称为"穿透")。
switch 的限制
  • 表达式必须是整型或字符型
  • case 后面必须是常量表达式
  • 不能直接判断浮点数或字符串

循环语句

for 循环

for 循环适用于已知循环次数的情况:

// 语法
for (初始化; 条件; 更新) {
    循环体;
}

// 示例:输出1到10
for (int i = 1; i <= 10; i++) {
    cout << i << " ";
}

// 示例:计算1到100的和
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;
}
cout << sum << endl;  // 5050

// 范围for循环(C++11)
int arr[] = {1, 2, 3, 4, 5};
for (int x : arr) {
    cout << x << " ";
}

while 循环

while 循环适用于不确定循环次数的情况:

// 语法
while (条件) {
    循环体;
}

// 示例:计算1到100的和
int sum = 0, i = 1;
while (i <= 100) {
    sum += i;
    i++;
}
cout << sum << endl;

// 示例:验证 3x+1 猜想
while (x > 1) {
    if (x % 2 == 1) {
        x = 3 * x + 1;
    } else {
        x = x / 2;
    }
}

do-while 循环

do-while 循环至少执行一次循环体:

// 语法
do {
    循环体;
} while (条件);  // 注意分号

// 示例:菜单选择
int choice;
do {
    cout << "1. 开始游戏" << endl;
    cout << "2. 设置" << endl;
    cout << "3. 退出" << endl;
    cout << "请选择: ";
    cin >> choice;
} while (choice != 3);

break 和 continue

// break: 退出整个循环
for (int i = 1; i <= 10; i++) {
    if (i == 5) break;  // 当i等于5时退出循环
    cout << i << " ";
}
// 输出: 1 2 3 4

// continue: 跳过本次循环,继续下一次
for (int i = 1; i <= 5; i++) {
    if (i == 3) continue;  // 跳过i等于3的情况
    cout << i << " ";
}
// 输出: 1 2 4 5

循环的选用原则

  1. 循环过程中有个固定的增加步骤(最常见的是枚举)时,使用 for 语句
  2. 只确定循环的终止条件时,使用 while 语句
  3. 使用 while 语句时,若要先执行循环体再进行判断,使用 do-while 语句

函数

函数的基本概念

函数是一段完成特定任务的代码块,可以被多次调用。使用函数可以:

  • 提高代码复用性
  • 使程序结构更清晰
  • 便于调试和维护

函数定义与声明

// 函数声明(原型)
返回类型 函数名(参数列表);

// 函数定义
返回类型 函数名(参数列表) {
    函数体;
    return 返回值;
}

// 示例
int add(int a, int b);  // 声明

int add(int a, int b) { // 定义
    return a + b;
}

void printHello() {     // 无返回值函数
    cout << "Hello!" << endl;
}

int main() {
    int result = add(3, 5);  // 调用函数
    cout << result << endl;  // 输出 8
    printHello();            // 输出 Hello!
    return 0;
}

参数传递方式

值传递
// 值传递:函数内修改不影响原变量
void swap1(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 1, y = 2;
    swap1(x, y);
    cout << x << " " << y << endl;  // 1 2(未交换)
    return 0;
}
引用传递
// 引用传递:函数内修改会影响原变量
void swap2(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 1, y = 2;
    swap2(x, y);
    cout << x << " " << y << endl;  // 2 1(已交换)
    return 0;
}
指针传递
// 指针传递:传递变量的地址
void swap3(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 1, y = 2;
    swap3(&x, &y);
    cout << x << " " << y << endl;  // 2 1(已交换)
    return 0;
}
在竞赛中,使用引用传递可以避免复制大对象,提高效率。同时,如果需要在函数内修改原变量,必须使用引用或指针传递。

默认参数

// 默认参数必须从右向左连续设置
int power(int base, int exp = 2) {
    int result = 1;
    for (int i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

int main() {
    cout << power(3) << endl;     // 9 (3^2)
    cout << power(2, 10) << endl; // 1024 (2^10)
    return 0;
}

递归函数

递归是函数调用自身的过程:

// 阶乘
long long factorial(int n) {
    if (n <= 1) return 1;  // 递归终止条件
    return n * factorial(n - 1);  // 递归调用
}

// 斐波那契数列
long long fib(int n) {
    if (n <= 2) return 1;
    return fib(n - 1) + fib(n - 2);
}

// 求和 1+2+...+n
int sum(int n) {
    if (n == 1) return 1;
    return n + sum(n - 1);
}

int main() {
    cout << factorial(5) << endl;  // 120
    cout << fib(10) << endl;      // 55
    cout << sum(100) << endl;     // 5050
    return 0;
}
递归必须有终止条件,否则会导致无限递归,程序崩溃(栈溢出)。递归深度过大也会导致栈溢出。

结构体

什么是结构体?

结构体(struct)是用户自定义的数据类型,可以将多个不同类型的数据组合在一起。

结构体定义与使用

// 定义结构体
struct Student {
    string name;
    int age;
    double score;
};  // 注意分号

// 创建结构体变量
int main() {
    // 方式1:先声明后赋值
    Student stu1;
    stu1.name = "小明";
    stu1.age = 15;
    stu1.score = 95.5;
    
    // 方式2:声明时初始化
    Student stu2 = {"小红", 16, 98.0};
    
    // 方式3:C++11统一初始化
    Student stu3{"小刚", 14, 88.5};
    
    // 访问成员
    cout << stu1.name << " " << stu1.age << " " << stu1.score << endl;
    
    return 0;
}

结构体数组

#include <iostream>
#include <string>
using namespace std;

struct Student {
    string name;
    int score;
};

int main() {
    Student class1[3] = {
        {"小明", 90},
        {"小红", 85},
        {"小刚", 95}
    };
    
    // 遍历结构体数组
    for (int i = 0; i < 3; i++) {
        cout << class1[i].name << ": " << class1[i].score << endl;
    }
    
    return 0;
}

结构体嵌套

struct Date {
    int year;
    int month;
    int day;
};

struct Person {
    string name;
    Date birthday;  // 嵌套结构体
};

int main() {
    Person p;
    p.name = "张三";
    p.birthday.year = 2000;
    p.birthday.month = 5;
    p.birthday.day = 15;
    
    cout << p.name << "的生日是: " 
         << p.birthday.year << "-" 
         << p.birthday.month << "-" 
         << p.birthday.day << endl;
    
    return 0;
}

结构体排序

#include <iostream>
#include <algorithm>
using namespace std;

struct Student {
    string name;
    int score;
};

// 自定义比较函数
bool cmp(Student a, Student b) {
    return a.score > b.score;  // 按分数降序
}

int main() {
    Student stu[3] = {
        {"小明", 90},
        {"小红", 85},
        {"小刚", 95}
    };
    
    // 排序
    sort(stu, stu + 3, cmp);
    
    // 输出排序结果
    for (int i = 0; i < 3; i++) {
        cout << stu[i].name << ": " << stu[i].score << endl;
    }
    
    return 0;
}

指针

什么是指针?

指针是一种特殊的变量,它存储的是另一个变量的内存地址,而不是值本身。

指针的声明与使用
int main() {
    int a = 123;  // a: 123
    int* pa = &a; // pa 指向 a 的地址
    *pa = 321;    // a: 321(通过指针修改)
}

指针与数组

int main() {
    int a[3] = {1, 2, 3};
    int* p = a;  // p 指向 a[0]
    *p = 4;      // a: [4, 2, 3]
    p = p + 1;   // p 指向 a[1]
    *p = 5;      // a: [4, 5, 3]
    p++;         // p 指向 a[2]
    *p = 6;      // a: [4, 5, 6]
}
数组名本身就是指向数组首元素的指针。a[i] 等价于 *(a + i)

指针与结构体

struct ThreeInt {
    int a, b, c;
};

int main() {
    ThreeInt x{1, 2, 3};
    ThreeInt* px = &x;
    (*px).a = 4;  // x: {4, 2, 3}
    px->b = 5;    // x: {4, 5, 3}(推荐写法)
}

空指针 nullptr

int* p = nullptr;  // C++11 推荐使用 nullptr

if (p == nullptr) {
    cout << "p 是空指针" << endl;
}
对空指针解引用会导致程序崩溃。在使用指针前,应检查其是否为空。

动态内存分配

// 动态分配单个对象
int* p = new int(1234);
/* ... */
delete p;

// 动态分配数组
int* arr = new int[100];
/* ... */
delete[] arr;
使用 new 申请的内存必须使用 delete 释放,否则会造成内存泄漏。

引用

什么是引用?

引用是变量的别名,对引用的操作就是对原变量的操作。

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int& r = a;  // r 是 a 的引用
    
    r = 20;      // a = 20
    cout << a << endl;  // 输出 20
    
    return 0;
}

引用的特点

  • 引用必须在定义时初始化
  • 引用一旦绑定,不能改变指向
  • 没有"空引用"
  • 引用比指针更安全

引用作为函数参数

void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 1, y = 2;
    swap(x, y);
    cout << x << " " << y << endl;  // 2 1
    return 0;
}
引用传参可以避免复制大对象,提高效率。同时可以修改原变量的值。

const 引用

int a = 10;
const int& r = a;  // const 引用

// r = 20;  // 错误:不能通过 const 引用修改值
a = 20;     // 正确:可以直接修改原变量

常量与常表达式

const 常量

const int a = 0;  // a 的类型为 const int

// a = 1;  // 错误,不能修改常量

const 指针

int a = 0;
const int b = 0;

int* p1 = &a;
*p1 = 1;  // 正确
const int* p2 = &a;
// *p2 = 2;  // 错误,不能通过常指针修改
// int* p3 = &b;  // 错误,不能用普通指针指向 const 变量
const int* p4 = &b;  // 正确

constexpr 常表达式(C++11)

constexpr 声明的变量或函数可以在编译时求值:

constexpr int a = 10;  // 直接定义常量

constexpr int FivePlus(int x) { return 5 + x; }

void test(const int x) {
    // std::array<x> c1;  // 错误,x在编译期不可知
    std::array<FivePlus(6)> c2;  // 可行,FivePlus编译期可以推断
}
把 const 理解成 "readonly",而把 constexpr 理解成 "const" 更加直观。

恭喜你完成 C++ 基础学习!

继续学习更多高级内容,挑战编程竞赛!

微信客服二维码

扫码添加微信客服 (加好友时请备注:小码豆)