这四个概念都涉及指针,但在声明语法、内存模型和使用场景上有明显区别。下面分别定义并对比。
1. 二级指针
定义:指向指针的指针,保存的是另一个指针变量的地址。
声明:类型 **ptr;
示例:
c
int a = 10; int *p = &a; // 一级指针 int **pp = &p; // 二级指针
作用:
-
在函数中修改传入的指针本身(例如动态内存分配:
int *p; func(&p);) -
管理指针数组(如命令行参数
char **argv)
内存模型:
text
pp → p → a (10)
2. 函数指针
定义:指向函数的指针,保存函数的入口地址。
声明:返回类型 (*ptr)(参数列表);
示例:
c
int add(int x, int y) { return x + y; }
int (*p)(int, int) = add; // p指向add函数
int result = p(3, 5); // 等效于add(3,5)
作用:
-
回调函数(如
qsort的比较函数) -
实现策略模式、状态机等
注意:int *p(int, int) 是返回指针的函数,不是函数指针。
3. 数组指针
定义:指向数组的指针,强调指向整个数组,而非单个元素。
声明:类型 (*ptr)[元素个数];
示例:
c
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr; // p指向包含5个int的数组
printf("%d", (*p)[2]); // 输出3
作用:
-
操作二维数组的行指针
-
传递固定长度的数组
区别:
-
int *p = arr;→ 指向首个元素,p+1指向下一个元素 -
int (*p)[5] = &arr;→ 指向整个数组,p+1跳过整个数组(5个int)
4. 指针数组
定义:一个数组,其中每个元素都是指针。
声明:类型 *数组名[元素个数];
示例:
c
int a=1, b=2, c=3;
int *arr[3] = {&a, &b, &c}; // 存放三个int指针
printf("%d", *arr[1]); // 输出2
作用:
-
存储字符串数组:
char *strs[] = {"hello", "world"}; -
构建二维结构的行索引
内存布局:
text
arr: [ ptr_to_a, ptr_to_b, ptr_to_c ]
综合辨析对比表
| 概念 | 声明示例 | 本质 | 常见用途 |
|---|---|---|---|
| 二级指针 | int **pp; | 指针的指针 | 修改指针本身、二维动态数组 |
| 函数指针 | int (*fp)(int); | 指向代码区的指针 | 回调、动态调用函数 |
| 数组指针 | int (*ap)[5]; | 指向数组整体 | 操作二维数组的行 |
| 指针数组 | int *pa[5]; | 存储指针的数组 | 字符串列表、多指针存储 |
易混淆点辨析
a) 数组指针 vs 指针数组
-
记忆技巧:先读后面两个字——“数组指针”是“指针”(指向数组),“指针数组”是“数组”(元素是指针)。
-
sizeof:
-
int (*ap)[5]→sizeof(ap)为指针大小(4/8字节),sizeof(*ap)为5*sizeof(int) -
int *pa[5]→sizeof(pa)为5*sizeof(int*)
-
b) 二级指针 vs 指针数组
-
二级指针常与指针数组配合使用:
char **argv可以指向char *argv[]的首地址。 -
但二级指针本身只是一个变量,而指针数组是一组连续的内存空间。
c) 函数指针的语法陷阱
-
int *f(int, int);// 函数,返回int* -
int (*f)(int, int);// 函数指针 -
可使用
typedef简化:typedef int (*Func)(int, int);
示例:综合应用
c
#include <stdio.h>
// 函数:加法
int add(int x, int y) { return x + y; }
int main() {
// 指针数组:存放两个数组的行地址
int row1[] = {1, 2};
int row2[] = {3, 4};
int *rows[2] = {row1, row2};
// 数组指针:指向一维数组(列数固定为2)
int (*p_row)[2] = &row1; // 指向row1整体
// 二级指针:指向rows指针数组的首元素
int **pp = rows;
// 函数指针:指向add函数
int (*fp)(int, int) = add;
// 使用二级指针访问二维数据
printf("%d\n", pp[1][0]); // 3
// 通过函数指针调用
printf("%d\n", fp(2, 3)); // 5
return 0;
}
总结
| 名称 | 核心要点 |
|---|---|
| 二级指针 | 解引用两次才能访问原始数据 |
| 函数指针 | 可像函数一样调用,常用于回调 |
| 数组指针 | 移动步长是整个数组大小,多用于二维数组的行 |
| 指针数组 | 元素都是指针,常用于存储多个地址(如字符串) |
理清这些概念的关键在于区分指针本身和指针指向的对象,并通过声明语法中的括号位置加以识别:
-
[]优先级高于*,所以int *p[5]先构成数组 → 指针数组 -
(*p)[5]用括号强制*先结合 → 数组指针 -
(*fp)(int)用括号结合*和函数参数 → 函数指针 -
**pp表示多级间接 → 二级指针
990

被折叠的 条评论
为什么被折叠?



