笔记C++语言,太焦虑了
调查研究
Javascript
基础知识
介绍
**javascript是一种运行在客户端(浏览器)的编程语言 ,实现人机交互效果 **
- 作用:网页特效、表单验证、数据交互、服务器编程(node.js)
组成:
- ECMAScripts —> 规定js的基础语法核心知识
- Web APIs  —>
- DOM 操作文档,比如对页面元素进行移动、大小、添加删除操作
- BOM 操作浏览器,比如页面弹窗,检测窗口宽度、存储数据到浏览器
 
- 书写位置
- 
内部js —>写在html里面,用script标签,写在上面 
- 
外部js —>代码写在js文件,引入html页面 
- 
内联js —>代码写在标签内部 <script> prompt("hello,world")document.write('你好,js') </script>
- 
注释 单行注释 // 快捷键 Ctrl + / 
 块注释 /* */ 快捷键 shift + alt + a
 结束符 —>英文分号代表语句结束 ;
- 输入输出语法
输出语法:向body输出内容 document.write('你好,js')
                       页面警示框 alert('你好,js')
                       控制台输出语法 console.log('你好,js')
输入语法:  提示输入prompt('请输入hello,world')
- 代码执行顺序
alert()和prompt()会跳过页面渲染先被执行
变量
- 变量的定义
变量是计算机存储数据的容器
- 变量的声明
创建变量:声明关键字、变量名
let 变量名
赋值:对变量进行初始化
let age = 18
//let不允许多次声明一个变量
交换两个变量的值,引入第三个变量temp
- 变量的本质
内存–>计算机存储数据的地方,程序在内存中申请一小块用来存放数据的小空间
- 变量的命名规范
由数字、字母、下划线、$符号组成,不能使用关键字,不能以数字开头;严格区分大小写
- let和var的区别
var可以先使用在声明、声明过的变量可以重复声明;变量提升、全局变量、没有块级作用域
声明变量统一用let
- 常量
概念:是一个不能被修改的值,通常用于表示固定、不变的量,使用const变量
使用:const PI = 3.1415926
常量不允许重新赋值,声明的时候必须复制(初始化)
- 数据类型(弱数据类型语言)
①基本数据类型
number、string、boolean、undefined、null、
②引用数据类型
object、function、array
数字–number
- 
定义: number类型用于表示整数和浮点数,包括正数、负数和零
- 
算术运算符 ( + - * / % >> 取余)  
- 
特别地: NaN是一个特殊的数值状态,它不等于任何值,包括自己,因此NaN != NaN
任何对NaN的操作都是返回NaN
字符串–string
- 用于存储文本数据的变量类型。字符串由字符组成,可以包含字母、数字、标点符号等;单引号、双引号、反引号包裹的数据
- 字符串拼接 ‘+’;
- 模版字符串
语法:``反引号
内容拼接变量时,用${ }包裹变量
${变量名}
其他类型
- 布尔类型—boolean
是一种数据类型,用于表示逻辑值,只有两种可能的值:true 和 false
- 未定义类型—undefined
未定义类型"通常指的是在程序运行时,遇到的与变量类型相关的错误;声明变量未赋值
- 空类型—null
表示一个变量被赋值为 null,将来存放对象
类型转换
typeof或typeof ()—>用于获取变量的类型
let num = 10
typeof num 
隐式转换:+ 两边只要有字符串,默认为字符串计算,其他算术运算符为数字类型
+'123'可转为数字类型
Number( ) 函数可以将字符串转换为数字
parseInt( ) 函数用于将字符串转换为整数
parsefloat( ) 函数将字符串转换为浮点数
运算符
赋值运算符(=、+=)
对变量进行赋值的运算符
let b = 5;
b += 3; // b现在等于8,等同于b = b + 3一元运算符(+)
只需要一个表达式就可运算,自增++和 自减–
自增运算符
- 前缀形式(++a):先增加值,再使用该值。
- 后缀形式(a++):先使用原值,再增加值。
自减运算符
- 前缀形式(--a):先减少值,再使用该值。
- 后缀形式(a--):先使用原值,再减少值。
比较运算符(> <)
比较运算符有隐式转换
- <=:小于等于
- ==:等于
- !=:不等于
- ===:严格等于
- !==:严格不等于
- 字符串比较
字符串比较转换为对应的ASCII码比较
逻辑运算符&&
逻辑与(全真为真)—&&
逻辑或(一真则真)—||
逻辑非 (非真即假)—!
流程控制语句
- 
顺序结构>>从上到下、依次执行 
- 
分支结构 - if:条件为真就执行
- else:否则执行这里
- switch:匹配哪个 case 就执行哪个
 
- 
循环结构 - for:计数循环,条件成立就继续
- while:先判后做,成立才循环
- do...while:先做后判,至少执行一次
- for:用于遍历数据结构
 - for...of:获取元素值(如数组元素、字符串字符)
- for...in:获取键名(如对象键、数组索引字符串)
 
- 
break和continue 
 break:彻底结束循环,立即跳出。
 continue:跳过当前迭代,继续下一轮循环
数组array
- 定义
 数组是一个有序的存储容器,用于存储多个值。这些值可以是 primitives(如字符串、数字、 boolean、 null、 undefined)或 objects(对象)、 arrays(数组)等复杂的值。
- 声明语法
let 数组名  = [数据]
- 访问
数组名[索引号]
长度–>数组的length获得:数组名.length
- 遍历
i <= array.length-1,确保索引不超过数组的最后一个元素(索引为 length-1)
进阶知识
HTML
基础知识
CSS
基础知识
Linux
基础知识
前景提要
- 计算机的主要组成部分:硬件系统和软件系统
操作系统(Operating System, OS)是计算机系统中负责管理和控制计算机及其资源的核心软件;
移动操作系统
- 安卓(Android)
- iOS
- 鸿蒙(HarmonyOS)
PC操作系统
- Windows
- macOS
- Linux
Linux的主要发行版:Ubuntu/RedHat/Centos
Windows操作系统
WSL(Windows Subsystem for Linux)
- WSL2:基于轻量级虚拟机(Hyper-V),提供完整的Linux内核,文件系统性能大幅提升,推荐使用。
Linux知识
Linux系统的组成:linux系统内核、系统级应用程序
Linux目录结构
- 根目录 (/):
- Linux系统的根目录是所有其他目录的起点,通常包含操作系统和系统配置文件。
 
- 常用目录层次结构:
- /boot:包含操作系统启动所需的文件和分区。
- /home:用户日志、配置文件等。
- /root:根用户的目录,通常是系统管理员的主目录。
- /etc:环境变量、系统配置文件。
- /user:用户目录,存储用户程序和数据。
- /mnt:挂载点,用于连接外置文件系统。
 
- 用户目录 (/user):
- 用户目录下通常包含用户的配置文件、应用程序的安装目录、以及用户生成的文件等。
 
- 本地目录 (/user/local):
- 用于存储用户的本地配置文件,如密码、登录信息等,通常隐藏在用户目录下。
 
- 设备驱动层:
- /dev:包含设备驱动和虚拟设备,如swap分区、设备映射等。
 
Shell编程
C++程序设计语言
基础知识
变量
命名规则:C++标识符由字母、数字和下划线组成,必须以字母或下划线开头,不能是关键字,并且区分大小写
数据的输入与输出
cout是标准输出流对象,通过<<运算符向控制台输出数据(如cout << "Hello" << endl;),endl换行;
cin是标准输入流对象,通过>>从控制台读取输入到变量(如cin >> name;)。
两者需包含头文件<iostream>,属std命名空间。
<<称插入运算符,>>为提取运算符,注意输入类型需匹配变量,字符串输入用getline()更安全。
数据类型
C++数据类型包括基本类型:整型( int、long long int)、浮点型(如 float、double)、布尔型(如 true、false)、字符型(char)和字符串型(string)、复合类型(数组array、结构体、类、联合体)、空类型(void)及引用类型
sizeof 是 C++ 中的一个一元运算符,用于计算数据类型或变量在内存中所占的字节数,返回值为 size_t 类型
size_t—无符号整数类型,专门用来表示 “对象大小” 或 “数组索引” 这类 非负整数值。
- sizeof(类型名)(如- sizeof(int))
- sizeof 变量/表达式(如- sizeof(a))
科学计数法:
科学计数法的幂次是 10 的幂,float 精度约 7 位十进制,double 精度约 15 位
未指定后缀的科学计数法默认是 double 类型。
例如:3e-2 是 double,若赋值给 float 变量,添加后缀 f 或 F:
flaot f3 = 3e-2f  =3*10^-2
double f3 = 3e+2     = 3*10^2
运算符
算术运算符
- /:除法(整数除法会截断小数部分)整数相除结果依然是整数
- %:取模(求余数,仅用于整数类型)
- ++:自增
- --:自减
前置运算符 — 变量先加减,再进行表达式运算;
后置运算符 — 先执行表达式运算,再进行变量加减
赋值运算符
=用于赋值,复合形式如+=、*=可简化操作
比较运算符
用于判断两值关系,返回布尔值:
==相等、!=不等、>大于、<小于、>=大于等于、<=小于等于
逻辑运算符
&&:全真为真;||:一真即真;!:非真即假
条件运算符
语法格式为:
condition ? expression1 : expression2
#include <iostream>
using namespace std;int main() {int score = 85;// 条件运算符:condition ? expr1 : expr2// 如果条件为真,返回expr1;否则返回expr2string result = (score >= 60) ? "及格" : "不及格";cout << "分数 " << score << " 的结果是:" << result << endl;// 输出:分数 85 的结果是:及格return 0;
}
三目运算符返回的是变量,可以继续赋值
#include <iostream>
using namespace std;int main() {int a = 10;int b = 20;// 三目运算符返回的是变量本身(左值),所以可以继续赋值// 因为 a < b,所以 (a > b ? a : b) 返回的是 b 这个变量// 相当于执行了 b = 100(a > b ? a : b) = 100;cout << "a = " << a << ", b = " << b << endl; // 输出: a = 10, b = 100return 0;
}
流程结构
顺序结构
依次执行
- 
程序从 main()函数开始
- 
逐行执行每条语句 
- 
每条语句执行完成后自动进入下一条 
- 
直到遇到 return 0;程序结束 
选择结构
if语句
简单if语句:if (条件) 语句;
- 如果条件为真,执行语句;否则跳过
if-else语句:if (条件) 语句1; else 语句2;
- 如果条件为真,执行语句1;否则执行语句2
if-else else-if语句:用于多条件判断
- 依次检查每个条件,执行第一个为真的条件对应的语句
重要规则:
- 条件表达式需要用圆括号 ()括起来
- 如果if或else后面有多条语句,必须用花括号 {}括起来形成代码块
- C++中,非零值被视为真,零值被视为假
Switch语句
重要规则:
- 类型限制:switch的判断表达式只能是整型(int, short, long等)或字符型(char),不能是浮点型、字符串或布尔型
- 值匹配:只能匹配具体的值,不能判断区间(如case 60-70: 是错误的)
- break的重要性:每个case后通常需要break语句,否则会"穿透"执行下一个case的代码
- default可选:可以包含default分支处理未匹配的情况
#include <iostream>
using namespace std;int main() {char grade = 'B';cout << "成绩等级对应评语:" << endl;switch (grade) {case 'A':cout << "优秀!继续保持!" << endl;break;  // 必须有break,否则会继续执行下一个casecase 'B':cout << "良好!很有潜力!" << endl;break;case 'C':cout << "及格!需要更加努力!" << endl;break;case 'D':cout << "不及格!要加油了!" << endl;break;case 'F':cout << "很差!需要重新学习!" << endl;break;default:  // 处理未匹配的情况cout << "无效的成绩等级!" << endl;break;}// 错误示例:尝试使用区间(这是不允许的)/*int score = 85;switch (score) {case 90-100:  // 错误!不能使用区间cout << "A" << endl;break;case 80-89:   // 错误!cout << "B" << endl;break;}*/// 正确处理数值范围的方式应该用if-elseint score = 85;cout << "\n用if-else处理分数区间:" << endl;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;}return 0;
}
循环结构
1. while循环
- 
语法: while (条件) { 循环体 }
- 
执行流程: - 判断条件表达式是否为真
- 如果为真,执行循环体,然后回到判断
- 如果为假,跳出循环,执行循环后的代码
 #include <iostream> using namespace std;int main() {int i = 1;// 当i <= 5时,重复执行循环体while (i <= 5) {cout << i << " ";i++; // 更新循环变量}// 输出:1 2 3 4 5return 0; } 
2. do while循环
- 语法
do {// 循环体
} while (条件);
- 重要规则:
- 至少执行一次:无论条件是否为真,循环体都会先执行一次
- 后判断:在每次循环体执行完毕后才检查条件
- 分号:while后的条件判断必须以分号结束
 
#include <iostream>
using namespace std;int main() {int i = 1;// 先执行循环体,再判断条件do {cout << i << " ";i++;} while (i <= 5);// 输出:1 2 3 4 5return 0;
}
3. for循环
- 语法:
for (初始化; 条件; 更新) {// 循环体
}
- 重要规则:
- 三要素集中:初始化、条件判断、更新操作都在括号内清晰定义
- 预测试:先判断条件,为真时才执行循环体
- 适用场景:适合循环次数已知的情况
 
数组是用于存储相同类型多个元素的连续内存空间
利用for循环遍历数组
#include <iostream>
using namespace std;int main() {int arr[5] = {10, 20, 30, 40, 50};// 使用for循环遍历数组for (int i = 0; i < 5; i++) {cout << "arr[" << i << "] = " << arr[i] << endl;}return 0;
}
猜数字案例
#include <iostream>      // 输入输出流
#include <ctime>         // time()函数获取时间
using namespace std;int main()
{cout << "猜数字游戏开始!" << endl;// 1. srand() + time(NULL):设置随机数种子// time(NULL)返回当前时间(秒数),确保每次运行程序产生不同的随机序列srand(time(NULL));// 2. rand() % 100 + 1:生成1-100的随机数// rand()产生0-RAND_MAX的随机数// % 100 得到0-99,+1 变成1-100int a = rand() % 100 + 1;int guess = 0;cout << "请输入你猜的数字(1-100):" << endl;// 3. while(true)无限循环 + break:实现持续猜测直到正确while (true) {cin >> guess;  // 输入// 4. if-else if-else:多分支判断if (guess > a) {cout << "猜大了" << endl;}else if (guess < a) {cout << "猜小了" << endl;}else {cout << "恭喜你猜对了" << endl;break;  // 5. break:跳出循环}}cout << "游戏结束" << endl;return 0;
}
4. 跳转语句
- 
break - 跳出循环**:在 for、while、do-while循环中,立即终止整个循环**
- 跳出switch:在 switch语句中,跳出当前switch结构,防止"穿透"到下一个case
 break只能跳出最内层的循环或switch语句
- 跳出循环**:在 
#include <iostream>
using namespace std;int main() {// break在循环中的使用for (int i = 1; i <= 10; i++) {if (i == 5) {break;  // 当i等于5时,立即跳出循环}cout << i << " ";  // 输出:1 2 3 4}return 0;
}
- 
continue - 跳过当前循环体中剩余的代码
- 直接进入下一次循环的迭代
- 对于 for循环,会先执行更新表达式,再判断条件
 continue只能在循环结构(for、while、do-while)中使用。
#include <iostream>
using namespace std;int main() {// continue跳过偶数,只输出奇数for (int i = 1; i <= 10; i++) {if (i % 2 == 0) {continue;  // 如果是偶数,跳过本次循环剩余代码}cout << i << " ";  // 只有奇数能执行到这里}// 输出:1 3 5 7 9return 0;
}
- **go to **
goto 标签名;
...
标签名: // 标签后跟冒号
 1. 无条件跳转:立即跳转到标签所在位置
 2. 标签命名:遵循变量命名规则,后跟冒号
 3. 作用范围:只能在同一函数内跳转
 4. 限制:不能跳过变量的初始化(如跳过带初始化的定义)
#include <iostream>
using namespace std;int main() {int i = 1;loop_start:  // 定义标签if (i > 5) {goto loop_end;  // 条件满足时跳转到loop_end}cout << i << " ";i++;goto loop_start;  // 跳转回loop_startloop_end:  // 标签位置cout << "\n循环结束" << endl;return 0;
}
// 输出:1 2 3 4 5
//       循环结束
数组
一维数组
- 声明语法:类型 数组名[大小];- 类型:数组中所有元素的数据类型(如int、double、char等)
- 大小:数组元素的个数,必须是编译时常量(正整数)
 
- 内存布局:
- 数组元素在内存中连续存储
- 第一个元素的索引是0,最后一个元素的索引是大小-1
- 可以通过&数组名[索引]获取元素的内存地址
 
- 初始化方式:
- 完全初始化:int arr[3] = {1, 2, 3};
- 部分初始化:int arr[5] = {1, 2};(剩余元素自动初始化为0)
- 自动大小:int arr[] = {1, 2, 3};(编译器根据初始化值确定大小)
 
- 完全初始化:
- 访问元素:
- 使用下标运算符 [],如arr[0]
- 不检查边界:访问超出范围的索引会导致未定义行为(如内存越界)
 
- 使用下标运算符 
- 数组名的含义:
- 数组名代表数组首元素的地址
- sizeof(数组名)返回整个数组的字节数
- 作为函数参数传递时,会退化为指针
 
#include <iostream>
using namespace std;int main() {// 1. 声明并初始化一维数组int scores[5] = {85, 92, 78, 96, 88};  // 完全初始化// 2. 访问数组元素(使用for循环)cout << "=== 数组元素遍历 ===" << endl;for (int i = 0; i < 5; i++) {cout << "第" << (i+1) << "个成绩: " << scores[i] << endl;}// 3. 修改数组元素scores[2] = 85;  // 将第三个元素修改为85cout << "\n修改后第三位成绩: " << scores[2] << endl;// 4. 数组大小计算cout << "数组总大小: " << sizeof(scores) << " 字节" << endl;cout << "单个元素大小: " << sizeof(scores[0]) << " 字节" << endl;cout << "元素个数: " << sizeof(scores) / sizeof(scores[0]) << endl;// 5. 内存地址演示cout << "\n=== 内存地址 ===" << endl;for (int i = 0; i < 5; i++) {cout << "scores[" << i << "] 地址: " << &scores[i] << endl;}cout << "数组名地址: " << scores << endl;  // 数组名即首元素地址return 0;
}
二维数组
- 
声明语法: 类型 数组名[行数][列数];- 例如:int matrix[3][4];声明一个3行4列的整型数组
 
- 例如:
- 
内存布局: - 元素在内存中连续存储
- 按行优先顺序:第一行所有元素 → 第二行所有元素 → …
- 总元素个数 = 行数 × 列数
- 总字节数 = 行数 × 列数 × sizeof(元素类型)
 
- 
初始化方式: - 按行初始化:int arr[2][3] = {{1,2,3}, {4,5,6}};
- 连续初始化:int arr[2][3] = {1,2,3,4,5,6};
- 部分初始化:未指定的元素自动初始化为0
 #include <iostream> using namespace std;int main() {// 1. 完整按行初始化(推荐,清晰易读)int arr1[2][3] = {{1, 2, 3},{4, 5, 6}};// 2. 连续初始化(按内存顺序)int arr2[2][3] = {1, 2, 3, 4, 5, 6};// 等价于上面的arr1// 3. 部分初始化 - 只初始化前几行int arr3[3][4] = {{1, 2}, // 第0行:1,2,0,0{3, 4, 5} // 第1行:3,4,5,0 // 第2行全部为0};// 4. 部分初始化 - 只初始化前几个元素int arr4[2][3] = {1, 2, 3, 4};// 等价于 {{1,2,3},{4,0,0}}// 5. 全部初始化为0int arr5[2][3] = {0}; // 所有元素都为0// 6. 省略行数,自动推断(列数必须指定)int arr6[][3] = {{1, 2, 3},{4, 5, 6},{7, 8, 9}}; // 编译器自动推断行数为3// 验证初始化结果cout << "=== 部分初始化示例(arr3) ===" << endl;for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {cout << arr3[i][j] << "\t";}cout << endl;}// 输出:// 1 2 0 0// 3 4 5 0 // 0 0 0 0return 0; } 
- 按行初始化:
- 
访问元素: - 使用双下标:数组名[行索引][列索引]
- 行索引范围:0 到 (行数-1)
- 列索引范围:0 到 (列数-1)
- 不进行边界检查,越界访问会导致未定义行为
 
- 使用双下标:
- 
数组名的含义: - 数组名代表第一行的地址(即&数组名[0])
- sizeof(数组名)返回整个二维数组的总字节数
 
- 数组名代表第一行的地址(即
#include <iostream>
using namespace std;int main() {// 1. 声明并初始化二维数组int matrix[3][4] = {{1, 2, 3, 4},    // 第0行{5, 6, 7, 8},    // 第1行  {9, 10, 11, 12}  // 第2行};// 2. 遍历并输出二维数组cout << "=== 二维数组遍历 ===" << endl;for (int i = 0; i < 3; i++) {      // 行循环for (int j = 0; j < 4; j++) {  // 列循环cout << matrix[i][j] << "\t";}cout << endl;  // 每行结束后换行}// 3. 访问特定元素cout << "\nmatrix[1][2] = " << matrix[1][2] << endl;  // 输出7// 4. 数组大小信息cout << "总大小: " << sizeof(matrix) << " 字节" << endl;cout << "每行大小: " << sizeof(matrix[0]) << " 字节" << endl;cout << "元素类型大小: " << sizeof(matrix[0][0]) << " 字节" << endl;cout << "总元素个数: " << (sizeof(matrix) / sizeof(matrix[0][0])) << endl;return 0;
}
函数
- 函数的定义
返回类型 函数名(参数列表) {// 函数体(具体实现代码)[return 表达式;]  // 如果返回类型不是void,则需要return语句
}
- 函数的调用
- 语法:函数名(实际参数列表);
#include <iostream>
using namespace std;// 函数定义
int add(int a, int b) {return a + b;
}void printResult(int result) {cout << "计算结果: " << result << endl;
}int main() {int x = 5, y = 3;// 函数调用示例int sum = add(x, y);           // 调用add函数,实参是变量x和yprintResult(sum);              // 调用printResult函数,实参是变量sumprintResult(add(10, 20));      // 嵌套调用:add的返回值作为printResult的参数printResult(add(x, 7));        // 实参可以是变量和常量的组合return 0;
}
- 函数的类别
- 无参无返回值 (void function())
- 特点:不接收任何输入,也不返回结果
- 用途:执行固定操作,如显示菜单、打印信息
 
void showMenu() {cout << "=== 主菜单 ===" << endl;cout << "1. 开始游戏" << endl;cout << "2. 退出游戏" << endl;
}
- 有参无返回值 (void function(parameters))
- 特点:接收输入参数,但不返回结果
- 用途:根据输入执行操作,如打印格式化信息
 
void printSum(int a, int b) {cout << a << " + " << b << " = " << (a + b) << endl;
}
- 无参有返回值 (return_type function())
- 特点:不接收输入,但返回一个计算结果
- 用途:获取系统状态、生成随机数等
 
int getRandomNumber() {return rand() % 100 + 1;  // 返回1-100的随机数
}
- 
有参有返回值 (return_type function(parameters)) 特点:接收输入参数,并返回计算结果 用途:最常用的函数类型,进行数据处理和计算 
int add(int a, int b) {return a + b;  // 根据输入参数计算并返回结果
}
案例
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;// 1. 无参无返回值
void showMenu() {cout << "=== 计算器 ===" << endl;cout << "1. 加法" << endl;cout << "2. 退出" << endl;
}// 2. 有参无返回值
void printResult(int a, int b, int result) {cout << a << " + " << b << " = " << result << endl;
}// 3. 无参有返回值  
int getRandomNumber() {return rand() % 10 + 1;  // 返回1-10的随机数
}// 4. 有参有返回值
int add(int a, int b) {return a + b;
}int main() {srand(time(0));// 测试四种函数类型showMenu();                    // 无参无返int num1 = getRandomNumber();  // 无参有返int num2 = getRandomNumber();int sum = add(num1, num2);     // 有参有返printResult(num1, num2, sum);  // 有参无返return 0;
}
- 函数的分文件编写
创建.h后缀名的头文件,创建.cpp后缀名的源文件,头文件中写函数声明,源文件中写函数定义
头文件(.h 或 .hpp):
1. 包含函数声明(函数原型)2. 使用    `#ifndef`/`#define`/`#endif` 防止重复包含(头文件保护)3. 通过    `#include` 在其他文件中引用
源文件(.cpp):
 1. 包含函数的具体实现(定义)
 2. 实现头文件中声明的函数
主文件(main.cpp):
	1. 包含      main() 函数
 2. 引用头文件来使用其他文件中的函数
指针
- 
指针的作用:指针间接访问内存 **指针是C++中一种特殊的变量,用于存储另一个变量的内存地址**
- 
语法: 数据类型* 指针变量名; 
- 
指针初始化 数据类型* 指针名 = &变量名;-------将变量的地址赋值给指针 
- 
&取地址 取地址运算符(&) &变量名;------获取变量的内存地址 
- 
解引用运算符(*) *指针名-------访问指针所指向地址中的值
 
- 
指针所占内存空间 - 大小固定:
- 在同一系统上,所有类型指针的大小都相同
- 与指向 int、double、char等无关
 
- 系统依赖:
- 32位系统:指针占 4字节(32位 = 4字节)
- 64位系统:指针占 8字节(64位 = 8字节)
 
- 使用 sizeof:
- sizeof(指针变量)或- sizeof(数据类型*)可获取指针大小
 
 
- 大小固定:
#include <iostream>
using namespace std;int main() {int value = 42;// 1. 指针声明int* ptr;// 2. 指针初始化(使用取地址符&)ptr = &value;// 3. 解引用(使用*获取指向的值)cout << "value的值: " << value << endl;cout << "ptr指向的值: " << *ptr << endl;cout << "value的地址: " << &value << endl;cout << "ptr存储的地址: " << ptr << endl;// 4. 通过指针修改值*ptr = 100;cout << "修改后value: " << value << endl;// 5. 空指针ptr = nullptr;  // 安全的空指针return 0;
}
空指针指向的内存,不允许访问,访问空指针所指向的内存是非法的
- 空指针的本质:
- 值为 nullptr(或NULL、0)
- 不指向任何有效的内存位置
- 是一种安全的"无指向"状态
 
- 值为 
常量指针(Pointer to const)
- 语法:const 数据类型* 指针名或数据类型 const* 指针名
- 含义:指针指向的数据不能修改,但指针本身可以指向其他地址
- 记忆法:“指向常量的指针”
int a = 10, b = 20;
const int* ptr = &a;  // ptr指向常量整数// ✅ 允许:改变指针指向
ptr = &b;  // ptr现在指向b// ❌ 禁止:修改指针指向的数据
// *ptr = 30;  // 错误!不能通过ptr修改数据
指针常量(Const pointer)
- 语法:数据类型* const 指针名
- 含义:指针本身是常量,指向的地址不能改变,但可以修改指向的数据
- 记忆法:“常量的指针”
int a = 10, b = 20;
int* const ptr = &a;  // ptr是一个常量指针,初始化指向a// ✅ 允许:修改指针指向的数据
*ptr = 15;  // a的值变为15// ❌ 禁止:改变指针指向
// ptr = &b;  // 错误!ptr是常量,不能重新赋值
常量指针常量(完全常量)
- 语法:const 数据类型* const 指针名
- 含义:既不能改变指向的地址,也不能修改指向的数据
int a = 10, b = 20;
const int* const ptr = &a;// ❌ 都不允许
// *ptr = 20;   // 错误!不能修改数据
// ptr = &b;    // 错误!不能改变指向
口诀:
- 
const在*左边:数据常量(指针可变)
- 
const在*右边:指针常量(数据可变)
- 
const在 两边:都是常量
- 
**指针和数组 ** - 数组名的本质:
- 数组名是一个指向首元素的指针常量
- arr等价于- &arr[0]
- 不能修改数组名的指向(因为是常量)
 
- 指针算术:
- 指针加减整数会按指向类型的大小移动
- ptr + 1移动- sizeof(类型)个字节
 
 - sizeof(arr)返回整个数组的字节数
- sizeof(ptr)返回指针变量的大小
 
- 数组名的本质:
#include <iostream>
using namespace std;int main() {int arr[5] = {10, 20, 30, 40, 50};// 1. 数组名作为指针cout << "arr = " << arr << endl;           // 数组首地址cout << "&arr[0] = " << &arr[0] << endl;   // 首元素地址cout << "*arr = " << *arr << endl;         // 10(首元素值)// 2. 指针指向数组int* ptr = arr;  // 等价于 int* ptr = &arr[0];// 3. 两种访问方式等价性cout << "\n=== 访问方式对比 ===" << endl;for (int i = 0; i < 5; i++) {cout << "arr[" << i << "] = " << arr[i] << ", *(arr+" << i << ") = " << *(arr + i)<< ", *(ptr+" << i << ") = " << *(ptr + i) << endl;}// 4. 指针遍历cout << "\n=== 指针遍历 ===" << endl;for (int* p = arr; p < arr + 5; p++) {cout << *p << " ";}cout << endl;// 5. 重要区别int* dynamicArr = new int[3]{1, 2, 3};cout << "sizeof(arr) = " << sizeof(arr) << endl;      // 整个数组大小cout << "sizeof(ptr) = " << sizeof(ptr) << endl;      // 指针大小cout << "sizeof(dynamicArr) = " << sizeof(dynamicArr) << endl; // 指针大小delete[] dynamicArr;return 0;
}
- 
指针和函数 - 指针作为函数参数
 - 概念:将指针作为参数传递给函数
- 优点 :
- 
避免大数据的复制开销 
- 
实现函数间的双向通信(修改原数据) 
- 
处理动态分配的内存  
 
- 
 - 
 
结构体
- 结构体的定义
struct 结构体名 {数据类型 成员1;数据类型 成员2;// ...
};
- 
结构体数组 
- 
结构体指针 
- 
结构体嵌套结构体 
- 
结构体做函数参数 
- 
const使用场景 
- 
结构体案例 
通讯管理系统案例
内存四区
内存分区模型:代码区、全局区、栈区、堆区
代码区;只读、共享
全局区:全局变量和静态变量(static)/常量(字符串常量,const修饰的全局变量)
栈区的注意事项:不要返回局部变量的地址、栈区的数据在函数执行完成后自动释放
堆区:
new 数据类型 new返回的是该数据类型的指针;
释放数据delete   释放数组 delete [ ]
#include <iostream>
using namespace std;int main() {// --- 栈区示例 ---int stackVar = 50;  // 栈区,函数结束自动释放// --- 堆区示例 ---int* heapPtr = new int(100);      // 堆区分配int* heapArray = new int[5]{1,2,3,4,5};  // 堆区分配数组cout << "*heapPtr = " << *heapPtr << endl;// 使用完必须释放delete heapPtr;        // 释放单个intdelete[] heapArray;    // 释放数组// 避免悬空指针heapPtr = nullptr;heapArray = nullptr;return 0;
}
引用
- 
引用的作用 替代指针实现引用传递 语法: 数据类型 &别名 = 原名;
- 
引用的注意事项 必须初始化:引用在声明时就必须绑定到一个对象 绑定后不可更改:引用一旦初始化,就不能再指向其他对象 绑定对象必须存在:不能引用不存在的变量(如已销毁的局部变量) 
- 
引用做函数参数 返回类型 函数名(类型& 参数名) {// 函数体 }
- 
引用做函数返回值(函数调用做左值) 
- 
引用的本质是指针常量 
- 
常量引用主要用来修饰形参 
进阶知识
函数高级
函数的默认参数(函数声明有默认参数,函数实现就不能有默认参数)
 从右向左原则:默认参数必须从右向左依次定义
 只能在声明中指定:通常在头文件中声明时设置默认值
 不能重复指定:定义时不能再写默认值
函数重载(函数的返回值不可以作为函数重载的条件)
 允许在同一作用域内定义多个同名函数,只要它们的参数列表不同
满足:同一个作用域、函数名称相同、函数参数类型不同或顺序不同或个数不同
重载的条件
函数重载必须满足以下至少一个条件:
| 条件 | 示例 | 
|---|---|
| 参数个数不同 | func()vsfunc(int a) | 
| 参数类型不同 | func(int a)vsfunc(double a) | 
| 参数顺序不同 | func(int, double)vsfunc(double, int) | 
类和对象
C++面向对象的三大特性:封装、继承、多态
封装
- 什么是封装:
- 将相关的数据(属性)和函数(方法)组织在一个类中
- 隐藏对象的内部实现细节
- 通过公共接口与外界交互
- 封装的好处:
- 安全性:防止外部直接修改内部数据
- 易维护性:内部实现可以改变而不影响外部代码
- 复用性:封装好的类可以被多次使用
- 简化使用:用户只需了解公共接口
类(class)
class 类名 {
private:    // 私有成员(默认)// 数据成员(属性)// 成员函数
protected:  // 保护成员// ...
public:     // 公有成员// 成员函数(接口)
};
- 访问控制:
- private:只能在类内部访问(默认)
- public:可以在任何地方访问
- protected:在类内部和派生类中访问
 
- 成员组成:
- 数据成员:描述对象的属性
- 成员函数:描述对象的行为
 
- 对象创建:
- 类名 对象名;
- 对象通过.操作符访问公有成员
 
实例化
类中的属性和行为统一称为成员
struct和class的区别
默认的访问权限不同struct(public)/class(prviate)
| 特性 | struct | class | 
|---|---|---|
| 默认访问权限 | public | private | 
| 默认继承方式 | public | private | 
| 使用习惯 | 侧重数据组织 | 侧重面向对象设计 | 
成员属性设置私有
对象的初始化和清理
1.构造函数和析构函数
	构造函数语法:类名(){ }
 关键特征:
- 
没有返回类型(连 void都不能写)
- 
函数名必须与类名完全相同 
- 
在创建对象时自动调用 构造函数的特点 
| 特性 | 说明 | 
|---|---|
| 无返回值 | 不能写任何返回类型 | 
| 自动调用 | 对象创建时自动执行,无需手动调用 | 
| 只调用一次 | 每个对象在其生命周期内仅调用一次 | 
| 可重载 | 可以有多个构造函数(参数不同) | 
| 可带参数 | 支持参数初始化成员变量 | 
#include <iostream>
using namespace std;class Timer {
public:// 构造函数:开始计时Timer() {cout << "计时开始..." << endl;}// 析构函数:结束计时~Timer() {cout << "计时结束!" << endl;cout << "任务完成!" << endl;}
};void doWork() {Timer t;  // 创建对象,自动开始计时// 模拟做一些工作cout << "正在处理数据..." << endl;cout << "正在保存文件..." << endl;cout << "正在清理缓存..." << endl;// 函数结束时,t的析构函数自动被调用
}int main() {cout << "程序开始" << endl;doWork();  // 调用函数cout << "程序结束" << endl;return 0;
}
	析构函数:~类名(){ }
 析构函数的核心特点
| 特性 | 说明 | 
|---|---|
| 没有返回值 | 不能写任何返回类型(包括void) | 
| 无参数 | 不能有任何参数(包括void) | 
| 自动调用 | 对象销毁时自动执行 | 
| 只调用一次 | 每个对象在其生命周期内仅调用一次 | 
| 不能重载 | 一个类只能有一个析构函数 | 
class 类名 {
public:// 构造函数 - 没有返回值,名字和类一样类名() {// 对象创建时自动执行}// 析构函数 - 名字前面加~~类名() {// 对象销毁时自动执行}
};
2.构造函数的分类及调用
构造函数的分类:
- 按参数分类
| 类型 | 示例 | 
|---|---|
| 无参构造 | Person() { } | 
| 有参构造 | Person(string name, int age) { } | 
- 按功能分类
| 类型 | 说明 | 
|---|---|
| 普通构造 | 包括无参和有参构造 | 
| 拷贝构造 | Person(const Person& p) { } | 
拷贝构造函数:
#include <iostream>
#include <string>
using namespace std;class Dog {
public:string name;Dog(string n) : name(n) {cout << "创建: " << name << endl;}// 拷贝构造函数Dog(const Dog& other) {name = "copy_of_" + other.name;cout << "复制: " << other.name << " → " << name << endl;}
};int main() {Dog dog1("旺财");           // 普通构造Dog dog2(dog1);             // 调用拷贝构造// 输出: 复制: 旺财 → copy_of_旺财Dog dog3 = dog1;            // 也调用拷贝构造// 输出: 复制: 旺财 → copy_of_旺财return 0;
}
注意事项:调用默认构造函数,不要加(),会被认为是一个函数的声明
Person p;     // ✅ 调用无参构造,创建对象
Person p( );   // ❌ 这是一个函数声明!不是创建对象
拷贝构造函数调用时机:
1.使用一个已经创建完毕的对象来初始化一个新对象
2.值传递的方式给函数参数传值
3.值方式返回局部对象
class Person {
public:// 拷贝构造函数Person(const Person& p) {cout << "拷贝构造函数被调用" << endl;}
};int main() {Person p1;// 1. 用已创建的对象初始化新对象Person p2(p1);        // ✅Person p3 = p1;       // ✅// 2. 值传递给函数参数void func(Person p);  // 传参时调用拷贝构造func(p1);// 3. 值方式返回局部对象Person create() {Person temp;return temp;  // 返回时可能调用拷贝构造}return 0;
}
构造函数调用规则:创建一个类,编译器会给每个类都添加至少3个函数
分别是默认构造函数、默认析构函数、拷贝构造(值拷贝)
如果用户定义有参构造函数,c++不提供默认无参构造,会提供默认拷贝构造
如果用户定义拷贝构造函数,c++不会在提供其他构造函数
3. 深拷贝与浅拷贝
4.初始化列表
5.类对象作为成员
6.静态成员
7.对象模型和this指针
8.友元
9.运算符重载
继承
多态
提高知识
模版
C++的另一种编程思想称为泛型编程,主要利用的技术就是模版;
C++提供两种模版机制:函数模版和类模版
模版的语法:
template<typename T>
函数声明或定义解释:
template ---声明创建模版
typename ---表明其后面的符号是一种数据类型,可以用class代替
T ---通用的数据类型,通常为大写字母
注意事项:
自动类型推导,必须推导出一致的数据类型T,才可以使用
模版必须要确定出T的数据类型,才可以使用
普通函数与函数模版区别:
普通函数调用可以发生隐式类型转换,函数模板调用不会发生隐式类型转换
如果利用显示指定类型的方式,可以发生隐式类型转换
普通函数与函数模版的调用规则:
如果函数模版和普通函数都可以实现,优先调用普通函数
可以通过空模版参数列表来强制调用函数模版
函数模版也可以发生重载
如果函数模版可以产生更好的匹配,优先调用函数模版
类模版
语法:
template <typename T>
类解释:
template  ---声明创建末模板
typename ---表明其后面的符号是一种数据类型,可以用class代替
T   ---通用的数据类型STL(Standard Template Library)
STL基本概念
STL从广义上分为容器(container)算法(algorithm)迭代器(iterator)
算法和容器之间通过迭代器进行无缝连接
STL六大组件
容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
1.容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据
2.算法:各种常用的算法
3.迭代器:扮演了容器与算法之间的胶合剂
4.仿函数:行为类似函数
5.适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
6.空间配置器:负责空间的配置与管理
容器:
STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组、链表、树、队列、集合、映射表等
这些容器分为序列式容器和关联式容器:
 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的关系
 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法(ALgorithms)
算法分为:质变算法和非质变算法
 质变算法:是指运算过程中会更改区间内元素的内容,例如拷贝、替换、删除等等
 非质变算法:是指运算过程中不会更改区间内元素内容,例如查找、计数、遍历、寻找极值等
迭代器:
提供一种方法,使之能够依寻访问某个日期所含的各个元素,而有又无需暴露该容器的内部表示方式
种类:
| 种类 | 功能 | 支持运算 | 
|---|---|---|
| 输入迭代器 | 对数据的只读访问 | 只读,,++、==、!= | 
| 输出迭代器 | 对数据的只写访问 | 只写,++ | 
| 前向迭代器 | 读写操作,并向前推进迭代器 | 读写,++、==、!= | 
| 双向迭代器 | 读写操作,并能向前和向后操作 | 读写,++,– | 
| 随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据 | 读写,++,–,[n],-n、<、<=、>、>= | 
容器算法迭代器初识
vector存放内置数据类型
容器:    vector
算法:          for_each
迭代器:      vector<int>::iterator
