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++ 程序也是这样的结构:
#include <iostream> int main() { std::cout << "Hello, World!" << std::endl; return 0; }
这段代码做了三件事:
#include <iostream>—— "我要使用输入输出功能"std::cout << "Hello, World!"—— "在屏幕上显示这句话"return 0;—— "正常结束"
不用担心现在看不懂代码。就像你第一天学英语看不懂整篇文章一样,后面的每一节我们会把每个符号、每行代码都讲清楚。耐心学完这一章,你一定能看懂。
编程练习
编写一个程序,输出三行文字:第一行是你的姓名,第二行是你的年龄,第三行是"开始学习C++"。要求每行末尾换行。
2. 环境搭建
通俗类比
学画画需要画笔和纸,学做饭需要锅和食材。学编程也需要工具:一个能把 C++ 代码翻译成计算机指令的翻译官(编译器),以及一个方便你写代码的编辑器(IDE)。
在写代码之前,我们需要在电脑上安装两个东西:
- 编译器:把 C++ 代码翻译成计算机能执行的语言。常用的有 Visual Studio(Windows)、Xcode(Mac)、g++(所有平台)。
- 编辑器 / IDE:写代码的地方。IDE 是"集成开发环境",简单说就是"全能写代码工具",能写代码、调试错误、运行程序。
Windows 用户 —— 安装 Visual Studio
Visual Studio 是微软官方的开发工具,功能强大,对新手最友好。
- 打开浏览器,访问
visualstudio.microsoft.com/zh-hans/ - 下载 Visual Studio Community(社区版),这是免费的
- 运行下载的安装程序,勾选"使用 C++ 的桌面开发"这一项
- 点击"安装",等待下载完成(大约 2-5GB,需要一些时间)
- 打开 Visual Studio,点击"创建新项目" → "空项目" → 输入项目名称(如 HelloWorld)→ 确定
- 在右侧"解决方案资源管理器"中,右键点击"源文件" → 添加 → 新建项 → 选择"C++ 文件(.cpp)" → 命名为
main.cpp - 在代码编辑区输入你的代码,按 F5 运行!
Mac 用户 —— 安装 Xcode
- 打开 App Store,搜索 "Xcode",下载安装(大约 10GB)
- 或者打开终端,输入
xcode-select --install,只安装命令行工具(几百 MB) - 打开 Xcode,创建新项目 → macOS → Command Line Tool → 选择 C++ 语言
- 写代码后,点击左上角的"运行"按钮()
最简单的验证方法
安装完成后,创建一个文件,输入以下内容:
#include <iostream> int main() { std::cout << "我的环境配置成功啦!" << std::endl; return 0; }
如果能运行并看到输出文字,恭喜你,环境搭建成功!
如果在安装过程中遇到问题,不要着急。常见问题:安装包太大下载慢(可以找 WiFi 好的地方)、找不到"使用 C++ 的桌面开发"选项(点击"修改"后可以看到)。遇到任何报错都可以复制到百度搜索,99%的问题都有人遇到过。
编程练习
安装完编译器后,编写并运行第一个C++程序,输出"Hello, C++ World!"到控制台。确保程序能够成功编译并执行。
3. 第一个 C++ 程序
通俗类比
学习任何语言的第一步都是说"你好"。学英语说 "Hello",学日语说 "Konnichiwa"。学编程语言也一样,第一个程序永远是让电脑说 "Hello, World!"。这就像是和电脑打了个招呼,确认它能听懂你的话。
现在,在你的编辑器里输入这段代码:
// 这是一行注释,计算机不会执行注释的内容 // 第1行:告诉电脑"我要用输入输出功能" #include <iostream> // 第3行:程序从这里开始执行 int main() { // 第5行:在屏幕上显示文字 std::cout << "Hello, World!" << std::endl; // 第7行:告诉电脑"我正常结束了" return 0; }
逐行解析(每一行都讲清楚)
第1行:// 这是一行注释...
以 // 开头的文字是注释。注释是给程序员看的,计算机完全无视它们。好的注释能让你的代码更容易理解。
// 这是单行注释 /* 这是多行注释 可以写很多行 计算机都不会执行 */ 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; 来偷懒:
#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 ~ 32767 | 1000 |
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"。不写也行,编译器会自动选择。
类型的简单使用
#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 —— 查看数据占多大空间
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。
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):
- 一个
int变量,值为 42 - 一个
double变量,值为 3.14159 - 一个
char变量,值为 'A' - 一个
bool变量,值为 true
5. 变量和常量
通俗类比
变量就像是一个带标签的盒子。盒子里可以装东西,你可以随时更换里面的东西。比如一个标签为"年龄"的盒子,今年装的是 15,明年装的是 16。
常量则像是一个被焊死的盒子,一旦装好就不能改了。比如圆周率 π 永远是 3.14159,你不能"改天把它改成 4"。
什么是变量?
变量 = 一个名字 + 一个值。创建变量的过程叫做"声明"或"定义":
// 变量声明:类型 名字 = 初始值; 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++ 区分大小写:
Age和age是两个不同的变量
// 好的命名 int studentAge; int student_age; // 下划线风格 double mathScore; // 不好的命名 // int 1stPlace; // 不能以数字开头 // int my age; // 不能有空格 // int class; // class 是关键字
常量(不会变的值)
如果你有一些永远不应该改变的值,比如数学常数、游戏的最大生命值等,用 const 定义常量:
const double PI = 3.14159; // 圆周率 const int MAX_LIVES = 3; // 最大生命数 // PI = 3.14; // 错误!不能修改常量 // constexpr 是更高级的常量(编译时就能确定值) constexpr int SQUARE(int x) { return x * x; }
变量的作用域
作用域就是变量"能被人看到"的范围。在大括号 {} 里创建的变量,只能在这个大括号里使用。
#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米,喜欢编程:是
编程练习
编写程序完成以下任务:
- 定义一个
const double PI = 3.14159 - 定义一个变量
radius,初始值为 5.0 - 计算圆的面积(PI * radius * radius)并输出
- 尝试修改 PI 的值,观察编译器报错信息
6. 运算符
通俗类比
运算符就像是计算器上的按钮:+ 是加,- 是减,× 是乘,÷ 是除。C++ 里的运算符本质上和数学课上学的一模一样,只是有些符号长得不一样(比如乘法是 * 不是 ×)。
算术运算符
| 运算符 | 名字 | 例子 | 结果 |
|---|---|---|---|
+ | 加 | 5 + 3 | 8 |
- | 减 | 5 - 3 | 2 |
* | 乘 | 5 * 3 | 15 |
/ | 除 | 5 / 3 | 1(整数除法会截断!) |
% | 取余(模) | 5 % 3 | 2(5除以3余2) |
整数除法会截断小数!5 / 2 得到 2,不是 2.5!% 是取余数,5 % 2 = 1。想要精确结果,把至少一个数改成小数:5.0 / 2 = 2.5。
自增和自减
++ 让变量加 1,-- 让变量减 1。注意前置和后置的区别:
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 == 5 | true |
!= | 不等于 | 5 != 3 | true |
> | 大于 | 5 > 3 | true |
< | 小于 | 5 < 3 | false |
>= | 大于等于 | 5 >= 5 | true |
<= | 小于等于 | 5 <= 3 | false |
不要把 ==(等于)和 =(赋值)搞混!if (a == 5) 是"判断 a 是否等于 5",a = 5 是"把 5 赋给 a"。写错会导致奇怪的错误。
逻辑运算符
| 运算符 | 含义 | 例子 | 结果 |
|---|---|---|---|
&& | 与(并且) | true && false | false(两个都为真才为真) |
|| | 或(或者) | true || false | true(有一个为真就为真) |
! | 非(取反) | !true | false |
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 = 17 和 b = 5,计算并输出它们的和、差、积、商、余数(a对b取模)以及 a 自增后的值。
7. 条件语句
通俗类比
条件语句就像是生活中的"如果……就……"。比如:"如果明天下雨,就带伞;否则,穿短袖。"程序也是一样,可以根据不同的条件执行不同的代码。
if 语句
最简单的条件判断。如果条件为真(true),就执行大括号里的代码。
#include <iostream> using namespace std; int main() { int age; cout << "请输入你的年龄: "; cin >> age; // 从键盘读取一个整数 if (age >= 18) { cout << "你已经成年了!" << endl; } return 0; }
if-else 语句
"如果条件成立就做 A,否则做 B":
int score; cout << "请输入成绩: "; cin >> score; if (score >= 60) { cout << "恭喜,及格了!" << endl; } else { cout << "不及格,下次加油!" << endl; }
if-else if-else(多个条件)
当有多个条件要判断时,用 else if:
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 更清晰:
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)
对于简单的二选一,可以写得更加简洁:
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 循环适合"我知道要循环多少次"的场景:
// 语法: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 循环在条件为真时一直执行,适合"我不知道要循环几次"的场景:
// 用户输入验证 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 | 跳过当前这次,继续下一次循环 |
// 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 个柜子……
创建和使用数组
// 声明数组:类型 名字[大小]; 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++ 中最常见的错误之一!
二维数组(表格/矩阵)
二维数组就像一张表格,有行有列:
// 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; }
获取数组大小
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。编写程序计算:
- 数组所有元素的和
- 数组所有元素的平均值
- 数组中的最大值和最小值
要求使用循环遍历数组,不要使用现成函数。
10. 函数
通俗类比
函数就像是一个"工具"或"机器人"。你给这个工具一些原材料(参数),它经过处理后给你一个成品(返回值)。比如榨汁机:你把水果放进去(参数),它给你果汁(返回值)。
函数最大的好处是可以重复使用。你写好一个求最大值的函数,以后每次需要求最大值都可以直接用它,不用重新写。
函数的基本结构
// 返回类型 函数名(参数列表) { 函数体 } // 定义一个加法函数 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 | 是 | 动态内存、可选参数 |
// 值传递:不能交换成功 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; }
默认参数
可以给参数设置默认值,调用时如果不传就使用默认值:
// greeting 有默认值 "你好" void greet(string name, string greeting = "你好") { cout << greeting << ", " << name << "!" << endl; } // 调用 greet("小明"); // 你好, 小明! greet("小红", "早上好"); // 早上好, 小红!
函数重载
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 版本)
递归函数
函数调用自身,叫做递归。经典例子:阶乘和斐波那契数列。
// 阶乘: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 中测试:
int factorial(int n):计算 n 的阶乘(递归实现)bool isPrime(int n):判断 n 是否为素数void printArray(int arr[], int size):打印数组所有元素
11. 指针
通俗类比
想象一条街上有许多房子,每个房子都有一个门牌号(地址)。指针就是一张写着门牌号的纸条。纸条本身不是房子,但它告诉你可以去哪个门牌号找到房子。
在 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
指针的基本操作
int* p1; // 声明指针(危险,可能指向随机地址) int* p2 = nullptr; // 安全的方式:初始化为空指针 int x = 10; int* p3 = &x; // 指针运算:移动到下/上一个 int p3++; // 地址增加 sizeof(int) 个字节
指针和数组
数组名本质上就是指向第一个元素的指针:
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 释放:
// 分配单个变量 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。
编程练习
编写程序演示指针的使用:
- 定义一个
int变量x = 10 - 定义指针
p指向x - 通过指针修改
x的值为 20 - 输出
x的值和地址,以及p的值和指向的值
12. 引用
通俗类比
你有一个正式的名字叫"张伟",你妈妈叫你"伟伟",你同学叫你"大伟"。这些都是同一个你的不同名字(别名)。引用就是变量的别名——它不创建新变量,只是给已有变量起了个小名。
引用的基本语法
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 |
| 使用方式 | 像普通变量一样 | 需要解引用 * |
| 安全性 | 更安全 | 更灵活但容易出错 |
引用作为函数参数
这是引用最常见的用途——让函数能够修改调用者传递的变量:
// 交换两个数(引用版本) 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 引用:
// 只读引用:效率高且安全 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 类(推荐)
#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; }
从键盘读取字符串
string name; cout << "请输入名字: "; cin >> name; // cin 遇到空格就停止 // 读取整行(包含空格) cin.ignore(); // 清除缓冲区残留的换行符 cout << "请输入全名: "; getline(cin, name); // 读取一整行
混合使用 cin >> 和 getline 时,cin >> 会在输入缓冲区留下一个换行符,导致 getline 读到空行。解决方法是在 getline 前调用 cin.ignore(); 清除残留的换行符。
编程练习
编写程序处理字符串:
- 读取用户输入的一个字符串
- 输出字符串的长度
- 输出字符串的第一个和最后一个字符
- 判断字符串是否为回文(正读反读相同)
14. 结构体
通俗类比
你班上的学生档案包含:姓名、年龄、性别、成绩。这四种信息类型各不相同(名字是文字、年龄是数字),但属于同一个人。结构体就是把这些不同类型的数据打包在一起的方式——就像把一个人的所有信息写在同一张档案卡上。
定义和使用结构体
#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; }
结构体数组和指针
// 结构体数组 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)
嵌套结构体
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 库让你把数据读写到硬盘上的文件里。
包含头文件和基础对象
#include <fstream> // 文件流 #include <iostream> using namespace std; // 三个常用类: // ofstream —— 写文件(output file stream) // ifstream —— 读文件(input file stream) // fstream —— 读写都行
写入文件
// 打开文件写入(像打开笔记本准备写) ofstream outFile("diary.txt"); // 检查是否成功打开 if (!outFile) { cout << "打不开文件!" << endl; return 1; } // 用 << 像 cout 一样写入 outFile << "今天是2026年5月2日" << endl; outFile << "我学会了C++的文件操作!" << endl; // 关闭文件(像合上笔记本) outFile.close(); cout << "保存成功!" << endl;
如果文件不存在,ofstream 会自动创建;如果已存在,默认会覆盖原有内容!
追加模式(不覆盖原有内容)
// ios::app = append 追加模式 ofstream outFile("diary.txt", ios::app); outFile << "这是一条新日记" << endl; outFile.close();
读取文件
// 打开文件读取 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();
读写数值数据
// 保存学生成绩到文件 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,然后再读取显示出来。
编程练习
编写程序实现简单的学生成绩文件管理:
- 将 3 名学生的姓名和成绩写入
scores.txt - 从
scores.txt读取数据并计算平均分 - 将统计结果追加写入同一文件
17. 面向对象基础——封装与类
通俗类比
想象一辆遥控汽车。你不用知道里面电机怎么转、电路怎么连,只需要按按钮(方法),车就会跑。"类"就像这辆车的设计图纸,把复杂的内部结构封装起来,只露出简单的操作按钮。
面向对象编程(OOP)是现代编程的核心思想。它把数据和操作数据的函数打包在一起,形成一个整体。
类的定义
// 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; } };
创建对象和使用
Car myCar; // 根据"图纸"造出一辆车(对象) myCar.brand = "BYD"; // 设置品牌 myCar.speed = 0; // 初始速度 myCar.accelerate(); // BYD 加速到 10 km/h myCar.accelerate(); // BYD 加速到 20 km/h myCar.brake(); // BYD 已停车
构造函数——对象出生时的初始化
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 | 类和子类能访问 | 家族秘密,只有家人知道 |
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 类,包含私有成员 width 和 height,以及公有方法:
- 构造函数初始化宽和高
area()计算面积perimeter()计算周长setWidth/setHeight设置新尺寸(带有效性检查,不能为负数)
在 main 中创建对象并测试所有方法。
18. 课后练习与项目实践
以下作业按难度分为 基础巩固(必做)、进阶挑战(选做)和 综合项目(综合运用)。每道题都附有参考实现,先独立完成再对照查看。
基础练习(必做)
作业 1:温度转换器
编写程序,让用户输入摄氏温度,输出对应的华氏温度。公式:华氏 = 摄氏 × 9/5 + 32
参考实现
#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整除。
参考实现
#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。要求用函数实现。
参考实现
#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个整数,存入数组,然后用冒泡排序从小到大排列并输出。
参考实现
#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)。
参考实现
#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. 找出总分最高的学生
参考实现
#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"。要求用函数封装每个运算。
参考实现
#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之间的数字,用户猜测,程序提示"太大"或"太小",统计猜测次数,猜中后恭喜用户。要求用到随机数、循环、条件判断。
参考实现
#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:待办事项清单(文件版)
项目目标
制作一个命令行待办事项清单,支持:添加任务、查看所有任务、删除任务、保存到文件。下次运行能读取之前的任务。
参考实现
#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分钟 → 查笔记 → 看答案理解 → 自己重写一遍。这才是真正的学习。