C++ 基础知识

本章节专为零基础读者设计。不需要任何编程经验,循序渐进,从最基础的概念开始,一步一步进入编程的世界。每一节都配有通俗易懂的类比、编程练习和课后练习,确保真正掌握每一个知识点。

本页阅读量: 加载中...

1. C++ 简介

通俗类比

想象你有一个非常听话的机器人。你可以给它写一份详细的指令清单,告诉它每一步要做什么。C++ 就像是你和计算机之间的"指令语言"——你写代码告诉计算机该做什么,计算机就会严格执行。

C++ 是一种计算机程序设计语言。它诞生于1979年,最初叫做 "C with Classes"(带类的C语言),后来在1983年改名为 C++。名字里的 "++" 是 C 语言中的"加1"运算符,意思是 C++ 是 C 语言的升级版。

为什么要学 C++?

  • 超快的运行速度:C++ 程序直接运行在电脑上,几乎没有中间环节,所以执行速度非常快。游戏、操作系统这类对速度要求很高的软件都用 C++ 写。
  • 几乎所有领域都在用:Windows 系统的很多部分、Chrome 浏览器、Photoshop、微信 PC 版、大部分游戏引擎……这些软件的核心代码都是 C++ 写的。
  • 学会 C++,其他语言都不难:如果你学会了 C++,再学 Python、Java、JavaScript 等语言会非常轻松,因为很多概念是相通的。
  • 锻炼逻辑思维:编程和数学一样,能训练你的逻辑思考能力。写程序的过程就是"把大问题拆成小问题,逐个解决"的过程。

C++ 能做什么?

领域你能做什么
游戏开发做 2D 小游戏、用游戏引擎做 3D 大作
桌面软件做计算器、记事本、音乐播放器、聊天工具
嵌入式控制机器人、智能家居、无人机
数据处理处理大量数据、科学计算、统计分析
网络编程做服务器、聊天室、文件传输工具

程序是什么?

简单来说,程序 = 数据 + 指令。就像做一道数学题,你需要"题目给的数据"和"解题的步骤"。C++ 程序也是这样的结构:

C++
#include <iostream>

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

这段代码做了三件事:

  1. #include <iostream> —— "我要使用输入输出功能"
  2. std::cout << "Hello, World!" —— "在屏幕上显示这句话"
  3. return 0; —— "正常结束"
说明

不用担心现在看不懂代码。就像你第一天学英语看不懂整篇文章一样,后面的每一节我们会把每个符号、每行代码都讲清楚。耐心学完这一章,你一定能看懂。

编程练习

编写一个程序,输出三行文字:第一行是你的姓名,第二行是你的年龄,第三行是"开始学习C++"。要求每行末尾换行。

2. 环境搭建

通俗类比

学画画需要画笔和纸,学做饭需要锅和食材。学编程也需要工具:一个能把 C++ 代码翻译成计算机指令的翻译官(编译器),以及一个方便你写代码的编辑器(IDE)。

在写代码之前,我们需要在电脑上安装两个东西:

  • 编译器:把 C++ 代码翻译成计算机能执行的语言。常用的有 Visual Studio(Windows)、Xcode(Mac)、g++(所有平台)。
  • 编辑器 / IDE:写代码的地方。IDE 是"集成开发环境",简单说就是"全能写代码工具",能写代码、调试错误、运行程序。

Windows 用户 —— 安装 Visual Studio

Visual Studio 是微软官方的开发工具,功能强大,对新手最友好。

  1. 打开浏览器,访问 visualstudio.microsoft.com/zh-hans/
  2. 下载 Visual Studio Community(社区版),这是免费的
  3. 运行下载的安装程序,勾选"使用 C++ 的桌面开发"这一项
  4. 点击"安装",等待下载完成(大约 2-5GB,需要一些时间)
  5. 打开 Visual Studio,点击"创建新项目" → "空项目" → 输入项目名称(如 HelloWorld)→ 确定
  6. 在右侧"解决方案资源管理器"中,右键点击"源文件" → 添加 → 新建项 → 选择"C++ 文件(.cpp)" → 命名为 main.cpp
  7. 在代码编辑区输入你的代码,按 F5 运行!

Mac 用户 —— 安装 Xcode

  1. 打开 App Store,搜索 "Xcode",下载安装(大约 10GB)
  2. 或者打开终端,输入 xcode-select --install,只安装命令行工具(几百 MB)
  3. 打开 Xcode,创建新项目 → macOS → Command Line Tool → 选择 C++ 语言
  4. 写代码后,点击左上角的"运行"按钮()

最简单的验证方法

安装完成后,创建一个文件,输入以下内容:

C++
#include <iostream>

int main() {
    std::cout << "我的环境配置成功啦!" << std::endl;
    return 0;
}

如果能运行并看到输出文字,恭喜你,环境搭建成功!

提示

如果在安装过程中遇到问题,不要着急。常见问题:安装包太大下载慢(可以找 WiFi 好的地方)、找不到"使用 C++ 的桌面开发"选项(点击"修改"后可以看到)。遇到任何报错都可以复制到百度搜索,99%的问题都有人遇到过。

编程练习

安装完编译器后,编写并运行第一个C++程序,输出"Hello, C++ World!"到控制台。确保程序能够成功编译并执行。

3. 第一个 C++ 程序

通俗类比

学习任何语言的第一步都是说"你好"。学英语说 "Hello",学日语说 "Konnichiwa"。学编程语言也一样,第一个程序永远是让电脑说 "Hello, World!"。这就像是和电脑打了个招呼,确认它能听懂你的话。

现在,在你的编辑器里输入这段代码:

C++
// 这是一行注释,计算机不会执行注释的内容
// 第1行:告诉电脑"我要用输入输出功能"
#include <iostream>

// 第3行:程序从这里开始执行
int main() {
    // 第5行:在屏幕上显示文字
    std::cout << "Hello, World!" << std::endl;

    // 第7行:告诉电脑"我正常结束了"
    return 0;
}

逐行解析(每一行都讲清楚)

第1行:// 这是一行注释...

// 开头的文字是注释。注释是给程序员看的,计算机完全无视它们。好的注释能让你的代码更容易理解。

C++
// 这是单行注释

/*
   这是多行注释
   可以写很多行
   计算机都不会执行
*/

int x = 5;  // 注释也可以放在行尾

第2行:#include <iostream>

#include 的意思是"包含进来"。iostream 是 "input-output stream" 的缩写,可以理解为"输入输出流"——就是控制"在屏幕上显示文字"和"从键盘读取输入"的功能。

为什么要写这一行?因为 C++ 很精简,默认不提供输入输出功能,你需要显式告诉它"我要用这个功能"。就像你去图书馆借书,需要先说"我要借这本书"。

第4行:int main()

这是主函数,是程序的入口。所有 C++ 程序都必须有一个 main(),程序就从这里开始执行。

  • int 表示这个函数会返回一个整数(整数就是 -3, 0, 5 这样的数)
  • main 是函数的名字,不能改
  • () 表示这是一个函数,括号里可以放参数

第5-6行:大括号 {}

大括号里的是函数体,也就是 main 函数要执行的指令。你可以把它想象成一个"任务清单",里面列着主函数要一件件完成的事。

第7行:std::cout << "Hello, World!" << std::endl;

这是核心语句,意思是"把 Hello, World! 输出到屏幕"。

  • std::cout:标准输出(standard character output),可以理解为"屏幕"
  • <<:插入运算符,可以理解为"发送到",把右边的内容发送到左边的屏幕
  • "Hello, World!":双引号里的是字符串(一串文字)
  • std::endl:end line,表示换行
再来一个比喻

std::cout << "Hello" 就像你在微信聊天框里输入"Hello"然后点击发送。<< 就是发送按钮,std::cout 就是聊天窗口。

第10行:return 0;

返回 0 表示"程序正常结束"。非 0 表示"出错了"。操作系统会检查这个返回值来判断程序是否正常运行。

动手试一试

编程练习

修改上面的程序,让它显示你的名字和年龄。例如:

我叫小明
今年16岁
我是程序员啦!

使用命名空间简化

如果你觉得每次都写 std:: 太麻烦,可以用 using namespace std; 来偷懒:

C++
#include <iostream>
using namespace std;

int main() {
    cout << "Hello, World!" << endl;  // 不需要 std:: 了
    return 0;
}
注意

在大项目里不建议使用 using namespace std;,因为可能导致名字冲突。但我们在学习阶段用它完全没问题,怎么简单怎么来!

编程练习

修改"Hello World"程序,使其输出以下内容(每行单独输出):

姓名:张三
年龄:18
爱好:编程

要求使用三条独立的 cout 语句,并添加适当的注释说明每条语句的作用。

4. 数据类型

通俗类比

你去超市买东西,有的东西按"个"卖(苹果),有的按"斤"卖(大米),有的按"瓶"卖(牛奶)。在 C++ 里,数据类型就像是商品的计量单位——它告诉计算机:这个数据是什么种类,占多大空间。

计算机内存就像是一排排的储物柜。当你创建一个变量时,计算机会根据数据类型为你分配合适大小的储物柜:

  • 装一个小数字 → 给小柜子(1-2 字节)
  • 装一个大数字 → 给大柜子(4-8 字节)
  • 装一个小数 → 给特殊的柜子(4-8 字节)
  • 装文字 → 给字符柜子(1 字节/字符)

常用数据类型一览

类型说明大小能存什么例子
bool布尔(开关)1 字节true(真)或 false(假)true
char字符1 字节一个字母、数字或符号'A', '5'
short短整数2 字节-32768 ~ 327671000
int整数4 字节约 -21亿 ~ 21亿42, -7
long long长整数8 字节超级大的数9999999999
float单精度小数4 字节约 6-7 位精度3.14f
double双精度小数8 字节约 15-16 位精度3.1415926

你可能注意到了:有些类型名字后面有个 f(如 3.14f)。这告诉编译器"这是一个 float,不是 double"。不写也行,编译器会自动选择。

类型的简单使用

C++
#include <iostream>
using namespace std;

int main() {
    int age = 16;            // 整数
    double height = 1.75;    // 小数
    char grade = 'A';      // 字符(用单引号)
    bool passed = true;    // 开关:true 或 false

    cout << "年龄: " << age << endl;
    cout << "身高: "; << height << "米" << endl;
    cout << "成绩: " << grade << endl;
    cout << "及格了吗: " << (passed ? "是" : "否") << endl;
    return 0;
}

sizeof —— 查看数据占多大空间

C++
int main() {
    cout << "bool: " << sizeof(bool) << " 字节" << endl;
    cout << "char: " << sizeof(char) << " 字节" << endl;
    cout << "int: " << sizeof(int) << " 字节" << endl;
    cout << "double: " << sizeof(double) << " 字节" << endl;
    return 0;
}

类型转换

有时候你需要把一种类型变成另一种类型。比如你想把 3.7 变成整数,计算机会直接截断小数部分变成 3

C++
double pi = 3.14;
int approx = (int)pi;  // 强制转换,approx = 3(小数被砍掉)

// 更安全的写法(C++ 推荐)
int approx2 = static_cast<int>(pi);

// 隐式转换(自动)
int a = 5;
double b = a;  // int 自动变成 double,b = 5.0
注意

整数除以整数,结果还是整数!5 / 2 结果是 2,不是 2.5。想要小数结果,至少把一个数写成小数:5.0 / 2 结果是 2.5。这是一个初学者最常犯的错误!

编程练习

定义并初始化以下变量,然后输出它们的值和占用字节数(使用 sizeof):

  1. 一个 int 变量,值为 42
  2. 一个 double 变量,值为 3.14159
  3. 一个 char 变量,值为 'A'
  4. 一个 bool 变量,值为 true

5. 变量和常量

通俗类比

变量就像是一个带标签的盒子。盒子里可以装东西,你可以随时更换里面的东西。比如一个标签为"年龄"的盒子,今年装的是 15,明年装的是 16。

常量则像是一个被焊死的盒子,一旦装好就不能改了。比如圆周率 π 永远是 3.14159,你不能"改天把它改成 4"。

什么是变量?

变量 = 一个名字 + 一个值。创建变量的过程叫做"声明"或"定义":

C++
// 变量声明:类型 名字 = 初始值;
int age = 15;           // 创建一个名为 age 的整数变量
double score = 89.5;    // 名为 score 的小数变量
string name = "小明";   // 名为 name 的字符串变量

// 先声明,后面再赋值
int num;     // 创建盒子,但里面还没有值
num = 100;   // 把 100 放进盒子
num = 200;   // 把 200 替换进去(原来的 100 没了)

变量命名规则

给变量起名字要遵守以下规则(就像给人起名字不能乱来):

  • 只能用字母数字下划线(_)
  • 不能以数字开头1num 是错的,num1 是对的)
  • 不能是 C++ 的关键字(如 int, return, if
  • C++ 区分大小写:Ageage 是两个不同的变量
C++
//  好的命名
int studentAge;
int student_age;   // 下划线风格
double mathScore;

//  不好的命名
// int 1stPlace;    // 不能以数字开头
// int my age;      // 不能有空格
// int class;       // class 是关键字

常量(不会变的值)

如果你有一些永远不应该改变的值,比如数学常数、游戏的最大生命值等,用 const 定义常量:

C++
const double PI = 3.14159;    // 圆周率
const int MAX_LIVES = 3;       // 最大生命数

// PI = 3.14;  // 错误!不能修改常量

// constexpr 是更高级的常量(编译时就能确定值)
constexpr int SQUARE(int x) {
    return x * x;
}

变量的作用域

作用域就是变量"能被人看到"的范围。在大括号 {} 里创建的变量,只能在这个大括号里使用。

C++
#include <iostream>
using namespace std;

int globalVar = 100;  // 全局变量:整个程序都能看到

int main() {
    int localVar = 50;   // 局部变量:只在 main 函数里能用

    if (true) {
        int blockVar = 20;  // 块级变量:只在这个 if 里能用
        cout << blockVar << endl;  //  可以
    }

    // cout << blockVar;  //  错误!blockVar 已经"消失"了

    cout << localVar << endl;   //  50
    cout << globalVar << endl;  //  100
    return 0;
}

编程练习

创建一个程序,定义以下变量并输出:

  • 你的名字(string)
  • 你的年龄(int)
  • 你的身高,单位米(double)
  • 你是否喜欢编程(bool)

输出格式:我叫小明,15岁,身高1.72米,喜欢编程:是

编程练习

编写程序完成以下任务:

  1. 定义一个 const double PI = 3.14159
  2. 定义一个变量 radius,初始值为 5.0
  3. 计算圆的面积(PI * radius * radius)并输出
  4. 尝试修改 PI 的值,观察编译器报错信息

6. 运算符

通俗类比

运算符就像是计算器上的按钮:+ 是加,- 是减,× 是乘,÷ 是除。C++ 里的运算符本质上和数学课上学的一模一样,只是有些符号长得不一样(比如乘法是 * 不是 ×)。

算术运算符

运算符名字例子结果
+5 + 38
-5 - 32
*5 * 315
/5 / 31(整数除法会截断!)
%取余(模)5 % 32(5除以3余2)
超级重要的提醒

整数除法会截断小数5 / 2 得到 2,不是 2.5% 是取余数,5 % 2 = 1。想要精确结果,把至少一个数改成小数:5.0 / 2 = 2.5

自增和自减

++ 让变量加 1,-- 让变量减 1。注意前置和后置的区别:

C++
int a = 5;
int b = ++a;  // 前置:先加1(a=6),再赋值(b=6)

int c = 5;
int d = c++;  // 后置:先赋值(d=5),再加1(c=6)

// 简写赋值
int x = 10;
x += 5;   // 等同于 x = x + 5;   现在 x = 15
x -= 3;   // 等同于 x = x - 3;   现在 x = 12
x *= 2;   // 等同于 x = x * 2;   现在 x = 24
x /= 4;   // 等同于 x = x / 4;   现在 x = 6

关系运算符(比较大小)

运算符含义例子结果
==等于5 == 5true
!=不等于5 != 3true
>大于5 > 3true
<小于5 < 3false
>=大于等于5 >= 5true
<=小于等于5 <= 3false
常见错误

不要把 ==(等于)和 =(赋值)搞混!if (a == 5) 是"判断 a 是否等于 5",a = 5 是"把 5 赋给 a"。写错会导致奇怪的错误。

逻辑运算符

运算符含义例子结果
&&与(并且)true && falsefalse(两个都为真才为真)
||或(或者)true || falsetrue(有一个为真就为真)
!非(取反)!truefalse
C++
int score = 85;
bool hasID = true;

// 判断是否及格(60分以上)并且有证件
if (score >= 60 && hasID) {
    cout << "可以参加!" << endl;
}

// 判断是否周末(周六或周日)
int day = 6;  // 6=周六
if (day == 6 || day == 7) {
    cout << "今天是周末!" << endl;
}

编程练习

编写程序实现一个简单的计算器:定义两个 double 变量 a = 17b = 5,计算并输出它们的和、差、积、商、余数(a对b取模)以及 a 自增后的值。

7. 条件语句

通俗类比

条件语句就像是生活中的"如果……就……"。比如:"如果明天下雨,带伞;否则,穿短袖。"程序也是一样,可以根据不同的条件执行不同的代码。

if 语句

最简单的条件判断。如果条件为真(true),就执行大括号里的代码。

C++
#include <iostream>
using namespace std;

int main() {
    int age;
    cout << "请输入你的年龄: ";
    cin >> age;  // 从键盘读取一个整数

    if (age >= 18) {
        cout << "你已经成年了!" << endl;
    }

    return 0;
}

if-else 语句

"如果条件成立就做 A,否则做 B":

C++
int score;
cout << "请输入成绩: ";
cin >> score;

if (score >= 60) {
    cout << "恭喜,及格了!" << endl;
} else {
    cout << "不及格,下次加油!" << endl;
}

if-else if-else(多个条件)

当有多个条件要判断时,用 else if:

C++
int score;
cout << "请输入成绩 (0-100): ";
cin >> score;

if (score >= 90) {
    cout << "优秀 (A)" << endl;
} else if (score >= 80) {
    cout << "良好 (B)" << endl;
} else if (score >= 70) {
    cout << "中等 (C)" << endl;
} else if (score >= 60) {
    cout << "及格 (D)" << endl;
} else {
    cout << "不及格 (F)" << endl;
}

switch 语句(多分支选择)

当要判断的值是一个整数或字符时,switch 比多个 if-else 更清晰:

C++
int day;
cout << "请输入星期数字 (1-7): ";
cin >> day;

switch (day) {
    case 1: cout << "星期一" << endl; break;
    case 2: cout << "星期二" << endl; break;
    case 3: cout << "星期三" << endl; break;
    case 4: cout << "星期四" << endl; break;
    case 5: cout << "星期五" << endl; break;
    case 6:
    case 7: cout << "周末" << endl; break;
    default: cout << "输入无效!" << endl;
}
说明

每个 case 后面都要有 break;,否则会"贯穿"到下一个 case。比如上面的 case 6 没有 break,所以执行完 6 后会继续执行 7 的代码。这是有意为之的——周六和周日都显示"周末"。

三目运算符(简化版 if-else)

对于简单的二选一,可以写得更加简洁:

C++
int a = 10, b = 20;

// 语法:(条件) ? 值A : 值B
// 如果条件为真,返回值A;否则返回值B
int max = (a > b) ? a : b;  // max = 20

// 等同于:
// int max;
// if (a > b) max = a;
// else max = b;

编程练习

编写一个程序,输入一个年份,判断它是否是闰年。闰年的规则:

  • 能被 4 整除,但不能被 100 整除 → 是闰年
  • 能被 400 整除 → 也是闰年

提示:用 % 判断是否整除,year % 4 == 0 表示能被 4 整除。

编程练习

编写程序:输入一个年份,判断它是否为闰年。闰年规则:能被4整除但不能被100整除,或者能被400整除。输出相应的判断结果。

8. 循环

通俗类比

循环就是"重复做同一件事"。比如每天早上起床要重复:睁眼 → 刷牙 → 洗脸 → 吃早餐。在编程里,如果你要写"打印 1 到 100",你不会写 100 行代码,而是让计算机自动重复100次。

for 循环(最常用)

for 循环适合"我知道要循环多少次"的场景:

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

// 打印 1 到 5
for (int i = 1; i <= 5; i++) {
    cout << i << " ";
}
// 输出: 1 2 3 4 5

// 计算 1+2+3+...+100
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;  // 等同于 sum = sum + i;
}
cout << "1到100的和: " << sum << endl;  // 5050

// 打印九九乘法表
for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) {
        cout << j << "x" << i << "=" << i*j << "	";
    }
    cout << endl;
}

while 循环(不知道循环多少次)

while 循环在条件为真时一直执行,适合"我不知道要循环几次"的场景:

C++
// 用户输入验证
int num;
cout << "请输入一个正数: ";
cin >> num;

while (num <= 0) {
    cout << "输入无效,请重新输入: ";
    cin >> num;
}

cout << "你输入的是: " << num << endl;

// 猜数字游戏
int secret = 7;
int guess;

while (true) {  // 无限循环
    cout << "猜一个 1-10 的数字: ";
    cin >> guess;

    if (guess == secret) {
        cout << "猜对了!" << endl;
        break;  // 退出循环
    } else if (guess < secret) {
        cout << "太小了!" << endl;
    } else {
        cout << "太大了!" << endl;
    }
}

循环控制关键字

关键字作用
break立即跳出循环
continue跳过当前这次,继续下一次循环
C++
// break:找到第一个能被 7 和 13 整除的数
for (int i = 1; i <= 1000; i++) {
    if (i % 7 == 0 && i % 13 == 0) {
        cout << "找到了: " << i << endl;  // 91
        break;  // 找到就退出,不再继续
    }
}

// continue:打印 1-10 中跳过 3 的倍数
for (int i = 1; i <= 10; i++) {
    if (i % 3 == 0) continue;  // 跳过 3, 6, 9
    cout << i << " ";  // 1 2 4 5 7 8 10
}

编程练习

编写程序计算 1! + 2! + 3! + ... + 10! 的和(n! = 1×2×3×...×n)。

提示:外层循环 i 从 1 到 10,内层计算 i 的阶乘,累加到总和中。

编程练习

使用循环编写程序,计算 1 到 100 之间所有奇数的和。分别用 for 循环和 while 循环各实现一次,验证结果是否一致(应为 2500)。

9. 数组

通俗类比

数组就像是一排有编号的储物柜,或者教室里的座位。每个储物柜都有一个编号(从 0 开始),你可以根据编号存取东西。比如 lockers[0] 是第 1 个柜子,lockers[1] 是第 2 个柜子……

创建和使用数组

C++
// 声明数组:类型 名字[大小];
int scores[5];  // 5个整数的数组

// 声明并初始化
int scores2[5] = {85, 90, 78, 92, 88};

// 自动推断大小
int nums[] = {10, 20, 30, 40, 50};  // 编译器知道是 5 个

// 访问元素(索引从 0 开始!)
cout << scores2[0] << endl;  // 85(第一个元素)
cout << scores2[2] << endl;  // 78(第三个元素)

// 修改元素
scores2[1] = 95;  // 把第二个元素改成 95

// 遍历数组
for (int i = 0; i < 5; i++) {
    cout << scores2[i] << " ";
}
超级重要的警告

数组索引从 0 开始!如果你声明了 int arr[5],有效的索引是 0, 1, 2, 3, 4。arr[5]越界访问,会导致未定义行为(可能崩溃,也可能读取出奇怪的数字)。这是 C++ 中最常见的错误之一!

二维数组(表格/矩阵)

二维数组就像一张表格,有行有列:

C++
// 3 行 4 列的二维数组
int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

// 访问第 2 行第 3 列(注意索引从 0 开始)
cout << matrix[1][2] << endl;  // 7

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

获取数组大小

C++
int arr[] = {1, 2, 3, 4, 5};
int size = sizeof(arr) / sizeof(arr[0]);
// sizeof(arr) 是整个数组的字节数(这里是 20)
// sizeof(arr[0]) 是一个元素的字节数(这里是 4)
// 20 / 4 = 5,就是元素个数

编程练习

创建一个包含 10 个成绩的数组,计算:

  • 总成绩
  • 平均成绩
  • 最高分和最低分

编程练习

定义一个包含 10 个整数的数组,值为 1 到 10。编写程序计算:

  1. 数组所有元素的和
  2. 数组所有元素的平均值
  3. 数组中的最大值和最小值

要求使用循环遍历数组,不要使用现成函数。

10. 函数

通俗类比

函数就像是一个"工具"或"机器人"。你给这个工具一些原材料(参数),它经过处理后给你一个成品(返回值)。比如榨汁机:你把水果放进去(参数),它给你果汁(返回值)。

函数最大的好处是可以重复使用。你写好一个求最大值的函数,以后每次需要求最大值都可以直接用它,不用重新写。

函数的基本结构

C++
// 返回类型 函数名(参数列表) { 函数体 }

// 定义一个加法函数
int add(int a, int b) {   // a 和 b 是"形式参数"
    int result = a + b;
    return result;          // 把结果返回给调用者
}

// 没有返回值的函数用 void
void sayHello(string name) {
    cout << "你好, " << name << "!" << endl;
    // void 函数不需要 return
}

int main() {
    // 调用函数
    int sum = add(5, 3);     // sum = 8
    cout << "5 + 3 = " << sum << endl;

    sayHello("小明");       // 输出: 你好, 小明!

    return 0;
}

函数参数传递方式

方式写法是否修改原变量适用场景
值传递int x否(只修改副本)不需要修改原变量
引用传递int& x是(修改原变量)需要修改原变量,或避免拷贝大对象
指针传递int* x动态内存、可选参数
C++
// 值传递:不能交换成功
void swap_wrong(int a, int b) {
    int temp = a; a = b; b = temp;
}

// 引用传递:可以交换成功
void swap_correct(int& a, int& b) {
    int temp = a; a = b; b = temp;
}

int main() {
    int x = 5, y = 10;
    swap_correct(x, y);
    cout << x << " " << y << endl;  // 10 5
    return 0;
}

默认参数

可以给参数设置默认值,调用时如果不传就使用默认值:

C++
// greeting 有默认值 "你好"
void greet(string name, string greeting = "你好") {
    cout << greeting << ", " << name << "!" << endl;
}

// 调用
greet("小明");             // 你好, 小明!
greet("小红", "早上好");  // 早上好, 小红!

函数重载

C++ 允许同名函数存在,只要参数列表不同:

C++
// 矩形面积
int area(int w, int h) { return w * h; }

// 圆形面积(参数数量不同)
double area(double r) { return 3.14159 * r * r; }

// 调用
cout << area(5, 3) << endl;     // 15(调用 int 版本)
cout << area(3.0) << endl;      // 28.27(调用 double 版本)

递归函数

函数调用自身,叫做递归。经典例子:阶乘和斐波那契数列。

C++
// 阶乘:n! = n × (n-1) × (n-2) × ... × 1
// 5! = 5 × 4 × 3 × 2 × 1 = 120
long long factorial(int n) {
    if (n <= 1) return 1;  // 终止条件
    return n * factorial(n - 1);  // 调用自己
}

// 调用
cout << "5! = " << factorial(5) << endl;  // 120

编程练习

编写一个函数 isPrime(int n),判断一个数是否是质数(只能被 1 和自身整除的数)。

提示:用循环从 2 试除到 sqrt(n),如果都不能整除,就是质数。

编程练习

编写以下函数并在 main 中测试:

  1. int factorial(int n):计算 n 的阶乘(递归实现)
  2. bool isPrime(int n):判断 n 是否为素数
  3. void printArray(int arr[], int size):打印数组所有元素

11. 指针

通俗类比

想象一条街上有许多房子,每个房子都有一个门牌号(地址)。指针就是一张写着门牌号的纸条。纸条本身不是房子,但它告诉你可以去哪个门牌号找到房子。

在 C++ 里,& 是"取地址"(看门牌号),* 是"解引用"(根据门牌号找到房子里的东西)。

指针是 C++ 中最强大也最棘手的概念。初学者经常在这里卡住,但只要理解了"地址"这个概念,其实非常简单。

什么是指针?

C++
int age = 20;       // 普通变量,存在某个内存地址中
int* ptr = &age;    // ptr 存储 age 的地址

// & 是取地址运算符
cout << "age 的值: " << age << endl;      // 20
cout << "age 的地址: " << &age << endl;   // 0x7ffd1234(十六进制地址)
cout << "ptr 存的地址: " << ptr << endl; // 相同

// * 是解引用运算符:通过地址找到值
cout << "ptr 指向的值: " << *ptr << endl;  // 20

// 通过指针修改原变量
*ptr = 25;  // 等同于 age = 25;
cout << age << endl;  // 25

指针的基本操作

C++
int* p1;           // 声明指针(危险,可能指向随机地址)
int* p2 = nullptr; // 安全的方式:初始化为空指针

int x = 10;
int* p3 = &x;

// 指针运算:移动到下/上一个 int
p3++;  // 地址增加 sizeof(int) 个字节

指针和数组

数组名本质上就是指向第一个元素的指针:

C++
int arr[] = {10, 20, 30, 40};
int* ptr = arr;  // arr 等同于 &arr[0]

// 以下等价
cout << arr[0] << endl;   // 10
cout << *ptr << endl;      // 10
cout << *(ptr + 1) << endl; // 20,等同于 arr[1]

动态内存分配(new / delete)

new 在运行时申请内存,用 delete 释放:

C++
// 分配单个变量
int* p = new int;
*p = 100;
delete p;  // 释放

// 分配数组
int* arr = new int[5];
for (int i = 0; i < 5; i++) {
    arr[i] = i * 10;
}
delete[] arr;  // 数组用 delete[]
重要提醒

每有一个 new 就必须有一个 delete,否则会造成内存泄漏!程序吃掉的内存不还给系统,运行久了会卡顿甚至崩溃。数组必须用 delete[],不能用 delete

编程练习

编写程序演示指针的使用:

  1. 定义一个 int 变量 x = 10
  2. 定义指针 p 指向 x
  3. 通过指针修改 x 的值为 20
  4. 输出 x 的值和地址,以及 p 的值和指向的值

12. 引用

通俗类比

你有一个正式的名字叫"张伟",你妈妈叫你"伟伟",你同学叫你"大伟"。这些都是同一个你不同名字(别名)。引用就是变量的别名——它不创建新变量,只是给已有变量起了个小名。

引用的基本语法

C++
int original = 10;
int& ref = original;  // ref 是 original 的引用(别名)

ref = 20;  // 通过别名修改值

cout << original << endl;  // 20(original 也被改了)
cout << ref << endl;       // 20

// 它们占用同一个地址!
cout << &original << endl;  // 地址 A
cout << &ref << endl;       // 地址 A(相同!)

引用 vs 指针

特性引用指针
声明语法int& ref = x;int* ptr = &x;
是否需要初始化必须立即初始化可以先声明后赋值
能否重新指向不能(一旦绑定就不能改)可以指向不同对象
能否为空不能可以为 nullptr
使用方式像普通变量一样需要解引用 *
安全性更安全更灵活但容易出错

引用作为函数参数

这是引用最常见的用途——让函数能够修改调用者传递的变量:

C++
// 交换两个数(引用版本)
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 5, y = 10;
    swap(x, y);  // 调用后 x=10, y=5
    cout << x << " " << y << endl;
    return 0;
}

const 引用

如果你不想函数修改参数,但也不想拷贝(比如传递大对象),用 const 引用:

C++
// 只读引用:效率高且安全
void print(const string& str) {
    cout << str << endl;
    // str += "!";  // 错误!不能修改 const 引用
}

编程练习

编写一个 swapByRef(int& a, int& b) 函数,使用引用交换两个整数的值。与值传递版本 swapByVal(int a, int b) 对比测试,说明两者的区别。

13. 字符串

通俗类比

C 风格字符串就像一张写满字的纸,你必须自己数有多少字,自己控制不写出纸的边缘。而 C++ 的 string 类就像一个智能笔记本——它会自动帮你计数、自动扩展纸张大小,还能方便地拼接、查找和替换文字。

C++ string 类(推荐)

C++
#include <string>
using namespace std;

int main() {
    string s1 = "Hello";     // 创建字符串
    string s2("World");     // 另一种方式

    // 拼接
    string s3 = s1 + " " + s2;  // "Hello World"

    // 获取长度
    cout << s1.length() << endl;  // 5

    // 访问字符
    cout << s1[0] << endl;    // 'H'
    cout << s1.at(0) << endl; // 'H'(安全版本)

    // 比较
    if (s1 == s2) cout << "相等" << endl;
    if (s1 < s2) cout << "s1 在字典序上更小" << endl;

    // 查找
    size_t pos = s3.find("World");
    if (pos != string::npos) {
        cout << "找到了,位置: " << pos << endl;  // 6
    }

    // 截取子串
    string sub = s3.substr(0, 5);  // "Hello"

    // C++11 范围 for 遍历
    for (char ch : s1) {
        cout << ch << "-";
    }

    return 0;
}

从键盘读取字符串

C++
string name;
cout << "请输入名字: ";
cin >> name;  // cin 遇到空格就停止

// 读取整行(包含空格)
cin.ignore();  // 清除缓冲区残留的换行符
cout << "请输入全名: ";
getline(cin, name);  // 读取一整行
提示

混合使用 cin >>getline 时,cin >> 会在输入缓冲区留下一个换行符,导致 getline 读到空行。解决方法是在 getline 前调用 cin.ignore(); 清除残留的换行符。

编程练习

编写程序处理字符串:

  1. 读取用户输入的一个字符串
  2. 输出字符串的长度
  3. 输出字符串的第一个和最后一个字符
  4. 判断字符串是否为回文(正读反读相同)

14. 结构体

通俗类比

你班上的学生档案包含:姓名、年龄、性别、成绩。这四种信息类型各不相同(名字是文字、年龄是数字),但属于同一个人结构体就是把这些不同类型的数据打包在一起的方式——就像把一个人的所有信息写在同一张档案卡上。

定义和使用结构体

C++
#include <string>
using namespace std;

// 定义结构体(学生档案)
struct Student {
    string name;    // 姓名
    int age;        // 年龄
    double score;   // 成绩
};

int main() {
    // 创建结构体变量
    Student stu1;
    stu1.name = "小明";
    stu1.age = 16;
    stu1.score = 89.5;

    // 列表初始化(C++11)
    Student stu2 = {"小红", 15, 92.0};

    // 访问成员用 . 运算符
    cout << stu1.name << " " << stu1.age << "岁 " << stu1.score << "分" << endl;

    return 0;
}

结构体数组和指针

C++
// 结构体数组
Student class1[3] = {
    {"张三", 16, 85},
    {"李四", 17, 90},
    {"王五", 16, 78}
};

// 遍历
for (int i = 0; i < 3; i++) {
    cout << class1[i].name << " " << class1[i].score << endl;
}

// 结构体指针用 -> 访问成员
Student stu = {"Alice", 16, 90};
Student* ptr = &stu;
cout << ptr->name << endl;  // Alice(等同于 (*ptr).name)

嵌套结构体

C++
struct Date {
    int year, month, day;
};

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

// 使用
Person p = {"张三", {2008, 5, 15}, "北京"};
cout << p.name << "的生日是 " << p.birthday.year << "年" << endl;

编程练习

定义一个 Student 结构体,包含姓名、学号、语文、数学、英语成绩。创建一个包含 3 名学生的数组,计算并输出每名学生的总分和平均分,以及全班的最高分学生。

16. 文件操作——把数据存进硬盘

通俗类比

想象你在写一本日记。如果只是写在草稿纸上,关机(睡觉)后就没了。文件操作就像把日记写进笔记本里保存起来,下次打开还能继续看。

程序运行时的数据都保存在内存中,关机就没了。fstream 库让你把数据读写到硬盘上的文件里。

包含头文件和基础对象

C++
#include <fstream>   // 文件流
#include <iostream>
using namespace std;

// 三个常用类:
// ofstream —— 写文件(output file stream)
// ifstream —— 读文件(input file stream)
// fstream  —— 读写都行

写入文件

C++
// 打开文件写入(像打开笔记本准备写)
ofstream outFile("diary.txt");

// 检查是否成功打开
if (!outFile) {
    cout << "打不开文件!" << endl;
    return 1;
}

// 用 << 像 cout 一样写入
outFile << "今天是2026年5月2日" << endl;
outFile << "我学会了C++的文件操作!" << endl;

// 关闭文件(像合上笔记本)
outFile.close();
cout << "保存成功!" << endl;
提示

如果文件不存在,ofstream 会自动创建;如果已存在,默认会覆盖原有内容!

追加模式(不覆盖原有内容)

C++
// ios::app = append 追加模式
ofstream outFile("diary.txt", ios::app);
outFile << "这是一条新日记" << endl;
outFile.close();

读取文件

C++
// 打开文件读取
ifstream inFile("diary.txt");

if (!inFile) {
    cout << "找不到文件!" << endl;
    return 1;
}

// 方法一:逐行读取(最常用)
string line;
while (getline(inFile, line)) {
    cout << line << endl;
}

// 方法二:逐个单词读取
// string word;
// while (inFile >> word) { cout << word << endl; }

inFile.close();

读写数值数据

C++
// 保存学生成绩到文件
ofstream out("scores.txt");
int scores[] = {85, 92, 78, 96};
for (int s : scores) {
    out << s << endl;
}
out.close();

// 从文件读取并计算总分
ifstream in("scores.txt");
int score, total = 0, count = 0;
while (in >> score) {   // 像cin一样用 >> 读取数字
    total += score;
    count++;
}
in.close();
cout << "平均分: " << (double)total / count << endl;

编程练习

写一个"通讯录程序",把3个朋友的姓名和电话号码保存到 contacts.txt,然后再读取显示出来。

编程练习

编写程序实现简单的学生成绩文件管理:

  1. 将 3 名学生的姓名和成绩写入 scores.txt
  2. scores.txt 读取数据并计算平均分
  3. 将统计结果追加写入同一文件

17. 面向对象基础——封装与类

通俗类比

想象一辆遥控汽车。你不用知道里面电机怎么转、电路怎么连,只需要按按钮(方法),车就会跑。"类"就像这辆车的设计图纸,把复杂的内部结构封装起来,只露出简单的操作按钮。

面向对象编程(OOP)是现代编程的核心思想。它把数据和操作数据的函数打包在一起,形成一个整体。

类的定义

C++
// class = 类,一种自定义的数据类型
// 把 属性(数据)和 方法(函数)打包在一起
class Car {
public:                           // 公开的:外部可以访问
    // 属性(成员变量)
    string brand;     // 品牌
    int speed;        // 当前速度

    // 方法(成员函数)
    void accelerate() {
        speed += 10;
        cout << brand << " 加速到 " << speed << " km/h" << endl;
    }

    void brake() {
        speed = 0;
        cout << brand << " 已停车" << endl;
    }
};

创建对象和使用

C++
Car myCar;           // 根据"图纸"造出一辆车(对象)
myCar.brand = "BYD";  // 设置品牌
myCar.speed = 0;    // 初始速度

myCar.accelerate();  // BYD 加速到 10 km/h
myCar.accelerate();  // BYD 加速到 20 km/h
myCar.brake();       // BYD 已停车

构造函数——对象出生时的初始化

C++
class Student {
public:
    string name;
    int age;

    // 构造函数:和类同名、无返回值,创建对象时自动调用
    Student(string n, int a) {
        name = n;
        age = a;
        cout << "学生 " << name << " 入学了!" << endl;
    }
};

// 创建时直接传参数
Student stu("小明", 15);   // 自动调用构造函数

访问修饰符

修饰符含义比喻
public任何人都能访问公开教室,谁都能进
private只有类内部能访问私人日记,只有自己能看
protected类和子类能访问家族秘密,只有家人知道
C++
class BankAccount {
private:
    double balance;   // 私有:外部不能直接修改余额

public:
    // 只能通过公开的方法来操作
    void deposit(double amount) {
        if (amount > 0) balance += amount;
    }

    void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }

    double getBalance() {
        return balance;   // 只能看,不能直接改
    }
};

编程练习

定义一个 Book 类,包含 title(书名)、author(作者)、price(价格)属性,以及一个 show() 方法显示图书信息。创建2本书并调用 show()。

编程练习

定义一个 Rectangle 类,包含私有成员 widthheight,以及公有方法:

  1. 构造函数初始化宽和高
  2. area() 计算面积
  3. perimeter() 计算周长
  4. setWidth/setHeight 设置新尺寸(带有效性检查,不能为负数)

main 中创建对象并测试所有方法。

18. 课后练习与项目实践

以下作业按难度分为 基础巩固(必做)、进阶挑战(选做)和 综合项目(综合运用)。每道题都附有参考实现,先独立完成再对照查看。

基础练习(必做)

作业 1:温度转换器

编写程序,让用户输入摄氏温度,输出对应的华氏温度。公式:华氏 = 摄氏 × 9/5 + 32

参考实现

C++
#include <iostream>
using namespace std;

int main() {
    double celsius;
    cout << "请输入摄氏温度: ";
    cin >> celsius;
    double fahrenheit = celsius * 9.0 / 5 + 32;
    cout << "华氏温度: " << fahrenheit << "°F" << endl;
    return 0;
}

作业 2:判断闰年

让用户输入一个年份,判断它是不是闰年。规则:能被4整除但不能被100整除,或者能被400整除。

参考实现

C++
#include <iostream>
using namespace std;

int main() {
    int year;
    cout << "输入年份: ";
    cin >> year;

    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
        cout << year << " 是闰年" << endl;
    } else {
        cout << year << " 不是闰年" << endl;
    }
    return 0;
}

作业 3:计算阶乘

用循环计算 n 的阶乘(n! = 1×2×3×...×n)。比如 5! = 120。要求用函数实现。

参考实现

C++
#include <iostream>
using namespace std;

long long factorial(int n) {
    long long result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
}

int main() {
    int n;
    cout << "请输入 n: ";
    cin >> n;
    cout << n << "! = " << factorial(n) << endl;
    return 0;
}

作业 4:数组排序

让用户输入5个整数,存入数组,然后用冒泡排序从小到大排列并输出。

参考实现

C++
#include <iostream>
using namespace std;

int main() {
    int arr[5];
    cout << "输入5个整数:" << endl;
    for (int i = 0; i < 5; i++) cin >> arr[i];

    // 冒泡排序
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }

    cout << "排序后: ";
    for (int n : arr) cout << n << " ";
    cout << endl;
    return 0;
}

进阶练习(选做)

作业 5:判断回文数

输入一个正整数,判断它是否是"回文数"(正着读反着读都一样,如 121、1331)。

参考实现

C++
#include <iostream>
using namespace std;

bool isPalindrome(int n) {
    if (n < 0) return false;
    long long reversed = 0, original = n;
    while (n > 0) {
        reversed = reversed * 10 + n % 10;
        n /= 10;
    }
    return original == reversed;
}

int main() {
    int n;
    cin >> n;
    cout << (isPalindrome(n) ? "是回文数" : "不是回文数") << endl;
    return 0;
}

作业 6:学生成绩管理系统(数组版)

定义一个包含5名学生的结构体数组(姓名、语文、数学、英语),实现功能:
1. 输入所有学生信息
2. 计算并显示每个学生的总分和平均分
3. 找出总分最高的学生

参考实现

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

struct Student {
    string name;
    int chinese, math, english;
    int total() { return chinese + math + english; }
    double avg() { return total() / 3.0; }
};

int main() {
    const int N = 3;
    Student s[N];

    for (int i = 0; i < N; i++) {
        cout << "输入学生" << i + 1 << " 姓名 语文 数学 英语: ";
        cin >> s[i].name >> s[i].chinese >> s[i].math >> s[i].english;
    }

    int maxIdx = 0;
    for (int i = 0; i < N; i++) {
        cout << s[i].name << " 总分=" << s[i].total()
             << " 平均=" << s[i].avg() << endl;
        if (s[i].total() > s[maxIdx].total()) maxIdx = i;
    }
    cout << "最高分: " << s[maxIdx].name << endl;
    return 0;
}

综合项目实践

项目 1:命令行计算器(综合)

项目目标

制作一个支持加减乘除、取模、幂运算的命令行计算器,循环运行直到用户输入 "exit"。要求用函数封装每个运算。

参考实现

C++
#include <iostream>
#include <cmath>
using namespace std;

double add(double a, double b) { return a + b; }
double sub(double a, double b) { return a - b; }
double mul(double a, double b) { return a * b; }
double divi(double a, double b) {
    if (b == 0) { cout << "除零错误!"; return 0; }
    return a / b;
}

int main() {
    string op;
    double a, b;
    while (true) {
        cout << "输入操作 (+ - * / ^ % 或 exit): ";
        cin >> op;
        if (op == "exit") break;
        cout << "输入两个数: ";
        cin >> a >> b;

        if (op == "+") cout << "结果: " << add(a, b) << endl;
        else if (op == "-") cout << "结果: " << sub(a, b) << endl;
        else if (op == "*") cout << "结果: " << mul(a, b) << endl;
        else if (op == "/") cout << "结果: " << divi(a, b) << endl;
        else if (op == "^") cout << "结果: " << pow(a, b) << endl;
        else if (op == "%") cout << "结果: " << (int)a % (int)b << endl;
        else cout << "未知操作" << endl;
    }
    cout << "再见!" << endl;
    return 0;
}

项目 2:猜数字游戏

项目目标

程序随机生成1-100之间的数字,用户猜测,程序提示"太大"或"太小",统计猜测次数,猜中后恭喜用户。要求用到随机数、循环、条件判断。

参考实现

C++
#include <iostream>
#include <cstdlib>   // rand(), srand()
#include <ctime>     // time()
using namespace std;

int main() {
    srand(time(0));                    // 用当前时间做随机种子
    int secret = rand() % 100 + 1;    // 1~100
    int guess, count = 0;

    cout << "猜数字游戏!我想了一个1-100的数字。" << endl;
    while (true) {
        cout << "你的猜测: ";
        cin >> guess;
        count++;
        if (guess > secret) cout << "太大了!" << endl;
        else if (guess < secret) cout << "太小了!" << endl;
        else {
            cout << "恭喜你猜对了!答案是 " << secret
                 << ",你猜了 " << count << " 次。" << endl;
            break;
        }
    }
    return 0;
}

项目 3:待办事项清单(文件版)

项目目标

制作一个命令行待办事项清单,支持:添加任务、查看所有任务、删除任务、保存到文件。下次运行能读取之前的任务。

参考实现

C++
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

const int MAX = 100;
string tasks[MAX];
int taskCount = 0;
string filename = "todo.txt";

void load() {
    ifstream in(filename);
    taskCount = 0;
    while (taskCount < MAX && getline(in, tasks[taskCount])) {
        taskCount++;
    }
}

void save() {
    ofstream out(filename);
    for (int i = 0; i < taskCount; i++) out << tasks[i] << endl;
}

void show() {
    if (taskCount == 0) { cout << "暂无任务" << endl; return; }
    for (int i = 0; i < taskCount; i++)
        cout << i + 1 << ". " << tasks[i] << endl;
}

void add(string t) {
    if (taskCount < MAX) tasks[taskCount++] = t;
}

void remove(int idx) {
    if (idx < 1 || idx > taskCount) return;
    for (int i = idx - 1; i < taskCount - 1; i++)
        tasks[i] = tasks[i + 1];
    taskCount--;
}

int main() {
    load();
    string cmd;
    cout << "=== 待办清单 === (add/show/del/save/quit)" << endl;
    while (true) {
        cout << "> "; cin >> cmd;
        if (cmd == "quit") { save(); break; }
        else if (cmd == "show") show();
        else if (cmd == "add") {
            cin.ignore();
            string t; getline(cin, t); add(t);
        }
        else if (cmd == "del") {
            int n; cin >> n; remove(n);
        }
        else if (cmd == "save") save();
        else cout << "未知命令" << endl;
    }
    return 0;
}
学习建议

这18节基础知识学完后,你已经具备了扎实的 C++ 基本功!建议先完成所有基础作业,再挑战进阶题目和综合项目。遇到问题时:先思考5分钟 → 查笔记 → 看答案理解 → 自己重写一遍。这才是真正的学习。