天天看點

進階指針

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

   二維數組做參數:

        二維數組做參數與一維數組做參數一樣,傳遞的都是首元素的位址,隻不過二維數組的每個元素又是一個一維數組 。

例:int arr[5][10];

       這是一個5行10列的×××數組,可以将它看成一個隻有5個元素的一維數組,隻不過每個元素又是一個大小為10的一維數組。

fun(arr);我們來分析一下當arr作為實參是,需要什麼類型的形參來接受它???

       arr作為參數時,代表首元素位址,要接受這個位址必須是一個指針或者是一個數組,但是他的每個元素的類型是int[10]。

       是以我們可以用一個指向類型為int [10]的數組指針來接受arr[5][10],即:int (*p)[10] 。    同樣也可以用一個數組來接受arr,即:int arr1[][10],這裡第二維的大小不能省略,在這裡int arr1[][10] 也可以被解析成int (*arr1)[10];

二級指針做參數:

例:char *p[5];

        這是一個大小為5,每個元素都是char *類型的數組,當他作為實參時,需要什麼樣類型的形參來接受他呢???

fun(p);       分析:既然p是一個數組,那麼數組在作為實參時,實際上傳遞過去的是首元素的位址,但是p的每一個元素都是一個char *類型,也是一個位址,是以形參的類型應該是char **。

總結:

進階指針
進階指針

數組名隻有在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 ) (); 對這個函數進行調用。

用途:

       1、回調函數:使用者将一個函數指針作為參數傳遞給其他函數,後者再“回調”使用者的函數,這種方式稱為“回調函數”,如果想要你編寫的函數在不同的時候執行不同的工作,這時就可以使用回調函數。回調函數也算是c語言裡面為數不多的一個高大上的東西。

        2、轉換表:轉換表本質上是一個函數指針數組,說白了就是一個數組,隻不過數組裡面存放的全部都是函數指針。

例:實作一個電腦

#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).

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

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

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

上一篇: 進階算法
下一篇: 無悲無喜

繼續閱讀