struct 结构体¶
方法速览¶
| 任务 | 方法 | 口诀 |
|---|---|---|
| 定义 | struct 名 { 成员列表 };——末尾分号必带 |
大括号后分号 |
| 访问 | 变量用 .,指针用 -> |
变量点、指针箭 |
| 求大小 | 成员依次排 + 对齐填充,补齐到最大对齐值 | 相加再对齐 |
| 排序 | sort(a, a+n, cmp),cmp 写“小于”的规则 |
cmp 管小于,返回真假 |
定义与成员访问¶
- 初始化:
{3, 4}按声明顺序给x、y;也可逐个赋值p.x = 3; p.y = 4;; - 访问:变量
p.x;指针q->x(等价(*q).x); - 嵌套:
a.in.x一路点到底;自引用必须用指针:struct Node { int d; Node* next; };——不能直接放Node next;(无限套娃); - typedef:
typedef struct { int x, y; } P;之后直接P p;; - 结构体可以整体赋值(逐成员拷贝)、可以作函数参数(值传递,拷贝一份,函数内修改不影响外面)。
例:
配合排序¶
sort 默认升序;自定义顺序靠比较器 cmp(a, b):返回真表示 a 排在 b 前面(即 a “小于” b)。
三条规矩:
- cmp 描述的是严格小于,相等必须返回 false(返回 true 会违反严格弱序,可能崩);
- 多关键字:先比第一关键字,不同就出结果;相同再比第二关键字;
- 降序就把
<换成>(或sort(..., greater<int>()))。
例:{(3,2), (1,5), (3,1), (1,2)} 按“x 升、x 同 y 降”排 → \(\{(1,5), (1,2), (3,2), (3,1)\}\)。
与 union 对比¶
| 对比项 | struct |
union |
|---|---|---|
| 内存 | 每个成员各占一块 | 所有成员共享一块 |
| 大小 | 成员相加 + 对齐填充(≥ 成员和) | 最大成员(对齐补齐) |
| 有效成员 | 全部同时有效 | 同一时刻只有一个 |
| 场景 | 打包多种数据(点、学生记录) | 互斥格式、拆字节、省空间 |
例:struct { int i; double d; } = 16 字节;union { int i; double d; } = 8 字节。
练习题目¶
练习 1 · 定义的末尾分号¶
题目
下列结构体定义正确的是( )
- A.
struct P { int x, y; }; - B.
struct P { int x, y } - C.
struct P { int x, y; } - D.
struct P ( int x, y );
答案与解析
答案:A
} 后的分号是定义的一部分,漏了编译错误;成员列表用 {} 不用 ()。
练习 2 · 变量访问用点¶
题目
struct P { int x, y; }; P p; 给 x 赋 3 的正确写法是( )
- A.
p.x = 3; - B.
p:x = 3; - C.
p->x = 3; - D.
x.p = 3;
答案与解析
答案:A
p 是变量用 .;-> 是指针专属。
练习 3 · 指针访问用箭头¶
题目
P* q = &p; 通过 q 给 y 赋 4,正确写法是( )
- A.
q.y = 4; - B.
*q.y = 4; - C.
y->q = 4; - D.
q->y = 4;
答案与解析
答案:D
指针用 ->;(*q).y 也对,但 *q.y 因 . 优先级高于 * 会解析成 *(q.y) 出错。
练习 4 · 两种访问的等价¶
题目
与 p->next 完全等价的表达式是( )
- A.
p.next - B.
(*p).next - C.
&p.next - D.
p.(*next)
答案与解析
答案:B
-> 就是“解引用再点”的缩写:(*p).next。
练习 5 · 初始化¶
题目
struct S { int a; char b; double c; }; S s = {1, 'x', 2.5}; 之后( )
- A. 编译错误,必须逐个赋值
- B.
s.a='x', s.b=1, s.c=2.5 - C.
s.a=1, s.b='x', s.c=2.5 - D.
s.c未初始化
答案与解析
答案:C
花括号按成员声明顺序依次初始化。
练习 6 · typedef struct¶
题目
typedef struct { int x, y; } P; 定义变量应写( )
- A.
struct P p; - B.
p P; - C.
P struct p; - D.
P p;
答案与解析
答案:D
typedef 之后 P 就是完整类型名,前面的 struct 不再需要。
练习 7 · 嵌套结构体¶
题目
struct In { int v; }; struct Out { In a; int b; }; Out o; 访问 Out 里 In 的 v,写作( )
- A.
o->a.v - B.
o.a.v - C.
o.v.a - D.
a.o.v
答案与解析
答案:B
o 是变量一路用 .;嵌套就从外往内逐层点。
练习 8 · 自引用必须用指针¶
题目
链表结点的正确定义是( )
- A.
struct Node { int d; Node next; }; - B.
struct Node { int d; Node* next; }; - C.
struct Node { int d; struct Node next; }; - D.
struct Node { int* d; int next; };
答案与解析
答案:B
成员里放自身类型会无限递归定义;放指针只占 8 字节,合法。
练习 9 · 结构体数组¶
题目
P a[3] = {{1,2},{3,4},{5,6}}; 则 a[1].y 的值是( )
- A. \(2\)
- B. \(3\)
- C. \(4\)
- D. \(6\)
答案与解析
答案:C
a[1] 是第 2 个元素 {3,4},.y 取 4。
练习 10 · 整体赋值¶
题目
P a = {1, 2}, b; b = a; b.x = 9; 之后 a.x 的值( )
- A. \(1\)
- B. 未定义
- C. \(0\)
- D. \(9\)
答案与解析
答案:A
b = a 是逐成员拷贝,之后改 b 不影响 a——结构体赋值是拷贝语义。
练习 11 · 值传递¶
题目
调用后p.x 的值( )
- A. \(100\)
- B. \(1\)
- C. 编译错误
- D. 未定义
答案与解析
答案:B
结构体值传递:函数里拿到的是拷贝,改的是副本。想在函数里改原件要传引用 f(P& s) 或指针。
练习 12 · sizeof(基础对齐)¶
题目
struct S { int i; char c; }; 的 sizeof 是( )
- A. \(5\)
- B. \(4\)
- C. \(8\)
- D. \(6\)
答案与解析
答案:C
\(4 + 1 = 5\),补齐到最大对齐值 4 的倍数 → 8。
干扰项思路:A 直接相加忘补齐。
练习 13 · sizeof(含 double)¶
题目
struct S { int i; char c; double d; }; 的 sizeof 是( )
- A. \(13\)
- B. \(8\)
- C. \(24\)
- D. \(16\)
答案与解析
答案:D
int 4 + char 1 + 填充 3(对齐 double)+ double 8 = 16。
练习 14 · sizeof(两个 char)¶
题目
struct S { char a; char b; int i; }; 的 sizeof 是( )
- A. \(6\)
- B. \(12\)
- C. \(8\)
- D. \(4\)
答案与解析
答案:C
两个 char 连排(1+1),再填充 2 字节对齐 int(4),共 8。
练习 15 · 含数组的 sizeof¶
题目
struct S { char name[10]; int age; }; 的 sizeof 是( )
- A. \(14\)
- B. \(16\)
- C. \(11\)
- D. \(10\)
答案与解析
答案:B
\(10 + 2\)(填充到 4 的倍数)\(+ 4 = 16\)。
练习 16 · sort 默认升序¶
题目
int a[4] = {3, 1, 4, 2}; sort(a, a + 4); 之后数组是( )
- A.
{4, 3, 2, 1} - B.
{3, 1, 4, 2} - C.
{1, 2, 3, 4} - D.
{1, 4, 2, 3}
答案与解析
答案:C
不带比较器默认升序。
练习 17 · 降序排序¶
题目
要把 int a[] 按从大到小排序,正确写法是( )
- A.
sort(a, a + n, greater<int>()); - B.
sort(a, a + n, less<int>());再反转 - C.
sort(a, a + n); - D.
sort(a + n, a);
答案与解析
答案:A
greater<int>() 让“大的算小”→ 降序;less 是默认升序;D 区间端点写反。
练习 18 · cmp 的返回语义¶
题目
自定义 bool cmp(int a, int b) { return a > b; } 并 sort(a, a+n, cmp),结果是( )
- A. 升序
- B. 编译错误
- C. 只排序奇数
- D. 降序
答案与解析
答案:D
cmp 返回真 = a 排 b 前面;a > b 为真即大者在前 → 降序。cmp 定义“谁在前”,不是“谁小”的字面意思。
练习 19 · 多关键字排序¶
题目
对{(3,2),(1,5),(3,1),(1,2)} 排序结果是( )
- A.
{(1,5), (1,2), (3,2), (3,1)} - B.
{(1,2), (1,5), (3,1), (3,2)} - C.
{(3,2), (3,1), (1,5), (1,2)} - D.
{(1,2), (1,5), (3,2), (3,1)}
答案与解析
答案:A
x 升序先分桶:x=1 在前;x 相同比 y 降序 → (1,5) 在 (1,2) 前,(3,2) 在 (3,1) 前。
练习 20 · cmp 不能“相等返回真”¶
题目
bool cmp(int a, int b) { return a >= b; } 的问题是( )
- A. 没有问题,等价降序
- B. 相等时返回真违反严格弱序,可能运行期崩溃
- C. 会把数组变成升序
- D. 编译错误
答案与解析
答案:B
比较器要求“a 等于 b 时必须返回 false”;>= 让相等元素也满足“前于”,std::sort 的快速排序分支可能越界崩溃。降序写 a > b 就够了。
练习 21 · 字符串成员排序¶
题目
struct S { string name; }; 按 name 字典序升序,cmp 应写( )
- A.
return a.name < b.name; - B.
return a.name > b.name; - C.
return a < b; - D.
return a.name.size() < b.name.size();
答案与解析
答案:A
string 的 < 就是字典序;B 是降序;D 按长度排不是字典序。
练习 22 · 成员默认权限¶
题目
struct S { int x; }; 中 x 的默认访问权限是( )
- A. private
- B. protected
- C. public
- D. 没有权限概念
答案与解析
答案:C
struct 成员默认 public;class 默认 private——这是两者在 C++ 里几乎唯一的差别。
练习 23 · 结构体含函数成员¶
题目
关于 C++ 的 struct,正确的是( )
- A. 只能放数据成员,不能放函数
- B. struct 不是 C++ 关键字
- C. 可以放函数,但不能有构造函数
- D. 可以有成员函数、构造函数,与 class 基本等价(仅默认权限不同)
答案与解析
答案:D
C++ 的 struct 可含成员函数与构造函数,功能上与 class 等价,只差默认访问权限。
练习 24 · 与 union 的大小对比¶
题目
struct S { int i; char c; }; 与 union U { int i; char c; }; 的 sizeof 分别是( )
- A. \(5\) 和 \(4\)
- B. \(8\) 和 \(4\)
- C. \(8\) 和 \(5\)
- D. \(4\) 和 \(4\)
答案与解析
答案:B
struct:\(4+1\) 补齐到 8;union:\(\max(4,1) = 4\)。
练习 25 · 选型¶
题目
“学生记录:姓名 string、年龄 int、成绩数组”,应选用( )
- A. union——省空间
- B. enum
- C. struct——各字段同时有效
- D. 指针数组
答案与解析
答案:C
多个字段要同时保存,必须 struct;union 适合互斥字段。
练习 26 · 综合输出¶
题目
输出( )- A. \(3\)
- B. \(7\)
- C. \(4\)
- D. 未定义
答案与解析
答案:B
指针传参改的是原件:\(3 + 4 = 7\)。对比练习 11 的值传递——指针(或引用)才能把修改带出来。
历年真题¶
2023 年 · 第 4 题¶
题目
假设有一个链表的节点定义如下:
现在有一个指向链表头部的指针:Node* head。如果想要在链表中插入一个新节点,其成员 data 的值为 \(42\),并使新节点成为链表的第一个节点,下面哪个操作是正确的?( )
A.
B. C. D.答案与解析
答案:A
头插三步:新结点接到旧头(newNode->next = head)→ 头指针改指新结点(head = newNode)。newNode 是指针,所以成员访问全程 ->。
干扰项思路:B 给 head->data 赋值改的是旧首结点且 newNode 未接 data;C 是尾接不是头插;D 忘了 head = newNode,链表头还是旧结点。
易错小结¶
}后的分号是 struct 定义的一部分,漏了必错;- 变量
.、指针->;p->x等价(*p).x,但*p.x因优先级出错; - 结构体赋值/传参都是拷贝:函数里想改原件传
P&或P*; - sizeof = 成员相加 + 对齐填充再补齐到最大对齐值(int+char=8、int+char+double=16);
- cmp 描述“谁排前面”:升序
a.x < b.x、降序>;相等必须返回 false(>=会崩); - 自引用成员必须是指针
Node* next。