06 数组名、指针数组与数组指针
一、核心结论:指针 +1 的步长
指针执行 +1,移动一个“所指向类型”的大小,而不是固定增加 1 字节。
int a[3] = {10, 20, 30};
int *p = a; // 指向一个 int
int (*q)[3] = &a; // 指向整个 int[3] 数组
| 表达式 | 类型 | +1 步长(假设 int 为 4 字节) |
|---|---|---|
a(通常表达式中) | int * | 4 字节 |
&a[0] | int * | 4 字节 |
&a | int (*)[3] | 12 字节 |
相同起始地址,不同步长
地址 0x1000 0x1004 0x1008 0x100C
┌───────────┬───────────┬───────────┐
数组 a │ a[0] = 10 │ a[1] = 20 │ a[2] = 30 │
└───────────┴───────────┴───────────┘
↑ ↑ ↑
a a+1 &a+1
&a
a + 1:跨一个int,指向a[1]。&a + 1:跨一个int[3],指向整个数组的尾后位置,不可解引用。a本身是数组对象,在大多数表达式中才转换为首元素指针;&a指向整个数组。
二、指针数组 vs 数组指针(新增)
| 对比 | 指针数组 | 数组指针 |
|---|---|---|
| 声明 | int *p[3] | int (*p)[3] |
| 本质 | 数组 | 指针 |
| 含义 | 存放 3 个 int * | 指向 int[3] 数组 |
| 常见访问 | *p[1] | (*p)[1] |
| 自身能否重新赋值 | 数组不能整体赋值 | 指针可以重新赋值 |
1. 指针数组:int *p[3]
┌──────┬──────┬──────┐
│ p[0] │ p[1] │ p[2] │
└──┬───┴──┬───┴──┬───┘
↓ ↓ ↓
x=10 y=20 z=30
int x = 10, y = 20, z = 30;
int *p[3] = {&x, &y, &z};
printf("%d\n", *p[1]); // 20
p[1] 是保存 y 地址的指针;*p[1] 读取 y 的值。
2. 数组指针:int (*p)[3]
┌────┬────┬────┐
p ───→ │ 10 │ 20 │ 30 │
└────┴────┴────┘
数组 a
int a[3] = {10, 20, 30};
int (*p)[3] = &a;
printf("%d\n", (*p)[1]); // 20
p 指向整个数组;*p 是数组本身;(*p)[1] 读取其第 2 个元素。
三、*p[1] 与 (*p)[1]
| 表达式 | 运算顺序 |
|---|---|
*p[1] | 先取 p[1],后解引用 |
(*p)[1] | 先解引用 p,再取下标 1 |
#include <stdio.h>
int main(void)
{
int x = 10, y = 20;
int *ptrs[2] = {&x, &y};
int a[3] = {30, 40, 50};
int (*row)[3] = &a;
printf("%d %d\n", *ptrs[1], (*row)[1]);
return 0;
}
输出:20 40。
无括号时,[] 比一元 * 优先级高;括号可以改变分组。
四、修改值 vs 修改指向
int a[2] = {10, 20};
int b[2] = {30, 40};
int *ptrs[2] = {&a[0], &b[0]};
int (*row)[2] = &a;
*ptrs[0] = 50; // 修改 a[0]
row = &b; // 让 row 指向数组 b
数组 a:[50] [20] 数组 b:[30] [40]
ptrs[0] ─→ a[0] = 50
ptrs[1] ─→ b[0] = 30
row ─→ 数组 b
| 表达式 | 值 |
|---|---|
a[0] | 50 |
*ptrs[1] | 30 |
(*row)[1] | 40 |
修改一个指针的指向不会自动修改其他独立指针。
五、蓝牙/TWS 工程选用
| 需求 | 推荐声明 | 原因 |
|---|---|---|
| 保存多个独立对象的地址 | Type *ptrs[N] | 每个元素可指向不同对象 |
| 操作固定列数的二维数组 | Type (*row)[N] | 保留整行数组的类型和步长 |
六、快速记忆
- 指针
+1按所指向类型大小移动。 a + 1跨一个元素;&a + 1跨整个数组。int *p[3]:指针数组,数组里有三个指针。int (*p)[3]:数组指针,一个指针指向完整数组。*p[1]:先下标再解引用;(*p)[1]:先解引用再下标。- 修改数据与改变指针指向不是一回事。
口诀:看括号辨类型,看指向类型算步长。