深入理解指针之高级指针

在指针中,还有指针数组、数组指针、函数指针、函数指针数组、函数指针的数组的指针这样一些高级指针,所以我们需要了解并掌握它们的含义和用法:

我们得先知道,  指针是和数组无关的:

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的指针。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值