C++ 中 struct(结构体)的定义与结构体数组 是 C++ 基础中非常重要且经常在面试、笔试、算法题中出现的知识点。
下面从定义方式、内存对齐、初始化、结构体数组、常见用法、注意事项 和 面试高频问题 全面讲解。
1. struct 的基本定义
C++ 中的 struct 与 C 语言基本一致,但功能更强大(可以包含成员函数、访问控制等)。
// 最基本写法
struct Student {
int id; // 学号
std::string name; // 姓名
int age; // 年龄
double score; // 分数
};
// 带默认访问权限(public)
struct Point {
double x;
double y;
double z;
};
C++ 中 struct 和 class 的主要区别(面试常考):
- 默认访问权限不同:
struct默认是publicclass默认是private- 其他(继承、构造、析构等)几乎无区别
现代 C++ 推荐:
如果只是数据载体(POD 类型),用 struct;
如果有行为(成员函数较多、封装),用 class。
2. 结构体的初始化方式(多种写法)
#include <string>
struct Student {
int id;
std::string name;
int age;
double score;
};
// 方式1:C风格初始化(最常见)
Student s1 = {1001, "Alice", 20, 95.5};
// 方式2:C++11 列表初始化(推荐)
Student s2{1002, "Bob", 21, 88.0};
// 方式3:指定成员初始化(C++20 更友好)
Student s3{.id = 1003, .name = "Charlie", .age = 19, .score = 92.5};
// 方式4:默认构造 + 逐个赋值
Student s4;
s4.id = 1004;
s4.name = "David";
s4.age = 22;
s4.score = 85.0;
3. 结构体数组(最常考)
// 定义结构体数组
Student students[5]; // 5 个元素,默认构造
// 初始化结构体数组
Student class1[3] = {
{1001, "Alice", 20, 95.5},
{1002, "Bob", 21, 88.0},
{1003, "Carol", 19, 92.5}
};
// C++11 统一初始化
Student class2[] = {
{1004, "David", 20, 90.0},
{1005, "Eve", 21, 85.5},
{1006, "Frank", 22, 93.0}
};
// 现代写法(推荐)
Student class3[4]{
{.id=1007, .name="Grace", .age=20, .score=96.0},
{.id=1008, .name="Henry", .age=19, .score=89.5},
{.id=1009, .name="Ivy", .age=21, .score=91.0},
{.id=1010, .name="Jack", .age=20, .score=87.0}
};
遍历方式对比:
// 传统 for
for(int i = 0; i < 3; i++) {
std::cout << class1[i].name << " " << class1[i].score << "\n";
}
// 范围 for(C++11+,推荐)
for(const auto& stu : class1) {
std::cout << stu.name << " " << stu.score << "\n";
}
4. 结构体内存对齐(面试高频)
C++ 会对结构体成员进行内存对齐(padding),目的是提高访问效率。
默认对齐规则(大多数编译器):
- 每个成员的起始地址必须是自身大小或系统默认对齐数的整数倍
- 整个结构体的大小必须是最大成员对齐数的整数倍
struct A {
char a; // 1 字节
int b; // 4 字节
double c; // 8 字节
};
// 实际占用:24 字节(不是 1+4+8=13)
内存布局(64位系统,典型 8 字节对齐):
偏移 0: char a (1字节 + 3字节填充)
偏移 4: int b (4字节)
偏移 8: double c (8字节)
总大小:24 字节
控制对齐方式(常用技巧):
// 方法1:使用 #pragma pack
#pragma pack(1) // 1 字节对齐(取消填充)
struct B {
char a;
int b;
double c;
}; // 大小 13 字节
#pragma pack() // 恢复默认
// 方法2:C++11 alignas
struct alignas(16) Vec4 {
float x, y, z, w;
};
5. 结构体数组的典型应用场景(算法题常见)
// 例:按分数降序排序
bool cmp(const Student& a, const Student& b) {
return a.score > b.score;
}
std::sort(std::begin(students), std::end(students), cmp);
// 例:结构体数组 + 结构体指针
Student* p = students;
p[0].score += 10; // 等价于 students[0].score += 10
6. 面试高频问题汇总
| 问题 | 核心回答要点 |
|---|---|
| struct 和 class 区别? | 默认访问权限不同(public vs private),其他几乎相同 |
| 结构体可以有成员函数吗? | 可以(C++ 支持),甚至可以有构造函数、析构函数、static 成员 |
| 结构体数组名是什么? | 指向首元素的指针(退化为指针),但不能直接 ++ / 赋值 |
| 结构体作为函数参数,传值还是传引用? | 推荐传 const 引用(避免拷贝开销) |
| 结构体内存对齐为什么存在? | 提高 CPU 访问效率(对齐访问快于非对齐访问) |
| 怎么让结构体按 1 字节对齐? | #pragma pack(1) 或 alignas(1) |
| 结构体可以作为 STL 容器元素吗? | 可以,但要满足可拷贝构造和可赋值(现代 C++ 更推荐 move 语义) |
| 结构体数组和指针数组哪个更常用? | 看场景:连续存储用结构体数组,动态大小用指针数组(vector) |
7. 小结口诀(快速记忆)
- struct 默认 public,class 默认 private
- 结构体数组名 → 首元素地址
- 内存对齐 → 看最大成员 + 编译器默认
- 初始化 →
{}列表初始化最现代 - 排序/查找 → 配合
std::sort、std::lower_bound使用 - 传参 → 优先
const Student&避免拷贝
如果你当前在准备面试或刷题,想针对结构体 + 链表/树/排序/哈希 的经典题目,我可以继续给你出题或讲解典型代码(比如结构体表示链表节点、坐标点排序、学生信息管理等)。
需要哪一部分再深入?直接说!