C++ 进阶核心语法详解:数组、指针、结构体、枚举

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 的指针(无有效地址),避免野指针:

    cpp 复制代码
    int* p = nullptr; // C++11推荐(替代NULL)
    if (p == nullptr) {
        cout << "指针为空" << endl;
    }
  • 野指针:指向已释放/无效内存的指针,访问会导致程序崩溃,需避免:
    ❌ 错误示例:

    cpp 复制代码
    int* 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++ 中 structclass 几乎等价,核心区别仅在于默认访问权限

  • 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++ 进阶核心语法,关键知识点总结:

  1. 数组 :固定长度的同类型数据集合,内存连续,下标从0开始,std::vector 是更灵活的动态替代方案;
  2. 指针 :存储内存地址的变量,通过 &(取地址)、*(解引用)操作,结合 new/delete 实现动态内存分配,需避免野指针;
  3. 结构体 :封装不同类型数据的自定义类型,默认公有访问,支持成员函数,是 class 的轻量版;
  4. 枚举 :组织命名常量的集合,enum class 是强类型版本,避免作用域污染和类型不安全问题。

这些语法是 C++ 高效性和灵活性的核心体现,也是理解后续「类继承」「多态」「STL容器」的基础。建议通过小项目(如通讯录管理系统、图书管理系统)巩固------用结构体存储数据,用指针实现动态增删,用枚举标识状态,全面掌握这些知识点。

相关推荐
ZHOUPUYU6 小时前
PHP 8.3网关优化:我用JIT将QPS提升300%的真实踩坑录
开发语言·php
寻寻觅觅☆10 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc11 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
偷吃的耗子11 小时前
【CNN算法理解】:三、AlexNet 训练模块(附代码)
深度学习·算法·cnn
l1t11 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
赶路人儿11 小时前
Jsoniter(java版本)使用介绍
java·开发语言
化学在逃硬闯CS12 小时前
Leetcode1382. 将二叉搜索树变平衡
数据结构·算法
ceclar12312 小时前
C++使用format
开发语言·c++·算法
码说AI12 小时前
python快速绘制走势图对比曲线
开发语言·python
Gofarlic_OMS12 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化