在指针中,还有指针数组、数组指针、函数指针、函数指针数组、函数指针的数组的指针这样一些高级指针,所以我们需要了解并掌握它们的含义和用法:
我们得先知道, 指针是和数组无关的:
1.指针是一种类型;数组也是一种类型;
2.指针可作左值,数组名却不可以;
一、指针数组
int *arr1[10];
char *arr2[4];
char **arr3[5];
如上,便是指针数组,
那么指针数组是数组还是指针?
#是数组,
这取决于它的优先级,因为[]的优先级高于*,所以他先和[]结合,因此首先它是数组,又因为前面有*,所以是指针数组;
二、数组指针
同理,数组指针便是指针,
如:int (*p)[10]
由于P先和*结合,所以p是一个指针变量,且指向一个大小为10个整形的数组;
注意:由于[]的优先级高于*,所以需要加上()来保证p先和*结合。
数组指针的应用:如下的程序可以实现存储数组的地址:
int arr[10] = { 0 };
int(*p2)[10] = &arr;
三、函数指针
首先看一段代码:
#include<stdio.h>
void test()
{
printf("hello,world!\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
system("pause");
return 0;
}
再来看看结果,
结果是一样的,所以:
函数的地址通常由函数名表示(函数的地址为第一条语句的地址),
我们想要存储函数的地址,则用
void(*pfun1)();
注:pfun1先和*结合,说明pfun1是指针,指针指向一个函数,指向的函数无参数,返回值类型为void。
扩展:我们来看两个有趣的代码。
//代码一
(*(void(*)())0)();
分析:首先我们看到0前面加了括号,则说明这是对0进行强转,而括号里面很明显是一个函数指针,所以是将0强转为函数指针,又因为函数指针是地址,所以0是4个字节的地址(返回值为void,参数为空的函数的地址),然后再进行解引用,就是函数调用。
//代码二
void(*signal(int, void(*)(int)))(int);
分析:
由于优先级的原因,所以signal先和括号结合,前面是*,可知signal是函数名,且是一个参数为int,另一个参数为函数指针的函数,再进行函数调用。
四、函数指针数组
函数指针数组就是把函数的地址存到一个数组中
如:
int (*parr1[10])();
函数指针数组的应用:
使用函数指针实现转移表
我们直接来看代码,
#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)
int my_add(int x, int y)
{
return x + y;
}
int my_sub(int x, int y)
{
return x - y;
}
int my_mul(int x, int y)
{
return x*y;
}
int my_div(int x, int y)
{
if (y)
{
return x / y;
}
else
{
printf("enter error!\n");
return -1;
}
}
void menu()
{
printf("#################################\n");
printf("#### 1:add 2:sub ####\n");
printf("#### 3:mul 4.div ####\n");
printf("#### 0:exit####\n");
printf("#################################\n");
printf("please select:\n");
}
int main()
{
int x, y;
int select = 1;
int ret;
int(*p[5])(int x, int y) = { 0, my_add, my_sub, my_mul, my_div };
while (select)
{
menu();
scanf("%d", &select);
if (select == 0)
{
break;
}
else if (select >= 1 && select <= 4)
{
printf("please enter<x,y>\n");
scanf("%d %d", &x, &y);
ret = (*p[select])(x, y);
}
else
{
printf("enter error!\n");
}
printf("ret=%d\n", ret);
}
system("pause");
return 0;
}
这样实现转移表则可以使程序比较简洁。
五、指向函数指针数组的指针
它是一个指针,可以指向一个元素都是函数指针的数组。
如:
void(*(*ppfunArr)[10])(const char *) = &pfunArr;
ppfunArr是一个指向函数指针数组pfunArr的指针。