高级指针

(一)、二维数组与二级指针参数数组


   二维数组作参数:ide

        二维数组作参数与一维数组作参数同样,传递的都是首元素的地址,只不过二维数组的每一个元素又是一个一维数组 。函数

例:int arr[5][10];url

       这是一个5行10列的×××数组,能够将它当作一个只有5个元素的一维数组,只不过每一个元素又是一个大小为10的一维数组spa


fun(arr);咱们来分析一下当arr做为实参是,须要什么类型的形参来接受它???指针

       arr做为参数时,表明首元素地址,要接受这个地址必须是一个指针或者是一个数组,可是他的每一个元素的类型是int[10]。get


       因此咱们能够用一个指向类型为int [10]的数组指针来接受arr[5][10],即:int (*p)[10] 。    一样也能够用一个数组来接受arr,即:int arr1[][10],这里第二维的大小不能省略,在这里int arr1[][10] 也能够被解析成int (*arr1)[10];input


二级指针作参数:回调函数

例:char *p[5];it

        这是一个大小为5,每一个元素都是char *类型的数组,当他做为实参时,须要什么样类型的形参来接受他呢???


fun(p);       分析:既然p是一个数组,那么数组在做为实参时,实际上传递过去的是首元素的地址,可是p的每个元素都是一个char *类型,也是一个地址,因此形参的类型应该是char **。


总结:

spacer.gifwKiom1clqGqSbiKWAABFE00QjMY890.png

数组名只有在sizeof()和取&时才不发生降级,其他地方都表明首元素地址。


(二)、函数指针


函数指针: 是一个指向函数的指针

声明:  

      例:void (*p)();           首先p是一个指针,它指向一个返回值为空,参数为空的函数。

初始化:

       要明确,函数指针本质仍是一个指针,既然是指针,那么就必须给他进行初始化才能使用它,下面来看一看函数指针的初始化,定义一个返回值为空参数为空的函数:void fun()。

        p=fun;

        p=&fun;

       这两种初始化的方式都是正确的。由于函数名在被编译后其实就是一个地址,因此这两种方式本质上没有什么区别。

调用:

      p();  

    (*p)();

       这两种方式都是正确的。p里面存的fun的地址,而fun与&fun又是同样的。


例:分析一下(*(void (*) () ) 0 ) ()是个什么东东!!!

        首先,void (*) ();是一个返回值为空,参数为空的函数指针类型。

        void (*) () 0 ;   它的做用是把0强制类型转换成一个返回值为空,参数为空的函数指针。

        (*(void (*) () )0) ; 找到保存在0地址处的函数。

       (*(void (*) () ) 0 ) (); 对这个函数进行调用。


用途:

       一、回调函数:用户将一个函数指针做为参数传递给其余函数,后者再“回调”用户的函数,这种方式称为“回调函数”,若是想要你编写的函数在不一样的时候执行不一样的工做,这时就可使用回调函数。回调函数也算是c语言里面为数很少的一个高大上的东西。

        二、转换表:转换表本质上是一个函数指针数组,说白了就是一个数组,只不过数组里面存放的所有都是函数指针。

例:实现一个计算器

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int Add(int a, int b)
{
  return a + b;
}
int Sub(int a, int b)
{
 return a - b;
}
int Mul(int a, int b)
{
 return a *b;
}
int Div(int a, int b)
{
 assert(b != 0);
 return a / b;
}
int operator(int (*fun)(int,int))   //回调函数
{
  int a = 0;
  int b = 0;
  printf( "请输入操做数:" );
  scanf( "%d%d", &a, &b);
  return (*fun )(a,b);              
}
int main()
{
  printf( "*************************************\n" );
  printf( "*0.exit           1.Add****\n" );
  printf( "*2.Sub           3.Mul****\n" );
  printf( "*4.Div           *********\n" );
  int(*fun[5])(int ,int);         //转换表
  fun[1] = Add;
  fun[2] = Sub;
  fun[3] = Mul;
  fun[4] = Div;
  int input = 1;
  while (input)
  {
    printf( "请选择> " );
    scanf( "%d", &input);
    if (input<0 || input>4)
    {                                                               printf( "选择无效\n" );
    }
    else if (input == 0)
    {                                                    break;
    }
    else
    {                                                           int ret = operator(fun[input]);
      printf( "%d\n", ret);
    }
  }
   system( "pause");
   return 0;
}



在这个计算器程序中,就使用到了转换表fun[]。fun[]里面存放了加减乘除四个函数,根据input的不一样,fun[input]调用不一样的函数。这种方式与switch() case的功能比较类似,不过转换表比switch()case更简单。


函数指针数组:

       函数指针数组是一个指针数组,也就是一个数组,只不过里面存放的全都是函数指针。

声明:例: char* (*p[5])(int,int);

       p与[5]先结合成一个数组,因此这是一个大小为5的数组,数组元素的类型是一个函数指针,这个函数指针指向一个返回值为char *,有两个参数,且参数类型为int,int的数组。

能够这样理解:char * (*)(int,int)   p[5];        其中char*(*)(int int)是p[5]的类型。


函数指针数组的指针:

       函数指针数组的指针是一个数组指针,本质上是一个指针,只不过指向的是一个存放函数指针的数组。

声明:例:char *(*(*p)[5])(int,int);

        *与p先结合成一个指针,因此p是一个指针,指针所指向的是一个大小为5的数组,这个数组存放的是函数指针,这些函数指针所指向的类型是返回值为char *,有两个int型参数的函数。

        能够这样理解: char *(*[5])(int,int) *p;    p是一个指针,类型是char*(*[5])(int,int).


总结:指针数组,是一个数组,里面存放的是指针。

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

函数指针数组,是一个数组,里面存放的是函数指针。

函数指针数组指针,是一个指针,指向一个存放函数指针的数组。

其实规律很简单,强调的都是最后两个字,最后两个字是什么他就是什么,而前面的字就是他的类型。

相关文章
相关标签/搜索