天天看點

《C和指針》讀書筆記(7)

聲明:該讀書筆記摘抄自《C和指針》——Kenneth A.Reek (著)    徐波(譯)。為了克服自己走馬觀花,提高閱讀和學習效率,決定将自己在讀書過程中遇到的一些知識點加以摘抄和總結備忘,在此感謝原書作者和翻譯。

一、數組名

1、一個誤區:數組名并不表示整個數組,它大多時候隻是一個指針常量,指向數組的第一個元素,它的類型取決于數組元素類型。這一點解釋了為什麼C語言的數組不能整體拷貝,隻能循環拷貝指派。如果你将數組名指派給另一個數組名,例如,int  a[10] ;  intb[10];  a = b; ,就已經錯的一塌糊塗:

    1)數組名是一個常量指針,它不可以被指派;

    2)就是上面提到的數組不能整體拷貝,因為你得到的僅僅是一個指向數組第一個元素的指針常量而已。

注:個人認為這兩點其實本質上是一個意思。即,假如數組名不是一個指針常量而是表示整個數組,那麼它可以整體指派。

2、數組名大多時候是一個常量指針,但是有且隻有兩種情況,數組名不用指針常量來表示:

    1)作為sizeof的表達式的時候,數組名表示整個數組,sizeof會傳回整個數組占用的位元組數;

    2)當數組名作為操作符&的操作數時,會産生一個指向該數組的指針。

二、數組的下标引用

1、當用下标來通路數組時,下标值可以為任意整數值,可以為負,但是程式員自己必須保證通路的有效性,即不能跳出數組的前邊界;下标值也可以大于數組實際長度,這通常用來實作不對稱邊界,但是要避免對超出數組有效長度的位址進行通路(隻要位址,不要值)。

2、C語言并不會對數組下标有效性進行安全檢查,C語言标準也并沒有規定編譯器必須對數組下标進行有效性檢查,對數組下标的有效性檢查會大大增加程式運作時間和空間的開銷。也就是說保證數組通路不越界的工作應該交由程式員來做。

3、a[2] 和2[a] 都是合法的,并且具有相同的效果,這緣于C語言實作下标的方式,因為在C語言中對下标的通路都可以轉換為對等的間接通路表達式。a[2] 、2[a]都會被編譯器轉換為*(2 + a),這兩種下标書寫形式對編譯器來說并無差異。當然,如果你不是在參加混亂代碼大賽,在代碼可讀性上沒有人會喜歡2[a]這種書寫方式。

三、指針與下标

1、加入下标和指針都可以實作某種需要,下标一定不會比指針更有效率,并且有時候指針比下标更有效率。

2、指針比下标更有效率的場合:當在數組中循環變量一次以固定步長移動時,固定數字與固定數字的相乘是在編譯期間完成的,不會占用運作時間,更有效率一些。

3、一個高效率的數組的拷貝, 将數組y的元素賦給數組x

#define      SIZE             10

int    x[size], y[size] ;

void array_to_array(void)

{

register   int     *p1, *p2;

for (p1=x, p2=y; p1<&x[SIZE]; ) {

*p1++ =  *p2++;

}

}

四、數組和指針

1、數組和指針都具有指針值,都可以進行間接通路和下标引用操作,但是需要注意的是他們并不等價。聲明一個數組時,編譯器首先根據數組元素個數為該數組配置設定記憶體,然後再建立數組名,它是一個指針常量,指向數組的第一個元素。聲明一個指針變量時,編譯器隻為該變量配置設定4個位元組的記憶體。

2、當一個數組名作為參數傳遞給一個函數時,該數組名退化為指針,此時,在函數内部對其sizeof時,得到的結果是4(32位機器),

3、編譯器允許數組不完整初始化,但隻允許順序省略後面的初始值,被省略的初始值全部為0;例如,int   a[10] = {1,2};   a[0] = 1, a[1] = 2, a[2]~a[9]全部為0。另外,對于全局數組,預設初始值都是0, 但是如果對于一個局部數組,并且所有元素都沒有初始化時,其所有元素初始值都是不确定的。

4、在數組聲明時,允許編譯器自動計算數組長度,例如,int   a[ ] = {1, 2, 3, 4, 5};

5、字元數組的初始化,

  方法1、char    a[ ] = {'h', 'e', 'l', 'l', o'', '\0'};        隻适用于較短的字元數組初始化

  方法2、char    a[ ] = "hello";   注意這種初始化方法與字元串常量的差別:當它用于初始化一個字元數組時,它就是一個字元數組的初始化清單,其他的任何情況都是字元串常量。

五、多元數組

1、int     a[3][4]; 可以将a看作一個具有三個元素的一維數組,隻不過每個元素又是一個具有4個元素的一位數組;

同樣,int     a[2][3][4];将a看作一個具有兩個元素的一維數組,其中每個元素又是一個具有三個元素的一維數組,而這三個元素的每一個又是一個具有4個元素的一維數組。可見,多元數組可以看作是很多一維數組的嵌套集合。

2、多元數組在記憶體中的存儲順序

在C語言中,多元數組元素的存儲順序按照最右邊的下标率先變化,這稱為行主序。

3、指向數組的指針

例如:int  a[3][4], *(p)[4] = a; 此時p指向該二維數組的第一行,p+1指向第二行,每一行是一個具有4個元素的數組,此時p就是一個指向數組的指針。

特别注意:若p初始化為int  *p = a; 則是錯的,因為p是一個指向整型的指針,而二維數組名a是一個指向二維數組第一行的一維數組的指針常量,也就是說a是一個指向數組的指針,相當于二級指針,用一個二級指針初始化一個一級指針,顯然不合适。此時應該使用行指針變量,即int   (*p)[4]才正确,要注意,除了第一維聲明為指針p外,其他各維必須明确用下标指定。 若将行指針變量定義為int   (*p)[ ]; 此時p仍然是一個指向一個一維數組的行指針變量,但是此時一維數組的長度卻沒有指定,于是當p指針參與運算時,它指向的數組将會被視為空數組,即數組長度為0,計算指針p的步長時将與0相乘,這種情況可能不是你想要的,應該避免。

4、多元數組作為函數參數

例如有一個二維數組:  int  a[3][4];    

a作為參數傳遞給函數:      func(a);

      函數func的聲明形式為: void func(int  p[ ][4])   或者void func(int   (*p)[4])

  注:要差別void  func(int   **p) ,這種聲明形式是錯誤的,p是一個真正的二級指針,即p被聲明為一個指向整型的指針的指針。

5、多元數組的初始化

原則:按照最右邊的下表率來變化。

6、多元數組的長度自動計算

注意,在多元數組中隻有第一維的長度才能自動計算,其餘各維必須顯示指定。

七、指針數組

下表優先級高于間接通路符優先級

             以上為第八章“數組和指針”摘抄總結,未完待續。。。

繼續閱讀