# 彻底攻克C语言指针

等几种较为复杂的指针，它们的定义形式分别是：

```c
int *p1[6];  //指针数组
int *(p2[6]);  //指针数组，和上面的形式等价
int (*p3)[6];  //二维数组指针
int (*p4)(int, int);  //函数指针
```

我相信大部分初学者对上面几种形式的指针都非常迷惑，不知道该从哪里入手去理解，为什么 p1、p2 是数组，而 p3 却是指针呢，它们仅仅是一个括号的区别。

指针是C语言中最强大最灵活的一部分，也是最难以理解的一部分，它是学习C语言的重点，没有学会指针就无从谈学会C语言。如果大家觉得上面几种形式的指针还能勉强接受，那么下面两个指针是不是让人抓狂呢？

```c
char *(* c[10])(int **p);
int (*(*(*pfunc)(int *))[5])(int *);
```

只要找到了窍门，再复杂的指针也是可以理解的，这节我们就来戳破这层窗户纸！

**C语言标准规定，对于一个符号的定义，编译器总是从它的名字开始读取，然后按照优先级顺序依次解析。对，从名字开始，不是从开头也不是从末尾，这是理解复杂指针的关键！**

有几种运算符的优先级非常容易混淆，它们的优先级从高到低依次是：

* 定义中被括号`( )`括起来的那部分。
* 后缀操作符：括号`( )`表示这是一个函数，方括号`[ ]`表示这是一个数组。
* 前缀操作符：星号`*`表示“指向xxx的指针”。

学会了“绝杀招式”，接下来我们就由浅入深，逐个击破上面的指针定义。

## 1) int \*p1\[6];

从 p1 开始理解，它的左边是 \*，右边是 \[ ]，\[ ] 的优先级高于 \*，所以编译器先解析`p1[6]`，p1 首先是一个拥有 6 个元素的数组，然后再解析`int *`，它用来说明数组元素的类型。从整体上讲，p1 是一个拥有 6 个 int \* 元素的数组，也即指针数组。

## 2) int (\*p3)\[6];

从 p3 开始理解，( ) 的优先级最高，编译器先解析`(*p3)`，p3 首先是一个指针，剩下的`int [6]`是 p3 指向的数据的类型，它是一个拥有 6 个元素的一维数组。从整体上讲，p3 是一个指向拥有 6 个 int 元素数组的指针，也即二维数组指针。

> 为了能够通过指针来遍历数组元素，在定义数组指针时需要进行降维处理，例如三维数组指针实际指向的数据类型是二维数组，二维数组指针实际指向的数据类型是一维数组，一维数组指针实际指向的是一个基本类型；在表达式中，数组名也会进行同样的转换（下降一维）。

## 3) int (\*p4)(int, int);

从 p4 开始理解，( ) 的优先级最高，编译器先解析`(*p4)`，p4 首先是一个指针，它后边的 ( ) 说明 p4 指向的是一个函数，括号中的

`int, int`是参数列表，开头的`int`用来说明函数的返回值类型。整体来看，p4 是一个指向原型为`int func(int, int);`的函数的指针。

## 4) char \*(\* c\[10])(int \*\*p);

这个定义有两个名字，分别是 c 和 p，乍看起来 p 是指针变量的名字，不过很遗憾这是错误的。如果 p 是指针变量名，`c[10]`这种写法就又定义了一个新的名字，这让人匪夷所思。

以 c 作为变量的名字，先来看括号内部部分`(* c[10])`：

```c
char *(*c[10])(int **p);
```

\[ ] 的优先级高于 \*，编译器先解析`c[10]`，c 首先是一个数组，它前面的`*`表明每个数组元素都是一个指针，只是还不知道指向什么类型的数据。整体上来看，`(* c[10])`说明 c 是一个**指针数组**，只是指针指向的数据类型尚未确定。

跳出括号，根据优先级规则（() 的优先级高于 \*）应该先看右边`(int **p)`：

```c
char *(*c[10])(int **p);
```

`( )`说明是一个函数，`int **p`是函数参数。

再看左边`char *`：

```c
char *(*c[10])(int **p);
```

`(*c[10])`表明 c 是一个指针数组，其他部分表明指针指向的数据类型，合起来就是：c 是一个拥有 10 个元素的**指针数组**，每个指针指向一个原型为`char *func(int **p);`的函数。

## 资料：

[只需一招，彻底攻克C语言指针](http://c.biancheng.net/cpp/html/3249.html)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xiaoxiami.gitbook.io/c/zhi-zhen/che-di-gong-ke-c-yu-yan-zhi-zhen.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
