指针的进阶(后半)

文章目录

  • 函数指针
  • 函数指针数组
  • 指向函数指针数组的指针
  • 结束语

函数指针

先看一段代码

int Add(int x, int y)
{
     
	return x + y;
}

int main()
{
     

	printf("%p\n", &Add);
	printf("%p\n", Add);
	return 0;
}

输出结果如下
指针的进阶(后半)_第1张图片
从上我们可以了解到其实函数名就是一个地址,所以用不用&的结果是一样的,但是地址该如何保存下来呢?
这就涉及到函数指针了,看代码

void test()
{
     
    printf("hehe\n");
}
下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();

pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无 参数,返回值类型为void。

实际例子如下:

int Add(int x, int y)
{
     
	return x + y;
}

int main()
{
     
	int (*pf)(int, int) = Add;
	//pf是一个函数指针,该指针指向的是一个函数,指向的函数有两个整形参数,返回值类型为int。
	printf("%d\n", (*pf)(1, 2));
	printf("%d\n", pf(1, 2));
	return 0;
}

输出结果如下
指针的进阶(后半)_第2张图片
上面说到,既然函数就是用地址来实现功能的,那么我们解引用和不解引用产生的结果当然是一样的。

我们接着来读读下面这个两个代码

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);
//代码1
(*(void (*)())0)();

我们先将(*(void (*)())0)()进行拆分
		(*(            )0)()
		  	 void(*)()
void(*)()不就是函数指针嘛,该指针指向一个函数,无参数,返回类型为void
那么void(*)()0?是什么意思呢
我们先来了解这个玩意儿(float*)p,p是一个指针,那么这个的意思就是把p强制类型转化为(float*)
回到void(*)()0,它的意思也很简单,就是把0这个整形强制转化为函数指针类型,地址为0。
那么解引用他就是找到这个0地址的内容,是一个函数,无参数,返回类型为void。
即为(*(void (*)())0)()

示例如下

int test()
{
     
	printf("QQHSJ\n");
	return 0;
}

int main()
{
     
	test();
	printf("%p\n", test);
	(*(int(*)())test)();
	return 0;
}

输出结果如下
指针的进阶(后半)_第3张图片

//代码2
void (*signal(int, void(*)(int)))(int);

它实际上就是一个函数声明,跟代码1一样我们来进行拆分
void(*                             )(int);
		signal(int, void(*)(int))
我们先看void(*p)(int),p是一个函数指针,它指向一个函数,参数为int,返回值类型为void。
一般来说我们通常的函数声明是这样的
int Add(int, int);
所以跟上述几乎代码2几乎是一样的,如果实在看不明白,我们就用一种别扭的方式理解,当然了这样的写法在编译器上面是无法通过的。
void(*)(int) signal(int, void(*)(int));int Add(int, int);
对比来看,形式完全是一模一样,所以它完完全全就是一个函数声明。只是返回类型是函数指针类型
就好比这个
int* BALABALA(int,int);,返回类型是整形指针类型。

但是void(*)(int) signal(int, void(*)(int));这种形式是可以实现的,但是需要用到typedef
如下

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

函数指针数组

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组, 比如:

int *arr[10];
//数组的每个元素是int*

那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?

int (*parr1[10])();
parr1 先和 [] 结合,说明parr1是数组,数组的内容是什么呢? 是 int (*)() 类型的函数指针。
如果觉得还不明确,用typedef替换

typedef int(* pfun_int)();
pfun_int parr1[10];

这样是不是清楚多了。

具体应用如下,加减乘除的计算代码

int Add(int x, int y)
{
     
	return x + y;
}

int Sub(int x, int y)
{
     
	return x - y;
}

int Mul(int x, int y)
{
     
	return x * y;
}

int Div(int x, int y)
{
     
	return x / y;
}

int main()
{
     
	int x, y;
	int input = 1;
	int ret = 0;
	int(*p[5])(int x, int y) = {
     0, Add, Sub, Mul, Div }; //转移表
	while (input)
	{
     
		printf("**************************\n");
		printf("**1:add************2:sub**\n");
		printf("**3:mul************4:div**\n");
		printf("**************************\n");
		printf("请选择:");
		scanf("%d", &input);
		if ((input <= 4 && input >= 1))
		{
     
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = (*p[input])(x, y);
		}
		else
			printf("输入有误\n");
		printf("ret = %d\n", ret);
	}
	return 0;
}

指向函数指针数组的指针

真是越走越远啊,难度确实蛮大的,大家好好学吧。柒柒没办法讲清楚的话,还望大家多抽点时间去看看书或者视频。

指向函数指针数组的指针是一个指针指针指向一个数组 ,数组的元素都是函数指针 ;

看代码

void test(const char* str)
{
     
    printf("%s\n", str);
}
int main()
{
     
    //函数指针pfun
    void (*Pfun)(const char*) = test;
    //函数指针的数组PfunArr
    void (*PfunArr[5])(const char*);
    pfunArr[0] = test;
    //指向函数指针数组PfunArr的指针PPfunArr
    void (*(*PPfunArr)[5])(const char*) = &PfunArr;
    return 0;
}

大家可能对第三个抱有非常大的疑问,解释如下

其实我们依旧可以用typedef的方式替换,从而理解“指向   函数指针数组   的   指针”

typedef void(*Void_Char)(const char*)
Void_Char PfunArr[5]

Void_Char PfunArr[5]它的意思就是PfunArr是一个数组,它的类型为Void_Char。
我们再回忆一下数组指针是怎么定义的

int arr[5] = {
      0 };
int (*p)[5] = &arr

那么要实现指针指向这个数组是不是变得异常简单了,即为
Void_Char *PPfunArr[5] = &PfunArr;
这样看是不是清楚很多了,我们再将它展开不就得到了void (*(*PPfunArr)[5])(const char*) = &PfunArr;

结束语

关于这一部分,可能还要小小的地方没有继续扩展,即回调函数指针和数组的解析

回调函数,我会专门详细的写一段代码,配上注释的情况下供小伙伴们阅读。

指针和数组的解析,部分代码如下,大家可以想想它输出的结果如何?


int a[] = {
     1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

欢迎大家共同探讨,如有什么不对的地方也请大家指出哦~

你可能感兴趣的:(c语言)