指针数组、数组指针和函数指针

1.指针数组

指针数组是数组,其内部元素是指针。

如:int *arr[10];  数组arr中存放的是int*型的指针变量


2.数组指针

数组指针是指针,它指向一个数组。

如:int (*p)[10];  指针p指向一个有10个整型元素的数组。


3.如何区分指针数组和数组指针?

在这里,要考虑符号之间的优先级问题,因为优先级()>[]>*,所以在int *p[10]中,p先和[]结合,构成数组的定义,数组名是p,int*用来修饰数组的内容,所以数组里面的元素都是指向整型的指针类型。而在int (*p)[10]中,p先和*结合,构成指针的定义,指针变量名是p,int修饰的是数组的内容,即数组的每个元素,数组在这里并没有名字,是个匿名数组。

4.函数指针

我们知道变量是有地址的,同样,我们编写函数,函数的代码储存在内存的代码块中,也是有地址的。我们通常把函数的地址也叫做函数的入口地址,也是函数第一条语句的地址。观察这样一段代码和它的结果:


可以看到 函数名和&函数名输出的地址结果是相同的。因此,函数的入口地址是函数名或&函数名。

既然函数有指针,那么我们用什么来存储它较好呢?

A.void (*pfun1)();

B.void *pfun2();

在这里又涉及到优先级问题,因为()>*,所以在A中,pfun1先与*结合,说明pfun1是一个指针,而void()是用来修饰指针的,说明pfun1指向一个函数,这个函数是无返回值的。A用来存储函数指针是合适的。而在B中,pfun2先与()结合,说明pfun2是一个函数,void*用来修饰这个函数,说明pfun2函数的返回值为void*型。所以B实际上是对函数的声明,不能表示函数指针。

下面有两个有趣的代码:

(1)(*(void ( * )( ) ) 0)( );

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

读者可能会对(1)中的0感到很奇怪,其实,这儿恰恰是突破点,0是一个数,也可以看作一个变量的值。0前面的(void ( * )( ) )就是对0进行强制类型转换。再分析它所代表的类型,根据上面的分析,很容易知道这是一个函数指针类型。(void ( * )( ) ) 0就是把0强制转换为一个函数指针,再对这个函数指针进行解引用就得到了函数名,所以(*(void ( * )( ) ) 0)就是函数名,这个函数无返回值。函数名后面跟“()”就是调用该函数。所以(1)是对函数的调用。整个过程中,函数名的访问属于匿名访问。

(2)大体上看,可以从优先级入手,因为()>*,signal先和()结合,“()”里面有两个参数,一个是int型,一个是void(*)(int)型,就是一个函数指针类型。signal(int ,void (*)(int))这部分看上去是对函数的调用。void(*)()是用来修饰函数的,说明这个函数的返回值是函数指针类型。这不恰巧是我们常见的函数声明吗?

5函数指针数组

把函数的指针存储到一个数组中,这个数组就是函数指针数组。如何定义函数指针数组?

辨析:A.int (*parr1[10])();    B.int *parr2[10]();     C.int (*)()parr33[10];

这里我们还要用到优先级:()>[]>*.A中,parr1先和[]结合,说明parr1是一个数组,int(*)()用来修饰这个数组,说明数组里面的元素是函数指针类型的,这些函数的返回类型都是整型。A正确。  B的parr2也先和[]结合,说明parr2是一个数组,int*()修饰parr2,如果是int*parr2();,则代表函数的声明,但是在这里,parr2是一个数组,我们也从来没有见过这样的形式,所以它什么也不是。C也什么都不是。

下面一段代码是对函数指针数组的应用,相信读者会更加理解函数指针数组。



5.指向函数指针数组的指针

指向函数指针数组的指针是一个指针,这个指针指向数组,数组里面的元素是函数指针。

如何定义?

void test(const char *str)//定义一个函数,函数的参数是const char*型的

{

    printf("%s\n",str);//函数的作用是输出一个字符串常量

}

int main()

{

   void (*pfun)(const char *)=test;//定义了一个函数指针,指向test函数

   void (*pfunArr[5])(const char *str);//声明了一个函数指针数组,共有5个元素,数组里的每个元素都是函数指针,函数无返                                                               回值,函数的参数是const char*型。

   pfunArr[0]=test;//给这个函数指针数组的第一个元素赋值,让它指向test函数。

   void (*(*ppfunArr)[10])(const char*)=&pfunArr;//定义一个指向函数指针数组的指针,这个指针指向具有10个元素的数组,                                                                                  这10个元素都是函数指针。并且初始化为pfunArr的地址。 

   return 0;


总结:区分指针数组、数组指针、函数指针、函数指针数组和指向函数指针数组的指针的重要依据是优先级和结合性,时刻谨记()>[]>*.然后除这部分外,剩下的都是用来修饰指针或数组的。



猜你喜欢

转载自blog.csdn.net/smell201611010513/article/details/80143632