4.7 数组指针、指针数组与二级指针

本篇区分数组指针、指针数组与二级指针,并能读懂常见复杂指针声明。

数组指针、指针数组与二级指针

概念说明

这一节最容易混淆的不是概念本身,而是声明语法太像。 可以先用一句话区分三类写法:

  • int (*p)[3]p 是“指向数组的指针”,常叫数组指针。
  • int *p[3]p 是“由 3 个指针组成的数组”,常叫指针数组。
  • int **pppp 是“指向一级指针的指针”,也就是二级指针。

真正读懂这些写法的关键,是记住 [] 的优先级高于 *。 所以很多时候,括号不是装饰,而是决定类型含义的必要部分。

这些类型都不是为了“故意刁难语法”。 它们在字符串列表、二维数组、命令行参数和需要间接修改指针本身的场景里都非常常见。

语法/规则

  1. int (*p)[3] 表示 p 指向一个包含 3 个 int 的数组。
  2. int *p[3] 表示 p 是一个数组,其中每个元素都是 int *
  3. int **pp 表示 pp 指向一个 int * 类型对象。
  4. char *argv[] 本质上就是一个指针数组,因此命令行参数天然和这部分知识有关。
  5. 二维数组常和数组指针配合,例如 int (*row)[4] = matrix;
  6. int ** 不能直接替代二维数组指针,因为它们期望的内存布局不同。
  7. 读复杂声明时,可以从变量名开始向外看,优先判断它是“数组”还是“指针”。

示例

指针数组

1
2
3
4
5
6
7
#include <stdio.h>

int main(void) {
    char *names[] = {"Tom", "Ada", "Lin"};
    printf("second = %s\n", names[1]);
    return 0;
}

输出结果:

1
second = Ada

数组指针和二级指针

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <stdio.h>

int main(void) {
    int matrix[2][3] = {
        {1, 2, 3},
        {4, 5, 6}
    };
    int value = 10;
    int *p = &value;
    int **pp = &p;
    int (*row)[3] = matrix;

    printf("matrix[1][2] = %d\n", row[1][2]);
    printf("value = %d\n", **pp);
    return 0;
}

输出结果:

1
2
matrix[1][2] = 6
value = 10

常见错误

  1. 忘记 [] 的优先级高于 *,结果把数组指针和指针数组完全看反。
  2. 在二维数组场景里误用 int **,导致类型不匹配或访问方式错误。
  3. 看见两个星号就只记“更复杂的指针”,却没弄清它到底指向的是什么类型。
  4. 复杂指针声明里省略必要括号,结果声明含义和自己想的完全不同。
  5. 没把“变量名往外读”的习惯建立起来,导致每次遇到复杂声明都只能硬背。
本文禁止转载
使用 Hugo 构建
主题 StackJimmy 设计 由 Hobin 魔改
最近构建时间:2026-04-17 19:07:48 CST
载入天数...载入时分秒...
发表了 1 篇文章 · 发表了 152 篇笔记 · 总计 18 万 0 千字