原文地址:http://www.cnblogs.com/processakai/archive/2012/04/04/2431946.html
錯誤的地方帶查證:
一、 數組的指針、指針數組以及指向指針的指針 考慮數組的指針的時候我們要同時考慮類型和維數這兩個屬性。換一句話,就是說一個數組排除在其中存儲的數值,那麼可以用類型和維數來位
一、數組的指針、指針數組以及指向指針的指針
考慮數組的指針的時候我們要同時考慮類型和維數這兩個屬性。換一句話,就是說一個數組排除在其中存儲的數值,那麼可以用類型和維數來位置表示他的種類。 A)一維數組 int a[10]; int *p; p=&a[0]//和p=a是等價的: (1) p[i]和a[i]都是代表該數組的第i+1個元素; B)多維數組
對照這個圖,如下的一些說法都是正確的(對於a[4][6]): a是一個數組類型,*a指向一個數組;a+i指向一個數組;a、*a和&a[0][0]數值相同;a[i]+j和*(a+i)+j是同一個概念; 總結一下就是:我們對於二維指針a,他指向數組a[0,1,2,3],使用*,可以使他降級到第二層次,這樣*a就指向了第一個真正的數組。對於其他的情況我們也可以採用相同的方式,對於其他維數和類型的數組我們可以採用相類似的思想。 int (*p)[5]; 這時p就是一個指針,要指向一個含有5個int類型元素的數組,指向其他的就會出現問題。 C)指針數組 int *p[10];//而不能是int (*p)[10] 或者 char *p[10]; 此時p是一個指針(數值上和&p[0]一樣); int * pt=t;//使用pt指向t 那麼這裏我們用什麼指向int *t[10]中的t呢?我們要使用一個指針的指針: int **pt=t; 這是因爲:在int *t[10]中,每個元素是指針,那麼同時t又指向這個數組,數組上和&t[0]相同,也就是指向t[0],指向一個指針變量,可以說是一個指針的指針了,所以自然要用 int **pt;
int *p1=&i; int**p2=&p1; 綜合以上的所有點,下面是我們常常看到一些匹配(也是經常出錯的地方): int a[3],b[2][3],c,*d[3]; void fun1(int *p); void fun2(int (*p)[3]); void fun3(int **p); void fun4(int p[3]); void fun5(int p[]); void fun6(int p[2][3]); void fun7(int (&p)[3]); 自己加上的:int (&p)[3]:p是一個引用,引用的是一個一維數組;
#include <string.h>
void fun7(int (&p)[3])
void main() 跟int *p的不同點在於 int t1[4] = {1,2,3,4}; 而 int t1[4] = {1,2,3}; 最新C99標準 int f(int t[3]);參數的數組個數最少爲3; 數組沒有像malloc一樣有信息頭;所以是經過在編譯時檢查的;同時說明sizeof(數組名)是編譯時生成;
函數 不會產生編譯時刻的可能值(但邏輯上不一定都對)
|
-------------------------------------------------------------------------分頁------------------------------------------------------------------------------------------
爲什麼可以有這樣的搭配,原因如下: 對於fun1 fun4 fun 5: 在編譯器看來fun1,fun4,fun5的聲明是一樣,在編譯時候,編譯器把數組的大小捨去不考慮,只考慮它是一個指針,也就是說有沒有大小說明是一樣的,所以三者的形式都是fun1的形式(其實只要提供了int*指針就可以了);對於fun7 :以上的解釋對於引用是不適用的,如果變量被聲明爲數組的引用,那麼編譯器就要考慮數組的大小了,那麼必須和聲明一模一樣(所以fun7就只有a合適);對於fun2:p是一個指向一個含有3個元素的數組,這樣b和b+i正好合適,而a卻不是(它是指向a[0]的,不是指向這個數組的);對於fun3:p是一個指針的指針,而d指向d[0],同時d[0]又是一個指針,所以d就是一個指針的指針。但是b卻不是(它是一個2*3的矩陣也就是年int [2][3]類型);對於fun6,p是一個2*3的數組類型,和b恰好完全匹配;
A) 函數指針 int (*p)(int I,int j); 不能是 int *p(int I,int j), 這樣就變成了返回指針的函數聲明瞭。 在C++中處於對安全性的考慮,指針和它指向的對象要類型一致,也就說上面的指針所指向的函數的特性要和它一模一樣:例如指向int min(int I,int j);是可以的。但是指向int min(double I ,double j);是不可以。函數指針也和其他的指針一樣,在使用的時候很怕發生"懸空",所以在使用的時候同樣要判斷有效性,或者在定義的時候就初始化。 int (*p)(int I,int j)=min; int (*p)(int I,int j)=&min; int (*p)(int I,int j)=0; B) 函數的指針參數 templateT integrate( T lower, T upper , T (*)(T)=0 )throw(integrated_exp); 這裏的最後的參數是一個函數的指針,並且被設定缺省值爲0。這個函數返回一個值,同時需要一個參數。假如加入我們有這樣的一個函數: double line(double x){ return a*x+b;} 那麼我就可以使用了。 typedef int (*PF)(int ); PF getProcessMethod( );//true C) 返回指針的函數 UserType * Process( ) { UserType ut(param-list); //process ut; return &ut;// } 這個變量在我們的函數結束的時候就被銷燬了,儘管地址可以傳出去,但是這個地址已經不存在了,已經不能使用的東西,在這個函數之外卻不知道,難免要出錯! UserType * Process ( ) { UserTpye *put=new UserType(param-list ); //process put; return put; } 我們在函數內部使用了一個new,分配了一個空間,這樣傳出來也是可以! 三、類成員的指針 類成員和一般的外部變量相互比較,不同就是它所在的域不同,這個域很重要,它決定了該變量可以使用的範圍。那麼一個指針如果要指向類的成員函數或者成員變量,那麼除了要表達它的返回類型、參數列表或者類型之外,那麼還要說明它所指向的變量(或者函數)的域,爲了說明該域我們要使用類域限定: class NJUPT { static double money=20000000; int num; public: NJUPT():num(10){}; int get(){return num;}; double getMoney(){reuturn money;} } 我們定義成員的指針爲 int NJUPT:: *p;//指向int型成員變量 int (NJUPt::*)p()//指向int f()型成員函數。 爲了使用這些指針,我們需要使用該類型的變量或者指針。 NJUPT s,*ps; 那麼調用的方式爲: cout<*p)(); 這個看起來似乎很奇怪!但是隻要你想到我們定義的指針被限定在了類域中了(我們在開始定義的使用使用了NJUPT:: ),這麼使用也是很自然的。 double *p=&NJUPT::money; double (*p)()=&NJUPT::getMoney(): |