基础与语法与数据结构:数据类型与变量
核心要点速览
- 数据类型分类:基本类型、复合(派生)类型、自定义类型
- 核心复合类型:指针、引用、数组、结构体、联合体、枚举
- 变量关键特性:存储类别(auto/static/extern 等)、初始化要求、作用域与生命周期
- 常量核心:const(只读)、constexpr(编译期常量)
- 类型转换:隐式转换(编译器自动)、显式转换(四种强制转换)
一、数据类型
1.1 基本类型
基本类型是 C++ 内置的基础数据类型,具有固定内存大小(部分受平台影响)和明确取值范围。
| 类型 | 典型大小(32/64 位系统) | 含义 / 范围 | 面试考点 |
|---|---|---|---|
bool |
1 字节 | 布尔值:true(1)/false(0) |
sizeof(bool)恒为 1;不可用 0 / 非 0 代替(语法允许但不规范) |
char |
1 字节 | ASCII 码:-128 |
区分signed char(带符号)和unsigned char(无符号);默认符号性由编译器决定 |
short |
2 字节 | 短整数:-32768~32767 | 与short int等价;用于节省内存 |
int |
4 字节(通用) | 整数:-2³¹~2³¹-1 | 平台无关性(主流编译器统一 4 字节);计数、返回值首选类型 |
long |
4 字节(32 位)/8 字节(64 位) | 长整数:随平台变化 | 避免依赖其大小,优先用固定宽度类型(如int64_t) |
long long |
8 字节 | 超长整数:-2⁶³~2⁶³-1 | C++11 标准,跨平台 8 字节,适合大整数 |
float |
4 字节 | 单精度浮点:有效数字 6-7 位 | 精度低;避免直接比较(存在误差) |
double |
8 字节 | 双精度浮点:有效数字 15-17 位 | 默认浮点类型(如3.14是 double);科学计算首选 |
void |
无大小 | 无类型(表示 “空”) | 用于无返回值函数、void*指针(可指向任意类型) |
关键补充
- 跨平台一致性保证:使用 C++11 固定宽度类型(定义于
<cstdint>),如int32_t(32 位带符号)、uint64_t(64 位无符号)。 sizeof计算规则:sizeof(char)恒为 1;sizeof(int)通常 4 字节;sizeof(void)编译报错;sizeof(bool)始终为 1。
1.2 复合类型(派生类型)
基于基本类型或自定义类型扩展,核心用于组合、关联或间接访问数据。
指针
- 存储目标变量的内存地址,大小仅与系统位数相关(32 位 4 字节,64 位 8 字节,与指向类型无关)。
- 核心特性:
- 未初始化指针为野指针(指向随机地址,操作易崩溃),需避免。
nullptr(C++11):空指针常量,替代NULL(NULL本质是 0,易引发歧义)。- 指针运算:仅对数组指针有效(
p++步长为指向类型的大小)。 - 数组名本质:指向数组首元素的常量指针(不可修改指向)。
引用
- 变量的 “别名”,语法:
类型& 引用名 = 变量名,必须初始化且绑定后不可更改。
| 对比项 | 指针 | 引用 |
|---|---|---|
| 定义 | 可空(nullptr) |
不可空(必须绑定变量) |
| 指向修改 | 可重新指向其他变量 | 绑定后不可更改 |
| 初始化 | 可延迟初始化(风险高) | 必须定义时初始化 |
| 内存占用 | 占内存(存储地址) | 不占额外内存(编译器优化) |
| 核心用途 | 动态内存管理、多级间接访问 | 函数参数 / 返回值(避免拷贝)、简化代码 |
结构体(Struct)
- 组合多个不同类型数据(成员)为一个整体,成员按顺序占用独立内存。
- 核心特性:结构体大小 = 成员大小之和 + 内存对齐填充字节。
- 用途:存储关联数据(如个人信息:姓名、年龄、身高)。
联合体(Union)
- 所有成员共享同一块内存,同一时间仅能有效使用一个成员。
| 对比项 | 结构体(Struct) | 联合体(Union) |
|---|---|---|
| 内存分配 | 成员独立占用内存,总大小 = 成员和 + 填充 | 成员共享内存,总大小 = 最大成员大小(+ 对齐填充) |
| 成员关系 | 成员并存(可同时访问) | 成员互斥(同一时间仅能用一个) |
| 核心用途 | 组合关联数据 | 节省内存、实现类型转换 |
枚举(Enum)
- 自定义整数类型,用于组合含义相关的命名常量。
- 分类:
- 传统枚举:
enum E {A, B=5, C};,成员作用域全局(易冲突),可隐式转 int。 - 强类型枚举(C++11 推荐):
enum class E {A, B};,作用域受限(需E::A访问),不可隐式转 int(更安全)。
- 传统枚举:
- 赋值规则:未手动赋值时,首个常量为 0,后续依次 + 1;中间赋值后,后续常量基于该值递增。
1.3 自定义类型
- 由用户通过
class(类)、struct(结构体)、enum(枚举)等关键字定义的类型。 - 核心作用:封装数据与行为,提升代码可读性和复用性。
二、变量
2.1 变量的定义与初始化
定义:编译器为变量分配内存空间。
初始化:定义时赋予初始值(避免 “垃圾值”,提升代码安全性)。
常见初始化方式:
1
2
3
4int a = 10; // 拷贝初始化
int b(20); // 直接初始化(适合构造函数场景)
int c{30}; // 列表初始化(C++11,禁止窄化转换,如int{3.14}编译报错)
int d = {40}; // 拷贝列表初始化
2.2 存储类别(关键字修饰)
存储类别决定变量的生命周期、作用域和存储位置。
| 关键字 | 核心特性与用途 |
|---|---|
auto(C++11) |
编译器自动推导类型;不能用于函数参数(模板除外)、数组类型;推导引用需显式加& |
static |
局部静态变量:生命周期为程序全程,首次调用初始化;全局静态变量:仅当前.cpp 可见(避免命名冲突);类静态成员:属于类,所有对象共享 |
extern |
声明变量 / 函数在其他文件定义(跨文件共享);仅声明不分配内存,带初始化则变为定义 |
register |
提示编译器存于寄存器(C++17 后弃用,现代编译器优化足够) |
mutable |
仅用于类非静态成员;允许 const 成员函数修改该变量(突破 const 限制) |
volatile |
禁止编译器优化;变量值可能被外部因素修改(如硬件、多线程),每次访问直接读内存 |
2.3 常见问题解答
- 局部变量屏蔽全局变量时如何访问全局变量?用
::(全局作用域解析符),如::global_var。 - 全局变量与局部
static变量的初始化顺序?全局变量在main前初始化,局部static变量首次进入函数时初始化(C++11 后线程安全);销毁顺序与初始化相反。 - 未初始化的局部变量和全局变量区别?局部非
static变量是 “垃圾值”;全局变量和static变量会零初始化(数值为 0,指针为nullptr)。
2.4 常量
常量是初始化后不可修改的变量,核心分为const和constexpr。
const(只读常量)
修饰变量:初始化后不可修改,作用域与变量一致。
修饰指针(三大场景):
1
2
3const int* p; // 常量指针:指向的内容不可改(*p不可改),p可改指向
int* const p; // 指针常量:p的指向不可改,*p可改
const int* const p; // 指向常量的指针常量:内容和指向均不可改
constexpr(编译期常量,C++11)
- 要求表达式在编译期可计算,比
const更严格(const可运行期初始化)。 - 用途:定义数组大小、模板参数等依赖编译期常量的场景。
2.5 类型转换
隐式转换(自动转换)
- 遵循 “安全优先” 原则,优先 “小范围→大范围”(类型提升),避免溢出。
- 转换顺序:
bool→char→short→int→long→long long→float→double→long double。 - 注意:
explicit关键字可禁止类的隐式类型转换。
显式转换(四种强制转换)
| 转换方式 | 核心用途 | 风险程度 |
|---|---|---|
static_cast |
基本类型转换(int→double)、父类 / 子类指针转换(无动态检查) |
中等(父类→子类可能越界) |
dynamic_cast |
多态类型转换(仅用于含虚函数的类),运行期检查有效性 | 低(失败返回nullptr/ 抛异常) |
const_cast |
移除指针 / 引用的const属性 |
高(修改原const变量会导致未定义行为) |
reinterpret_cast |
底层二进制重解释(如int*→char*) |
极高(依赖平台,无移植性) |
问答
- 何时用
dynamic_cast?多态场景下,需将父类指针安全转为子类指针(需父类有虚函数,运行期校验合法性)。 - 为何避免
reinterpret_cast?直接操作二进制,忽略类型安全,结果依赖平台,移植性极差。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 肖恩的博客!
评论

