对于指针数组,数组指针,函数指针,函数指针数组,指向函数指针数组的指针 的理解

  在开始理解之前,先摆上我最喜欢的一句话:在《C语言深度剖析》中:数组就是数组,指针就是指针,它们是完全不同的两码事!他们之间没有任何关系,只是经常穿着相似的衣服来迷惑你罢了。


对于指针数组和数组指针:《C语言深度剖析》这样解释:

指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身 决定。它是储存指针的数组的简称。

数组指针:首先它是一个指针,它指向一个数组。在 32 位系统下永远是占 4 个字节, 至于它指向的数组占多少字节,不知道。它是指向数组的指针的简称。

 
  而我是这样理解的:(个人觉得这样比较好理解)在语文中,我们学过定语,比如我的书,强调的是书,而“我的”是定语来修饰“书”。同样,指针数组:它是一个数组,就如同“书”,而指针,就像“我的”一样。既然是数组,其实就和我们平常所学的数组没有什么区别,但是,重点就在他们的元素类型,指针数组,这个数组的元素很强大,它存储的是一个地址。数组指针,对,它是一个指针,那么它指向谁呢?我们注意到前面的定语是数组,说明它指向的是一个数组。它还是我们的那个指针,只不过,它也变得更强大了,它竟然背着我们偷偷指向了一个数组(后面它会更强大,指向函数,甚至还指向一个数组,这个数组它里面的元素又是一个指针,又指向一个函数)



来,我们来看一下代码:

A)int *p1[10];

B)int (*p2)[10];



在这里我们首先得了解到优先级的问题,“[]”的优先级比“*”要高。所以p1“[]”结合,构成一个数组。我们之前了解到,数组元素的类型就是,去掉数组名和“[]”,剩下的就是数组元素的类型,那么A)中数组元素的类型就变成了int *,没错,就是指针。而对于B),()的优先级比“[]”高,那么,p2就与“*”结合构成一个指针。对于指针来说,比如 int *p我们会说,p指向的内容的类型是整型,同样的去掉“*p"就是p所指向的内容,”int [10]“,说明它是指向的是一个的数组,数组元素的类型都是整型。

既然数组和指针不同,能体现在哪?

主要在p+1;

看以下代码:

int main()
{
	int a[3][4];
	
	return 0;
}


如果我们把上面的这个数组赋值给一个指针,为int *p)[4],这里p是一个指针,它指向一个有三个元素的数组,那么p+1会跳过整个数组,也就是指向了二维数组的第二行,也称为行指针。

而如果是这样呢:int *p[3],这是一个数组,它有三个元素,它里面的元素是指针变量,p+1,执行后会指向的是下一个元素。也就是(arr+1).


总结:数组指针是一个指针变量,似乎是C语言里专门用来只下过二维数组的,它占有内存中中一个指针的存储空间。指针数组是多个指针变量,以数组的形式在内存当中,以数组的形式存在内存当中,占有多个指针的存储空间


在这个链接中点击打开链接上面的很多内容都是在这里学习的。

到了激动人心的时刻:

该谈论函数指针,函数指针数组,指向函数指针数组的指针这三个内容了,别着急,慢慢来。

我们先来看一个准则:出处:点击打开链接

在上面的连接中有讲到:右左法则。

 

右左法则:首先从最里面的圆括号(未定义的标识符)看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明。

 


在《C语言深度剖析》中,对这三个概念是这样解释的:

函数指针:顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数

 


函数指针数组char* (*pf[3])(char* p);

这是定义一个函数指针数组。它是一个数组,数组名为 pf,数组内存储了 3 个指向函数的 指针。这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函 数。这念起来似乎有点拗口。不过不要紧,关键是你明白这是一个指针数组,是数组。


 

指向函数指针数组的指针(函数指针数组的指针):char* (*(*pf)[3])(char* p);

注意,这里的 pf 和上一节的 pf 就完全是两码事了。上一节的 pf 并非指针,而是一个数组名; 这里的 pf 确实是实实在在的指针。这个指针指向一个包含了 3 个元素的数组;这个数字里 面存的是指向函数的指针;

 

 


面的两个例子,用右左法则分析如下:

char* (*pf[3])(char* p),首先从最里面的圆括号(未定义的标识符)看起,即(*pf[3]),前面我们说过”[]”的优先级高于“*”,所以,pf和“[]”构成了一个数组。数组有三个元素,再看pf左边,“*,表示数组元素的类型是指针。(*pf[3])是一个“()”,说明数组元素指向函数,是函数指针,函数的参数类型呢是(char* p),返回值类型是char*。总结起来就是一个数组有三个元素是指针类型,指向函数。

 

 

char* (*(*pf)[3])(char* p),先未定义的标识符(*pf),由于“*”和pf结合构成一个指针,再看(*pf)右边是一个数组,表明这个指针指向有三个元素的数组,(*pf)左边“*”表明数组的元素类型是指针。再跳出圆括号,来到(*(*pf)[3])右边,看到的是一个“()”,表明这个数组指向的是一个函数,而这个函数的返回值是char*,参数类型是(char* p)

 


具体代码:

 

//函数指针数组
#include <stdio.h>
#include <string.h>
char* fun1(char* p)
{
	printf("%s\n", p);
	return p;
}
char* fun2(char* p)
{
	printf("%s\n", p);
	return p;
}
char* fun3(char* p)
{
	printf("%s\n", p);
	return p;
}
int main()
{
	char* (*pf[3])(char* p);
	pf[0] = fun1; // 可以直接用函数名
	pf[1] = &fun2; // 可以用函数名加上取地址符
	pf[2] = &fun3;
	pf[0]("fun1");
	pf[0]("fun2");
	pf[0]("fun3");
	return 0;
}
//函数指针数组的指针
#include <stdio.h>
#include <string.h>
char* fun1(char* p)
{
	printf("%s\n", p);
	return p;
}
char* fun2(char* p)
{
	printf("%s\n", p);
	return p;
}
char* fun3(char* p)
{
	printf("%s\n", p);
	return p;
}
int main()
{
	char* (*a[3])(char* p);
	char* (*(*pf)[3])(char* p);
	pf = &a;
	a[0] = fun1;
	a[1] = &fun2;
	a[2] = &fun3;
	pf[0][0]("fun1");
	pf[0][1]("fun2");
	pf[0][2]("fun3");
	return 0;
}





在上面提供的链接中对于右左法则的使用如果很熟练的话,那么就对这些理解的很清楚了。

 

(*(void(*) ())0)()这是《C语言深度剖析》中一个很经典的例子,可以用来锻炼下:

 

解释如下:还是用右左法则,先看到(*)是一个指针,(*)的右边是“()”,表明这是一个函数,再看(*)左边表明函数的返回值类型为void,跳出这个圆括号,来到(void(*) ())的右边是一个0,很多人都卡在这边。有一个小知识点:如何声明一个给定类型的标量,那么该类型的类型转换就很容易得到了:只需要把声明中的变量名 和声明末尾的分号去掉,再将剩余的部分用一个括号整个“封装”起来即可。例如:因为下面的声明:
float *h)();
表示h是一个指向返回值为浮点类型的函数的指针,因此,
float*)())
表示一个“指向返回值为浮点类型的函数的指针”的类型转换。同理(void(*) ())也表示强制类型转换,将0强制类型转换为一个函数指针。0 是一个地址,也就是说一 个函数存在首地址为 0 的一段区域内。再看左边,(void(*) ())是“*”,表示对这个函数指针进行解引用,(*(void(*) ())0)右边的“()”表示对这个函数解引用之后进行调用。

 

再来看这个代码:

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

还是利用右左法则:先看未定义的标识符,

下面借助《C语言深度剖析》代码来具体了解:(*)表示是一个指针,它的右边是一个”()”,表示这是一个函数指针,它的参数是int,返回值是void。再看void(*)(int)左边,前面有“,”表明是同等级别的,说明int , void(*)(int)都是参数,是哪个函数的参数呢?l(int ,void(*)(int)外面的signa是函数名,*表示这个函数又是一个函数指针。跳出这个(*signal(int , void(*)(int))),来到右边,又是“(),表明又是一个函数,函数的参数类型是int类型,返回值是void。总结一下:有一个函数指针,它的参数里面又嵌套了一个函数指针。

 

 两个程序的运行结果图:

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/miqingzhiwen/article/details/80088260