大家好,我是网域小星球。
前面我们学过了指针基础、指针与数组的关系。但在进阶语法、笔试面试和实际项目里,经常会遇到三个长得很像、含义却完全不同的概念,很多人学到这里直接混淆:指针数组、数组指针、函数指针。
它们长得像、用法不同、坑点密集。本篇用最清晰的对比 + 案例,一次性讲透,全程 VS2022 可直接运行。
目录
[1. 定义](#1. 定义)
[2. 用途:指向二维数组](#2. 用途:指向二维数组)
[1. 定义](#1. 定义)
[2. 最常用场景:多字符串管理](#2. 最常用场景:多字符串管理)
[五、数组指针 vs 指针数组 对比表](#五、数组指针 vs 指针数组 对比表)
[1. 什么是函数指针?](#1. 什么是函数指针?)
[2. 定义格式](#2. 定义格式)
[3. 最简单使用示例](#3. 最简单使用示例)
[4. 实战用途:菜单跳转 / 回调函数](#4. 实战用途:菜单跳转 / 回调函数)
一、本章学习目标
- 分清 数组指针 与 指针数组,不再混淆
- 掌握二维数组与数组指针的关系
- 理解 函数指针 是什么、怎么定义、怎么用
- 学会用函数指针实现回调、简易菜单跳转
- 搞定 C 语言指针进阶高频考点
二、先破局:一句话分清两个易混概念
- 数组指针 :本质是指针,指向一个数组
- 指针数组 :本质是数组,里面每个元素都是指针
口诀:后面两个字是什么,它就是什么。
三、数组指针(指向数组的指针)
1. 定义
cpp
类型 (*指针名)[数组长度];
例如:指向 5 个 int 的数组
cpp
int (*p)[5];
()优先级很高- 先说明
p是指针 - 再说明它指向一个长度为 5 的 int 数组
2. 用途:指向二维数组
二维数组名,本质就是数组指针。
cpp
int arr[2][3] = { {1,2,3}, {4,5,6} };
int (*p)[3] = arr;
访问:
cpp
// 第0行第1列
printf("%d", (*p)[1] );
完整示例
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int arr[2][3] = { {1,2,3}, {4,5,6} };
int (*p)[3] = arr;
printf("%d\n", (*p)[0]); // 1
printf("%d\n", (*(p+1))[0]); // 4
return 0;
}
四、指针数组(存放指针的数组)
1. 定义
cpp
类型 *数组名[长度];
例如:长度为 3 的指针数组
cpp
int *arr[3];
[]优先级比*高- 先说明
arr是数组 - 每个元素是
int*类型指针
2. 最常用场景:多字符串管理
cpp
char *strArr[] = {
"Chinese",
"Math",
"English",
"Programming"
};
完整示例
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
char *courses[] = {
"语文", "数学", "英语", "C语言"
};
for (int i = 0; i < 4; i++)
{
printf("%s\n", courses[i]);
}
return 0;
}
五、数组指针 vs 指针数组 对比表
| 写法 | 名字 | 本质 | 记忆 |
|---|---|---|---|
int (*p)[5] |
数组指针 | 指针,指向数组 | 括号包住,是指针 |
int *p[5] |
指针数组 | 数组,存指针 | 无括号,是数组 |
一句话区分:有括号是指针,没括号是数组。
六、函数指针(指向函数的指针)
1. 什么是函数指针?
函数在内存中也有地址。函数指针就是存放函数地址的指针。
2. 定义格式
cpp
返回值类型 (*指针名)(参数列表);
示例:指向参数为 (int,int)、返回 int 的函数
cpp
int (*fp)(int, int);
3. 最简单使用示例
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
// 定义函数指针
int (*fp)(int, int) = add;
// 两种调用方式等价
printf("%d\n", add(2, 3));
printf("%d\n", fp(2, 3));
return 0;
}
4. 实战用途:菜单跳转 / 回调函数
cpp
void show() { printf("显示信息\n"); }
void add() { printf("添加数据\n"); }
void exitSys() { printf("退出系统\n"); }
int main()
{
// 函数指针数组
void (*funcArr[])(void) = { exitSys, show, add };
int choice;
scanf("%d", &choice);
funcArr; // 直接调用对应函数
}
这是做菜单框架、状态机、插件化的基础。
七、高频易错点
- 把
int (*p)[5]写成int *p[5],含义完全相反 - 函数指针少写括号
int *fp(int,int)变成函数声明 - 数组指针越界,特别是二维数组使用时
- 函数指针类型不匹配(返回值 / 参数对不上)
- 函数指针赋值时加了
&或漏写&(其实都可以,但要规范)
八、本章核心总结
- 数组指针 :
int (*p)[n]→ 指针,指向数组 - 指针数组 :
int *p[n]→ 数组,存指针 - 口诀:括号是指针,无括号是数组
- 函数指针 :
int (*fp)(int,int)指向函数地址 - 函数指针可做回调、菜单跳转、简化分支逻辑
- 这一章是 C 语言进阶分水岭,搞懂才算真正入门指针
下期预告
下一篇学习 typedef,给复杂类型起别名,简化数组指针、函数指针等复杂写法,让代码更简洁易读。