C++ 进阶核心语法详解:数组、指针、结构体、枚举
在上一篇基础语法的基础上,本文聚焦 C++ 中更核心的进阶语法------数组、指针、结构体、枚举,这些是理解 C++ 内存模型、数据组织方式的关键,也是区分 C++ 与高级语言(如 Python)的核心特征。每个知识点均配套可运行的代码示例,兼顾原理与实战。
一、数组:固定大小的同类型数据集合
数组是 C++ 中最基础的复合数据类型,用于存储固定数量、相同类型的元素,内存中连续排布,访问效率极高。
1. 数组的基本语法
(1)定义语法
cpp
// 语法:类型 数组名[元素个数];
int nums[5]; // 定义一个能存5个int的数组(未初始化)
// 定义并初始化(推荐)
int nums2[5] = {1, 2, 3, 4, 5}; // 完全初始化
int nums3[5] = {1, 2}; // 部分初始化,剩余元素默认值为0
int nums4[] = {1, 2, 3}; // 省略长度,编译器自动计算(长度为3)
(2)核心规则
- 数组长度必须是常量 (编译期确定),不能是变量(C++11 后可通过
std::vector实现动态数组); - 数组下标从
0开始,最后一个元素下标为长度-1; - 数组名本质是指向第一个元素的常量指针(不能修改指向,但可修改元素值)。
2. 数组的访问与遍历
cpp
#include <iostream>
using namespace std;
int main() {
// 定义并初始化字符串数组
string books[3] = {"C++ Primer", "Python编程", "数据结构"};
// 方式1:下标访问(最常用)
cout << "下标访问:" << books[0] << endl; // 输出第一个元素
// 方式2:遍历数组(for循环)
int len = sizeof(books) / sizeof(books[0]); // 计算数组长度
cout << "\n遍历数组:" << endl;
for (int i = 0; i < len; i++) {
cout << "第" << i+1 << "本:" << books[i] << endl;
}
// 方式3:指针访问(数组名=首元素地址)
cout << "\n指针访问:" << endl;
string* p = books; // p指向数组首元素
for (int i = 0; i < len; i++) {
cout << *(p + i) << endl; // *(p+i) 等价于 books[i]
}
return 0;
}
运行结果:
下标访问:C++ Primer
遍历数组:
第1本:C++ Primer
第2本:Python编程
第3本:数据结构
指针访问:
C++ Primer
Python编程
数据结构
3. 二维数组(数组的数组)
用于存储表格类数据(行+列),语法为 类型 数组名[行数][列数]:
cpp
#include <iostream>
using namespace std;
int main() {
// 定义3行2列的二维数组(成绩表)
int scores[3][2] = {
{90, 85}, // 第1行:语文、数学
{88, 92}, // 第2行
{78, 80} // 第3行
};
// 遍历二维数组
for (int i = 0; i < 3; i++) { // 行
cout << "第" << i+1 << "个学生:";
for (int j = 0; j < 2; j++) { // 列
cout << scores[i][j] << " ";
}
cout << endl;
}
return 0;
}
运行结果:
第1个学生:90 85
第2个学生:88 92
第3个学生:78 80
4. 数组的局限性与替代方案
-
局限性:长度固定、无法动态扩容、越界访问无编译报错(运行时可能崩溃);
-
替代方案:C++ 标准库的
std::vector(动态数组),兼容数组语法且支持动态增删:cpp#include <iostream> #include <vector> // 引入vector头文件 using namespace std; int main() { vector<int> nums = {1, 2, 3}; // 动态数组 nums.push_back(4); // 动态添加元素 nums[0] = 10; // 下标访问 // 遍历vector for (int num : nums) { // 范围for循环(C++11+) cout << num << " "; } return 0; }运行结果:
10 2 3 4
二、指针:直接操作内存地址的核心工具
指针是 C++ 最具特色的语法,本质是存储内存地址的变量,通过指针可直接读写内存,实现高效的数据操作(如动态内存分配、函数传址)。
1. 指针的基本概念
- 内存地址:每个变量在内存中占用一块空间,地址是该空间的唯一标识(如
0x7ffeefbff5c4); - 指针变量:存储地址的变量,类型需与指向的变量类型匹配;
- 核心运算符:
&(取地址符):获取变量的内存地址;*(解引用符):通过地址访问变量的值。
2. 指针的定义与使用
cpp
#include <iostream>
using namespace std;
int main() {
// 1. 普通变量
int a = 10;
cout << "变量a的值:" << a << endl;
cout << "变量a的地址:" << &a << endl; // &a 获取a的地址
// 2. 定义指针变量(类型* 指针名)
int* p = &a; // p存储a的地址,p是指向int的指针
cout << "指针p的值(a的地址):" << p << endl;
cout << "指针p解引用(a的值):" << *p << endl; // *p 访问p指向的变量
// 3. 通过指针修改变量值
*p = 20;
cout << "修改后a的值:" << a << endl; // a变为20
return 0;
}
运行结果(地址仅为示例):
变量a的值:10
变量a的地址:0x7ffeefbff5c4
指针p的值(a的地址):0x7ffeefbff5c4
指针p解引用(a的值):10
修改后a的值:20
3. 指针的核心用法
(1)函数传址(修改实参)
C++ 函数参数默认是「值传递」(拷贝参数),指针可实现「址传递」(直接修改原变量):
cpp
#include <iostream>
using namespace std;
// 指针传参:交换两个整数
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
}
int main() {
int a = 1, b = 2;
cout << "交换前:a=" << a << ", b=" << b << endl;
swap(&a, &b); // 传入a、b的地址
cout << "交换后:a=" << a << ", b=" << b << endl;
return 0;
}
运行结果:
交换前:a=1, b=2
交换后:a=2, b=1
(2)动态内存分配(new/delete)
指针结合 new/delete 可在堆上分配内存(数组/对象),灵活控制内存生命周期:
cpp
#include <iostream>
using namespace std;
int main() {
// 1. 动态分配单个变量
int* p = new int; // 堆上分配int大小的内存,返回地址
*p = 100;
cout << "动态变量值:" << *p << endl;
delete p; // 释放内存(必须!否则内存泄漏)
// 2. 动态分配数组
int* arr = new int[5]{1,2,3,4,5}; // 堆上分配5个int的数组
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
delete[] arr; // 释放数组内存(必须加[])
return 0;
}
运行结果:动态变量值:100 1 2 3 4 5
(3)空指针与野指针
-
空指针:指向
NULL/nullptr的指针(无有效地址),避免野指针:cppint* p = nullptr; // C++11推荐(替代NULL) if (p == nullptr) { cout << "指针为空" << endl; } -
野指针:指向已释放/无效内存的指针,访问会导致程序崩溃,需避免:
❌ 错误示例:cppint* p = new int; delete p; *p = 10; // 野指针访问,崩溃!
4. 指针与引用的区别
引用(&)是指针的简化版,新手易混淆,核心区别:
| 特性 | 指针 | 引用 |
|---|---|---|
| 本质 | 存储地址的变量 | 变量的别名 |
| 可修改指向 | 可以(如 p = &b) |
不可(初始化后固定) |
| 空值 | 可指向nullptr | 必须绑定有效变量 |
| 语法 | 需要解引用(*p) |
直接使用(如 ref) |
示例:
cpp
#include <iostream>
using namespace std;
int main() {
int a = 10;
int& ref = a; // 引用:ref是a的别名
ref = 20;
cout << "a的值:" << a << endl; // a=20
return 0;
}
三、结构体:自定义复合数据类型
结构体(struct)用于将不同类型的变量 封装成一个整体,是 C++ 面向对象的基础(比 class 更轻量,默认公有访问)。
1. 结构体的定义与使用
(1)基本语法
cpp
// 定义结构体
struct 结构体名 {
// 成员变量(可不同类型)
类型1 成员1;
类型2 成员2;
// 成员函数(C++支持,C不支持)
返回值类型 函数名(参数) { ... }
};
(2)完整示例:学生结构体
cpp
#include <iostream>
#include <string>
using namespace std;
// 定义结构体:学生信息
struct Student {
// 成员变量
string name; // 姓名
int age; // 年龄
float score; // 成绩
// 成员函数:打印学生信息
void showInfo() {
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "成绩:" << score << endl;
}
};
int main() {
// 1. 创建结构体对象
Student s1; // 栈上创建
// 赋值成员变量(. 访问成员)
s1.name = "张三";
s1.age = 18;
s1.score = 92.5;
// 调用成员函数
s1.showInfo();
// 2. 初始化结构体
Student s2 = {"李四", 19, 88.0};
cout << "\n李四的成绩:" << s2.score << endl;
// 3. 结构体指针(-> 访问成员)
Student* p = &s2;
cout << "李四的姓名:" << p->name << endl; // 等价于 (*p).name
return 0;
}
运行结果:
姓名:张三
年龄:18
成绩:92.5
李四的成绩:88
李四的姓名:李四
2. 结构体数组
存储多个结构体对象,适合批量管理数据:
cpp
#include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
int age;
};
int main() {
// 结构体数组
Student students[2] = {
{"张三", 18},
{"李四", 19}
};
// 遍历结构体数组
for (int i = 0; i < 2; i++) {
cout << "第" << i+1 << "个学生:" << students[i].name << "," << students[i].age << "岁" << endl;
}
return 0;
}
运行结果:
第1个学生:张三,18岁
第2个学生:李四,19岁
3. 结构体与类的区别
C++ 中 struct 和 class 几乎等价,核心区别仅在于默认访问权限:
struct:成员默认public(外部可直接访问);class:成员默认private(仅内部可访问)。
示例:
cpp
struct A {
int a = 10; // 默认public,外部可访问
};
class B {
int b = 20; // 默认private,外部不可访问
public:
int getB() { return b; } // 需通过公有函数访问
};
int main() {
A a;
cout << a.a << endl; // 正常访问
B b;
// cout << b.b << endl; // 编译报错
cout << b.getB() << endl; // 正确访问
return 0;
}
四、枚举:限定取值范围的常量集合
枚举(enum/enum class)用于定义命名常量集合,将离散的常量组织起来,提高代码可读性(替代魔法数字)。
1. 传统枚举(enum)
(1)基本语法
cpp
// 定义枚举:枚举名 { 常量1, 常量2, ... }
enum 枚举名 {
常量1, // 默认值0
常量2, // 默认值1,依次递增
常量3 = 5, // 自定义值,后续+1
常量4
};
(2)示例:图书状态枚举
cpp
#include <iostream>
using namespace std;
// 定义枚举:图书状态
enum BookStatus {
AVAILABLE, // 可借阅(默认0)
BORROWED, // 已借出(1)
LOST = 5 // 丢失(自定义5)
};
int main() {
// 使用枚举常量
BookStatus status = AVAILABLE;
// 枚举本质是整数,可转换
cout << "AVAILABLE的值:" << status << endl; // 输出0
// 条件判断
if (status == AVAILABLE) {
cout << "图书可借阅" << endl;
}
// 遍历枚举(需手动控制范围)
for (int i = AVAILABLE; i <= LOST; i++) {
cout << "枚举值:" << i << endl;
}
return 0;
}
运行结果:
AVAILABLE的值:0
图书可借阅
枚举值:0
枚举值:1
枚举值:2
枚举值:3
枚举值:4
枚举值:5
2. 强类型枚举(enum class,C++11+)
传统枚举存在「作用域污染」「类型不安全」问题,enum class 解决了这些问题,是推荐用法:
cpp
#include <iostream>
using namespace std;
// 强类型枚举(作用域限定)
enum class Color {
Red, // 0
Green, // 1
Blue // 2
};
int main() {
// 必须加枚举名限定
Color c = Color::Red;
// 强类型:不能直接转换为整数,需显式强制转换
cout << "Red的值:" << static_cast<int>(c) << endl;
// 类型安全:不会与其他枚举/整数混淆
// if (c == 0) {} // 编译报错
if (c == Color::Red) {
cout << "颜色是红色" << endl;
}
return 0;
}
运行结果:
Red的值:0
颜色是红色
3. 枚举的典型应用场景
- 状态标识:如订单状态(待支付、已支付、已取消);
- 选项选择:如颜色、方向、错误码;
- 替代魔法数字:用
Status::SUCCESS替代0,代码更易读。
示例:订单状态枚举
cpp
#include <iostream>
using namespace std;
enum class OrderStatus {
PENDING, // 待支付
PAID, // 已支付
CANCELLED // 已取消
};
void printOrderStatus(OrderStatus status) {
switch (status) {
case OrderStatus::PENDING:
cout << "订单待支付" << endl;
break;
case OrderStatus::PAID:
cout << "订单已支付" << endl;
break;
case OrderStatus::CANCELLED:
cout << "订单已取消" << endl;
break;
}
}
int main() {
OrderStatus order = OrderStatus::PAID;
printOrderStatus(order);
return 0;
}
运行结果:订单已支付
五、总结
本文覆盖了 C++ 进阶核心语法,关键知识点总结:
- 数组 :固定长度的同类型数据集合,内存连续,下标从0开始,
std::vector是更灵活的动态替代方案; - 指针 :存储内存地址的变量,通过
&(取地址)、*(解引用)操作,结合new/delete实现动态内存分配,需避免野指针; - 结构体 :封装不同类型数据的自定义类型,默认公有访问,支持成员函数,是
class的轻量版; - 枚举 :组织命名常量的集合,
enum class是强类型版本,避免作用域污染和类型不安全问题。
这些语法是 C++ 高效性和灵活性的核心体现,也是理解后续「类继承」「多态」「STL容器」的基础。建议通过小项目(如通讯录管理系统、图书管理系统)巩固------用结构体存储数据,用指针实现动态增删,用枚举标识状态,全面掌握这些知识点。