高級指針

(一)、二維數組與二級指針參數數組


   二維數組作參數: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).


總結:指針數組,是一個數組,裏面存放的是指針。

數組指針,是一個指針,指向一個數組的指針。

函數指針數組,是一個數組,裏面存放的是函數指針。

函數指針數組指針,是一個指針,指向一個存放函數指針的數組。

其實規律很簡單,強調的都是最後兩個字,最後兩個字是什麼他就是什麼,而前面的字就是他的類型。

相關文章
相關標籤/搜索