本篇的主要内为:
- 指针数组
- 数组指针
- 函数指针
- 函数指针数组
- 指向函数指针数组的指针
指针数组
指针数组,说白了就是一个数组,数组成员的数据类型为指针。
举个栗子:
#include<stdio.h>
int main()
{
int i = 0;
char *p[3] = {"Hello", "World", "!"};
for (i = 0; i < 3; i++)
{
printf("%s ", p[i]);
}
printf("\n");
return 0;
}
p是一个数组,这个数组的每个成员的类型都为指针。p[0]中存储的是“Hello”的首地址,p[1]中存储的是“world”的首地址,p[2]中存储的是“!”的首地址。
数组指针
数组指针,顾名思义就是指针,不过指针的类型却是数组。
举个栗子:
#include<stdio.h>
int main()
{
int a[10] = {0};
return 0;
}
我们知道a是一个数组,它的成员的数据类型为int,那么如果我们对进行 &a 操作。那么该用什么类型的变量来存储呢?
这就用到了数组指针的知识。
//数组指针的定义
int (*pa)[10] = &a;
//数组指针的理解方式:
//1.()的优先级高于[] 因此,p 先和 * 组合,表明p是一个指针变量。
//2.然后再与[]组合,表明它指向一个长度为10的数组,而数组大的每个成员的类型都为int。
数组指针的使用:
#include<stdio.h>
int main()
{
int a[10] = {0};
int (*pa)[10] = &a;
printf("a = %p\n", a);
printf("&a = %p\n", &a);
printf("pa = %p\n", pa);
printf("a + 1 = %p\n", a + 1);
printf("(&a) + 1 = %p\n", (&a) + 1);
printf("pa + 1 = %p\n", pa + 1);
return 0;
}
运行结果:
通过上面的运行结果,我们可以看到,对数组指针 pa + 1
地址变化为 40
个。地址的变化为整个数组的大小。
数组指针在二维数组中的应用:
#include<stdio.h>
int main()
{
int arr[3][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
Print(arr);
return 0;
}
//Print()函数的参数都可以写成什么呢?
void Print(int a[3][5], int i, int j)
void Print(int a[][5], int i, int j)
void Print(int (*a)[5], int i, int j)
我们分析第三种情况,之前说过,我们可以把二维数组模拟成一维数组,那么二维数组的首元素就是一个数组,所以我们可以用一个数组指针来接受它,而这个一维数组的元素又有5个,所以可以创建形参为(*a)[5]
。
函数指针
函数指针是指向函数的指针变量。
首先看一段代码:
#include<stdio.h>
void fun()
{
printf("fun\n");
}
int main()
{
fun();
printf("fun() = %p\n", fun);
printf("&fun() = %p\n", &fun);
return 0;
}
运行结果:
下面这两个地址是fun函数的地址,那我们要如何将地址保存起来呢。
void (*pfun) ();
//pfun 先和 * 结合,表示是指针。
//再与()结合,表明它指向函数,函数没有参数,返回类型为void。
函数指针的应用:
void Add(int a, int b)
{
printf("%d\n", a + b);
}
int main()
{
void(*p) (int, int);
p = Add;
(*p)(5, 3);
return 0;
}
// 如果我们去掉解引用操作符呢? p(5, 3)
运行结果:
我们可以看到,即使不对函数指针进行解引用,我们也可以调用函数,因此,函数的调用,只需要入口地址即可。
函数指针数组
函数指针数组,是用来存放指针类型为函数指针的数组。
#include <stdio.h>
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a - b;
}
int Div(int a, int b)
{
return a - b;
}
int main()
{
int i = 0;
int(*p[4])(int, int) = {Add, Sub, Mul, Div};
for (i = 0; i < 4; i++)
{
printf("%d\n", p[i](6, 2));
}
return 0;
}
// int(*p[4])(int, int) = {Add, Sub, Mul, Div};
// p 首先和 [] 组合,表示它是一个数组。
// 数组成员的类型是 参数为两个int型的 ,返回类型为 int 的函数的指针。
运行结果:
指向函数指针数组的指针
上面说到了函数指针数组,那么对该数组取地址后,应该用什么变量存储它呢?这就用到了指向函数数组的指针。
举个栗子:
//上面创建了一个函数指针数组,它的四个成员分别指向四个函数 Add, Sub, Mul, Div
//现在,要用变量将 &p 存储起来。
int(*p[4])(int, int) = {Add, Sub, Mul, Div};
//pp是一个指向函数指针数组的指针
int(*(*pp)[4])(int, int) = &p;
运行结果: