1. 程式人生 > >複雜指標宣告具體例項

複雜指標宣告具體例項

左右宣告法則:

首先從最裡面的圓括號(未定義的識別符號)看起,然後往右看,再往左看。每當遇到圓括號時,就應該掉轉閱讀方向。一旦解析完圓括號裡面所有的東西,就跳出圓括號。重複這個過程直到整個宣告

修正:
筆者要對這個法則進行一個小小的修正,應該是從未定義的識別符號開始閱讀,而不是從括號讀起,之所以是未定義的識別符號,是因為一個聲明裡面可能有多個識別符號,但未定義的識別符號只會有一個。

連結:https://www.cnblogs.com/Lunais/p/5969181.html


 

int (*func)(int *p);
首先找到那個未定義的識別符號,就是func,它的外面有一對圓括號,而且左邊是一個*號,這說明func是一個指標,然後跳出這個圓括號,先看
右邊,也是一個圓括號,這說明(*func)是一個函式,而func是一個指向這類函式的指標,就是一個函式指標,這類函式具有int*型別的形參,返回值型別是 int。

 

#include <stdio.h>

int max( int *p )
{
 return 0;
}

int main ()
{
 int *k;
 int (*func)(int *p) = &max;
 func( k );

  return 0;
}


 

 

int (*func)(int *p, int (*f)(int*));
func被一對括號包含,且左邊有一個*號,說明func是一個指標,跳出括號,右邊也有個括號,那麼func是一個指向函式的指標,這類函式具有int *和int (*)(int*)這樣的形參,返回值為

int型別。再來看一看func的形參int (*f)(int*),類似前面的解釋,f也是一個函式指標,指向的函式具有int*型別的形參,返回值為int。

 

#include <stdio.h>

int max( int *p )
{
 return 0;
}

int test( int *pt, int (*f)(int*))
{
 return 0;
}

int main ()
{
 int *k;
 int (*func)(int *p, int (*f)(int*)) = &test;
 func( k, &max);

  return 0;
}


 

 

int (*(*func)(int *p))[5];
func是一個函式指標,這類函式具有int*型別的形參,返回值是指向陣列的指標,所指向的陣列的元素是具有5個int元素的陣列

#include <stdio.h>

typedef int(*TYPE)[5];
TYPE fun( int *k )
{
int a[5];
TYPE p=&a;
return p;
}

int main ()
{
  //func是一個函式指標,這類函式具有int*型別的形參,返回值是指向陣列的指標
  //所指向的陣列的元素是具有5個int元素的陣列。
  int (*(*func)(int *p))[5] ;
  func = &fun;
  return 0;
}

 


int (*func[5])(int *p);
func右邊是一個[]運算子,說明func是一個具有5個元素的陣列,func的左邊有一個*,說明func的元素是指標,要注意這裡的*不是修飾 func的,而是修飾func[5]的,原因是[]運算子優先順序

比*高,func先跟[]結合,因此*修飾的是func[5]。跳出這個括號,看右邊,也是一對圓括號,說明func陣列的元素是函式型別的指標,它所指向的函式具有int*型別的形參,返回值型別為

#include <stdio.h>

int max( int *p )
{
 return 0;
}

int main ()
{
  int (*func[5])(int *p);
  func[0] = &max;

  return 0;
}

 


double (* (* P1)[10] )( double k );//陣列指標,第一個*說明陣列中包含的是指標,往右是引數列表,說明陣列中包含的是函式指標,這些函式沒有引數,返回值型別是double

 

 

#include <stdio.h>

/* "*(*P2[10])()"用typedef分解及使用 */
typedef double ( * ppt )( double k );
typedef ppt (*p)[2];

double M( double k )
{
 return k;
}

double L( double k )
{
 return k + 1;
}

int main ()
{
 double (*mm)(double k);
 p  a;
 ppt arry[2] = { &M, &L };
 a = &arry ;
 mm = **a;//得到&M地址
 mm = *(*a+1) ;//得到&L的地址
 printf( "%f\n", mm(3.14));

 getchar();
    return 0;
}


最後看一個比較難點的例子:double  ( *(* (*fp3)( double(*u)(double k) ) )[1] )(  double k  );

對比:double (* (* P1) [1] )( double (*p) ( double k ) );

/*分析 double (* (* P1)[1] )( double (*p) ( double k ) ) :用左右法分析 :首先找到未知變數P1,往右看到第一個括號,往左看遇到第一個*,說明P1是一個指標。跳出第一個內部括號,首先與【】結合,因為【】優先順序比*高,說明P1是一個數組指標。在往右看是第二個括號),然後往左看遇到第一個*,說明陣列指標裡面的元素是一個指標,什麼型別的指標呢?跳出第二個括號,往右是引數列表,說明陣列中包含的是函式指標,這些函式double (*p) ( double k )型別,返回值型別是double   */

使用typedef分解  double (* (* P1)[1] )( double (*p) ( double k ) );

第一步:typedef double ( * ppt )( double k );==> double (* (* P1)[10] )( ppt k );

第二部:typedef ppt (*p)[1];==> 此時如果定義一個變數 (p a;),那麼a的型別將和P1的型別一致

 

使用typedef分解  double  ( *   (*    (*fp3)( double(*u)(double k) )   ) [1] )(  double k  );

/*   如果把 (*fp3)( double(*u)(double k) ) 替換成P1,那麼將和上面舉的例子相同  */

第一步:typedef p (*fp3)( ppt point );//返回型別是一個數組指標,所以p是一個數組指標型別

第二步:typedef ppt (*p)[1];//定義一個數組指標,陣列指標所指向的陣列具有“函式指標,指向形參為double,返回為double”的特徵

第三步:typedef double ( * ppt )( double k );//定義一個函式指標,指向形參為double,返回為double的函式

貼上測試型別程式碼:

#include <stdio.h>

typedef double ( * ppt )( double k );
typedef ppt (*p)[1];//p的型別為 ppt (*)[1];
typedef p (*fp)( ppt point );//定義一個函式指標,引數也是一個函式指標

typedef double  ( *(* (*fp3)( double(*u)(double k) ) )[1] )(  double k  );

int main ()
{
    fp3 jj;
    fp qq;
    jj = qq;

    return 0;
}//沒有報錯,說明使用typedef分解正確

最後貼上使用例項,以幫助大家更詳細的瞭解:

#include <stdio.h>

typedef double ( * ppt )( double k );
typedef ppt (*p)[1];//p的型別為 ppt (*)[1];
typedef p (*fp)( ppt point );//定義一個函式指標,引數也是一個函式指標

//跟前面一樣,先找到變數名fp3(這裡fp3其實是新型別名),往右看是圓括號,調轉方向往左是*,說明fp3是一個指標;跳出圓括號,
//往右看是ppt型別的引數,說明fp3是一個函式指標,接著往左是*號,說明該函式的返回值是一個指標;跳出第二層圓括號,往右是[]運算子,
//說明函式的返回值是一個數組指標,接著往左是*號,說明陣列中包含的是指標;跳出第三層圓括號,往右是引數列表,說明陣列中包含的
//是函式指標,這些函式有一個double的形參,返回值型別是double。簡言之,fp3是一個指向函式的指標,所指向的函式具有ppt型別引數返回double型別的值,
//且返回一個含有1個數組指標,並且該陣列指標所指向的陣列具有ppt型別並且步長一樣的陣列。
typedef double  ( *(* (*fp3)( double(*u)(double k) ) )[1] )(  double k  );

//typedef double *(*P2[10])();//指標陣列,數組裡面的元素是函式指標,指向沒有引數返回值為double型別的函式
//typedef double (* (* P1)[10])();//陣列指標,第一個*說明陣列中包含的是指標,往右是引數列表,說明陣列中包含的是函式指標,這些函式沒有引數,返回值型別是double
/* 如果max函式的型別定義為 P2,則會報錯,因為函式不允許反回陣列
P1 max( int *k )
{
 P1 pt;
 return 0;
}*/

double test( double result )
{
 return result;
}

/* 引數point為指向ppt(返回值為double,引數為double型別的引數)型別的指標 */
p func( ppt point )
{
 ppt b[1] = { point } ;//建立一個ppt型別的陣列,陣列元素為ppt型別
 p point_b;//建立一個數組指標,用於指向ppt型別的陣列,注意步長要一樣
 point_b = &b;
 return point_b;
}

int main ()
{
// ppt本身就是函式指標,ppt*為指向函式指標的指標
//  ppt* point;
//  point = &test;//報錯

 fp a;//定義一個fp型別的函式指標
 ppt point_test;//定義一個ppt型別的函式指標

 a = &func;//&操作符只是顯示地說明了編譯器隱式執行的任務,a = func也可以
 point_test = **a( &test );//*a( &test ),取得陣列b的地址。**a( &test ),取得陣列b裡面的內容,即test的地址

 printf( "%f\n", point_test(3.14));
 getchar();

}

 

參考連結:

https://www.cnblogs.com/Lunais/p/5969181.html

https://blog.csdn.net/skywalker_leo/article/details/48622193