48.C++基础语法知识总结

48.总结


48.1 知识点

学习的主要内容

强调


48.2 核心要点速览

函数

函数基础

  • 作用:封装代码、提升复用率、抽象行为。
  • 声明与定义:标准在头文件(.h)声明、源文件(.cpp)定义;临时可在.cpp中处理,需提前声明。
  • 语法返回类型 函数名(参数列表) { 逻辑; return 值; }void无返回值,return可提前结束函数。

形参与实参

  • 形参:函数内声明的参数(如int a)。
  • 实参:调用时传入的具体值(如add(5, 10))。
  • 值传递:形参是实参拷贝,修改不影响实参。

参数默认值

  • 作用:调用时可省略参数,使用默认值。
  • 注意:声明可带默认值,定义不可;可选参数需放在普通参数后。

变量作用域

  • 局部变量:语句块内声明,块结束后销毁。
  • 全局变量:函数外声明,程序结束后销毁,可被全局访问。
  • 同名变量:内部作用域屏蔽外部。

函数重载

  • 条件:同作用域、同名函数,参数数量/类型/顺序不同(与返回值无关)。
  • 注意:可选参数可能导致编译器歧义。

递归函数

  • 关键:必须有结束条件(如if (num>10) return;),函数自调用。

内联函数

  • 作用:用inline声明,编译时将代码插入调用处,减少函数调用开销。
  • 限制:递归/大型函数不适用,可能导致代码膨胀。

变量的存储类型

auto变量

  • 作用:让编译器自动推断变量类型,减少手动定义。
  • 特点
    • 需声明时初始化,否则无法推断类型。
    • 优点:代码简洁;
    • 缺点:影响可读性,初学阶段不建议频繁使用。
  • 示例
    auto i = 10;(编译器推定为int

static变量

  • 作用:声明周期贯穿程序运行,存储全局或局部静态变量。
  • 分类
    • 静态局部变量:函数内声明,仅初始化一次,函数返回后不销毁。
    • 静态全局变量:文件内作用域,不可跨文件访问(普通全局变量可跨文件)。
  • 特点
    • 优点:适合缓存或全局共享数据,仅初始化一次。
    • 缺点:持续占用内存,可能增加内存消耗。

register变量

  • 作用:建议存储在CPU寄存器中,提高访问速度(现代编译器已自动优化,较新版本C++已废弃)。
  • 限制
    • 无法获取地址(无寄存器地址)。
    • 现代开发中极少使用,编译器优化更高效。
  • 对比
    类型 存储位置 速度 容量限制
    寄存器 CPU内部 极快 有限
    内存 内存条 较慢 较大

extern变量

  • 作用:跨文件共享全局变量或函数,声明时不定义,需在另一文件中定义。
  • 注意
    • 不允许跨文件定义同名全局变量,会编译报错。
    • 仅声明外部已定义的内容,不能重复定义。
  • 示例
    // 文件1.cpp中定义  
    int globalVar = 10;  
    // 文件2.cpp中声明  
    extern int globalVar;  
    

数组

一维数组

核心要点 说明
基本概念 相同类型数据的线性集合,内存连续存储。
声明方式 int arr[5];(指定容量)、int arr[] = {1,2,3};(自动推导容量)。
长度计算 sizeof(arr) / sizeof(int),获取数组元素个数。
元素访问 索引从0开始,arr[0]为首个元素,越界访问可能返回不确定值。
初始化规则 未指定元素初始化为0,如int arr[3] = {1};,其余元素为0。
操作限制 静态数组容量固定,增删元素需重新分配数组(如复制到新数组)。

二维数组

核心要点 说明
基本概念 行列结构的数据集合,用arr[row][col]访问元素。
声明方式 int arr[3][4];(3行4列)、int arr[][4] = {{1,2},{3,4}};(自动推导行数)。
行列计算 行数:sizeof(arr)/sizeof(arr[0]),列数:sizeof(arr[0])/sizeof(int)
元素访问 arr[i][j],i为行索引,j为列索引。
函数传参 需指定列数,如void func(int arr[][4], int rows)

字符数组

核心要点 说明
字符串初始化 char str[] = "hello";时,末尾自动添加\0作为结束符。
乱码原因 未初始化或无\0时,打印会读取到随机内存,导致乱码(如“烫烫烫”)。
手动添加结束符 char arr[] = {'A','B','\0'};,确保字符串正确结束。
与字符串区别 字符数组是数组,字符串是string类型,后者更灵活(如自动管理长度)。

指针基础

内存地址与指针概念

核心要点 说明
内存地址 内存单元的唯一编号(字节为单位),如int i=2占4字节,地址为连续4个字节的首地址。
指针定义 存储变量地址的变量,通过&获取地址,*解引用获取值。例:int* p=&ipi的地址,*pi的值。

指针基础操作

操作 语法 示例
声明 类型* 指针名 int* ptr;
初始化 指针=&变量 int a=10; int* p=&a;
解引用 *指针 cout << *p;(输出10)
空指针 void* p=nullptr; 不指向任何有效地址,避免野指针。
野指针 未初始化或指向已释放内存的指针,可能导致程序崩溃。

指针进阶操作

要点 细节 示例
内存占用 64位系统下占8字节(32位占4字节),与类型无关。 sizeof(int*)=8
&与*混合使用 &*p:先解引用再取地址(等价于p);*&a:先取地址再解引用(等价于a)。 &*ptr == ptr
指针自增减 按类型大小跳转:int* ptr自增跳4字节,char*跳1字节。 int a=10; int* p=&a; p++后地址+4。
空类型指针 void*可指向任意类型,使用时需强转。 void* p=&s; short s2=*(short*)p;

指针与常量

类型 定义 特点
指向常量的指针 const int* p; 可改指向,不可改值。p=&j; *p=10报错,p=&i允许。
指针常量 int* const p; 不可改指向,可改值。p=&j报错,*p=20允许。
指向常量的指针常量 const int* const p; 不可改指向和值。p=&j*p=10均报错。

指针和数组

指针与一维数组

核心要点 说明
内存关系 数组连续存储,指针指向首地址,通过指针增减访问元素。
建立联系 - 数组名即首地址:int* p = arr;
- 首元素地址:p = &arr[0];
元素访问 - 解引用:*p(首元素),*(p+1)(次元素)
- 下标语法:p[0]等价于*(p+0)
指针运算 自增/减按元素大小偏移(如int*自增跳4字节)。
数组名限制 数组名是固定地址,不能重定向;指针可指向任意合法内存。

指针与二维数组

核心要点 说明
内存结构 二维数组按行连续存储,可视为一维数组的一维数组。
数组指针 - 定义:int (*p)[4](指向含4个int的一维数组)
- 偏移:p+1跳一行(4×4=16字节)
元素访问 - 按元素指针
int* p = &arr[0][0]; 指向首个元素,*p访问元素,p+1跳1个int(4字节)。

- 按行指针
int (*p)[4] = arr; 指向整行,*(p+i)取第i行首地址,*(*(p+i)+j)取i行j列元素。

示例:*(*(p+1)+2)等价于arr[1][2],步骤为:
1. p+1:指向第2行(偏移16字节)。
2. *(p+1):转换为行内首元素地址(类型int*)。
3. *(p+1)+2:地址加2(偏移8字节),指向第2行第3列。
4. *(*(p+1)+2):解引用得到元素值。
二维数组名 - arr是行指针,*arr是列指针(首元素地址)
- sizeof(arr)为整体大小,sizeof(p)为指针大小(8字节)

指针与字符数组

核心要点 说明
字符串初始化 - char arr[] = "hello"; 自动加\0
- 纯字符数组需手动加\0,否则打印乱码
字符指针 - 指向常量字符串:const char* p = "test";
- 可直接打印,遇\0结束
遍历方式 - while (*p != '\0') { cout << *p++; }
- 偏移量控制:while (*(p+i) != '\0')
注意事项 - 常量字符串不可修改(如"test"[0] = 'a'报错)
- 指针未初始化或越界访问导致崩溃

指针数组

操作 语法示例 说明
定义与初始化 int* p[3] = {&a, &b, &c}; 每个元素存储变量地址,需初始化或后续赋值
访问值 cout << *p[0]; 解引用指针数组元素,获取指向的值
修改指向 p[0] = &d; 改变指针数组元素存储的地址
修改值 *p[0] = 99; 通过指针修改指向变量的值
遍历 for (int i=0; i<3; i++) cout << *p[i]; 遍历每个指针,解引用获取值

数组指针 vs 指针数组

对比项 数组指针 指针数组
定义 指向一个数组的指针 由多个指针组成的数组
本质 指针变量,存储数组的首地址 数组变量,元素为指针
语法 类型 (*指针名)[元素个数] 类型* 数组名[数组长度]
示例 int (*p)[4];(指向含4个int的数组) int* p[4];(含4个int*指针的数组)
存储内容 数组的首地址 多个变量的地址
访问元素 *(*(p+i)+j)(二维数组第i行j列) *(p[i])(解引用第i个指针指向的值)
应用场景 操作二维数组、矩阵 存储多个指针(如函数指针、动态内存)

多级指针

各级指针对比

级别 定义 语法声明 示例 访问值 应用场景
一级指针 指向普通变量的指针 int* p; int a=10; int* p=&a; *p 普通变量地址存储、函数参数传递
二级指针 指向一级指针的指针 int** pp; int* p=&a; int** pp=&p; **pp 指针数组、函数中修改指针指向
三级指针 指向二级指针的指针 int*** ppp; int** pp=&p; int*** ppp=&pp; ***ppp 复杂数据结构(如指针的指针数组)

内存分配

内存存储区域对比

区域 存储内容 生命周期 读写属性 管理方式
代码段 函数机器码、执行指令 程序运行期 只读 系统自动加载
数据段 全局变量、静态变量 程序运行期 可读写 系统自动管理
常量段 字符串字面量、只读数据 程序运行期 只读 系统自动管理
局部变量、函数参数、返回值 函数调用周期 可读写 编译器自动分配/释放
动态分配的内存(new申请) 程序员手动控制 可读写 手动用new分配/delete释放

堆内存分配与释放

操作 语法 示例 注意事项
单个对象分配 类型* 指针 = new 类型(初始值); int* p = new int(10); - 指针变量在栈,指向堆内存
- 必须初始化或赋值
数组分配 类型* 指针 = new 类型[容量]; int* arr = new int[5]; - 需用delete[]释放
- 可聚合初始化:new int[3]{1,2,3}
释放单个对象 delete 指针; delete p; p = nullptr; - 释放后指针置为nullptr,避免野指针
- 重复释放会崩溃
释放数组 delete[] 指针; delete[] arr; arr = nullptr; - 必须与new[]配对使用
- 释放后指针置空

内存安全核心要点

问题类型 原因 解决方案
内存泄漏 堆内存未用delete释放 - 及时调用delete/delete[]
- 指针释放后置nullptr
越界访问 数组索引超出范围、野指针操作 - 用sizeof计算数组长度
- 避免访问未分配的内存
空指针错误 访问nullptr或未初始化指针 - 声明时置nullptr
- 使用前检查if (p != nullptr)
野指针 指向已释放的内存或未分配区域 - 释放后立即置nullptr
- 不

引用

引用的基础使用

核心要点 说明
定义 变量的别名,与原变量共享内存地址,声明时用&,如int& ref = a;
初始化 必须初始化,如int& ref = a;(不能int& ref;)。
类型一致性 引用类型必须与原变量一致,否则编译报错(如short& ref = intVar会报错)。
绑定限制 绑定后不能更改指向,如ref = b;是修改a的值而非重新绑定。
内存占用 不占用新内存,与原变量共用同一内存地址。

左值引用 vs 右值引用

类别 左值引用(& 右值引用(&&
语法 int& ref = a;(绑定左值变量) int&& ref = 10;(绑定右值临时对象)
绑定对象 持久化对象(如变量、数组、指针) 临时对象(如字面量10、函数返回值)
生命周期 与原变量一致,随作用域结束销毁 延长右值生命周期至引用作用域结束
可修改性 可修改原变量的值(如ref = 20修改a 可修改绑定的临时对象(如ref = 20修改临时值)
应用场景 函数参数传递(避免拷贝)、变量别名 移动语义(避免临时对象拷贝)、右值优化

引用与函数

场景 说明
左值引用参数 - 函数参数为int& value,可直接修改实参,避免值拷贝开销。
- 例:void swap(int& a, int& b)交换两个变量的值。
右值引用参数 - 函数参数为int&& value,绑定右值临时对象,优化临时值操作。
- 例:void process(int&& tmp)处理临时计算结果。
常量引用参数 - 函数参数为const int& value,防止修改实参,常用于只读场景。
- 例:void print(const string& str)打印字符串,不修改原数据。
函数返回引用 - 不能返回局部变量的引用(局部变量销毁后引用无效)。
- 例:int& getRef(int& d) { return d; }返回传入变量的引用,修改返回值会影响原变量。

枚举

对比项 普通枚举 强类型枚举(enum class)
声明语法 enum E_Name { A, B, C }; enum class E_Name { A, B, C };
命名空间 枚举项直接暴露在全局作用域 枚举项属于枚举类作用域(如E_Name::A
类型安全 无类型安全,可与整数混用 严格类型安全,禁止与整数隐式转换
隐式转换 自动转换为int(如int x = A; 需显式转换(如int x = static_cast<int>(E_Name::A);
底层类型 默认为int,不可指定 可指定(如enum class E : short { A, B };
作用域 枚举项在全局作用域,可能冲突 枚举项在枚举类内,避免冲突
跨枚举比较 不同枚举项可比较(如A == B 禁止不同枚举类比较(编译错误)
初始化规则 未赋值时从0开始递增(如A=1, B, C→B=2, C=3) 未赋值时从0开始递增,需显式访问(如E_Name::A

结构体

结构体基本用法

核心要点 说明
声明语法 struct Student { int age; string name; };
初始化方式 - 聚合初始化:Student s = {18, "张三"};
- 构造函数初始化:Student s(18, "张三");
成员访问 - 普通变量:s.age
- 指针变量:s_ptr->name
内存占用 包含所有成员变量的字节和内存对齐填充字节,如struct {int a; char b;}占8字节(4+1+3填充)

结构体嵌套与内存对齐

核心要点 说明
嵌套语法 struct A { struct B { int b; } b; };
内存对齐规则 1. 成员变量起始地址为自身类型大小的倍数
2. 整体大小为最大成员类型的倍数
示例 struct {double a; int b;}占16字节(8+4+4填充)
优化建议 按成员大小降序排列,减少填充字节,如double在前,int在后

构造函数与析构函数

类型 构造函数 析构函数
声明 Student() {} / Student(int a) : age(a) {} ~Student() {}
作用 初始化结构体对象 释放对象资源(如堆内存)
调用时机 声明对象时自动调用 对象释放时自动调用
注意事项 可重载,无返回值,函数名与结构体同名 不可重载,无参数,函数名前加~

结构体与函数

场景 说明
参数传递 - 值传递:拷贝副本,不影响原对象
- 指针/引用传递:直接操作原对象
返回值 可返回结构体,但避免返回局部变量(生命周期结束后失效),推荐返回堆内存对象
示例 void func(Student& s) { s.age++; }(引用传递修改原对象)

结构体数组与指针

核心要点 说明
声明与初始化 - 静态数组Student arr[5];(默认调用无参构造)
- 聚合初始化Student arr[3] = {{18,"A"}, {20,"B"}, {22,"C"}};
- 动态数组(堆)Student* ptr = new Student[5];(需匹配delete[]释放)
指针指向数组 - 指针指向数组首地址:Student* p = arr;
- 指针偏移访问:p->age(首元素)、(p+1)->name(次元素)
数组元素访问 - 下标访问:arr[0].age
- 指针访问:p[0].age(等价于arr[0].age)、*(p+1).name(等价于arr[1].name
动态内存管理 - 堆上数组分配:Student* heapArr = new Student[5]{ {18,"A"}, ... };
- 释放:delete[] heapArr;(必须与new[]配对,否则内存泄漏)
构造与析构调用 - 静态数组:声明时调用构造函数,作用域结束时调用析构函数
- 动态数组:new[]时调用构造函数,delete[]时调用析构函数
指针数组 vs 数组指针 - 指针数组Student* ptrArr[3];(数组元素为结构体指针)
- 数组指针Student (*arrPtr)[5];(指针指向结构体数组)

类型别名(typedef/using)

核心要点 说明
语法 - typedef 原类型 别名;
- using 别名 = 原类型;
作用 简化复杂类型书写,提高可读性,如:
typedef void (*FuncPtr)(int, double);
示例 - 数组别名:typedef int Arr[10]; Arr arr;
- 函数指针别名:using FPtr = void(*)(Student&);

核心概念

要点 说明
本质 预处理指令,编译前进行文本替换,无类型检查,类似“文本别名”。
定义语法 #define 宏名 替换内容(不带参数)
#define 宏名(参数) 表达式(带参数)

分类与示例

类型 示例 注意事项
不带参数宏 #define PI 3.14159 常用于定义常量,如PIMAX_SIZE
带参数宏 #define ADD(x,y) (x+y) 表达式需加括号(如(x)*(y)),避免优先级错误。

关键用法

  • 常量定义#define ELEMENT_NUM 100
  • 代码简化#define PRINT(x) cout << x << endl
  • 条件编译
    #ifdef DEBUG  
        cout << "调试模式" << endl;  
    #endif  
    
  • 取消定义#undef MACRO_NAME

优缺点

优点 缺点
1. 简化重复代码,便于全局修改。
2. 条件编译灵活(适配不同平台/版本)。
1. 无类型检查,可能引发隐性错误。
2. 命名冲突风险,缺乏作用域限制。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏