《C專家程式設計》讀書筆記9

2021-05-27 07:33:29 字數 3134 閱讀 7530

第九章 再論陣列

宣告本身還可以進一步分成3種情況:

外部宣告(external array)的宣告。

陣列的定義(記住,定義是宣告的一種特殊情況,它分配記憶體空間,並可能提供乙個初始值)。

函式引數的宣告。

所有作為函式引數的陣列名總是可以通過編譯器轉換為指標。

作為函式定義的形式引數,char s和 char* s是一樣的。

陣列下標表示式總是可以改寫為帶有偏移量的指標表示式。

char my_array[10];

char *my_ptr;

i = strlen( my_array);

j = strlen( my_ptr);

printf ( 「%s %s」, my_ptr, my_array);

它清楚地展示了陣列和指標的可互換性。

printf(「 array at location %x holds string %s」, a, a);

同一條語句中,既把陣列名作為乙個位址(指標),又把它作為乙個字元陣列。

什麼時候陣列和指標相同:

規則1. 表示式中的陣列名(與宣告不同)被編譯器當做乙個指向該陣列第乙個元素的指標。

規則2. 下標總是與指標的偏移量相同。

規則3. 在函式引數的宣告中,陣列名被編譯器當做指向該陣列第乙個元素的指標。

int a[10], *p, i=2;

可以通過以下任何一種方法來訪問a[i];

p = a;  p[i];

p = a;  *(p + i);

p = a + i;  *p;

對陣列的引用如a[i]在編譯時總是被編譯器改寫成*(a + i)的形式。

在表示式中,指標和陣列是可以互換的,因為它們在編譯器裡的最終形式都是指標,並且都可以進行取下標操作。

在函式形參定義這個特殊情況下,編譯器必須把陣列形式改寫成指向該陣列第乙個元素的指標形式。編譯器向函式傳遞陣列的位址,而不是整個陣列的拷貝。這種隱性轉換意味著三種形式是完全等同的。因此,在函式my_function()的呼叫上,物理實參是陣列還是真的指標都是合法的。

my_function(int *turnip)

my_function(int turnip)

my_function(int turnip[200])

之所以要把傳遞給函式的陣列引數轉換為指標是出於效率的考慮。

在c語言中,所有非陣列形式的資料實參均以傳值形式呼叫。

在下列的定義中:

my_function(int *turnip)

my_function(int turnip)

my_function(int turnip[200])

int my_int;

int *my_int_ptr;

int my_int_array[10];

你可以合法地使用下列任何乙個實參來呼叫上面任何乙個原型的函式。它們常常用於不同的目的。

相反,如果出於func()函式內部,就沒有一種容易的方法分辨這些不同的實參,因此也無法知道呼叫該函式是出於何種目的。

當然,在函式內部使用指標,所能進行的對陣列的操作幾乎跟傳遞原原本本的陣列沒有差別,只不過,如果想用sizeof來獲取陣列的長度,所得到的結果不正確而已。

如果想讓**看上去清楚明白,就必須遵循一定的規則!我們傾向於始終把引數定義為指標。因為這是編譯器內部所使用的形式。

注意,有一樣操作只能在指標裡進行而無法在陣列中進行,那就是修改它的值。陣列名是不可修改的左值,它的值是不能改變的。

語句array = array2;將引起乙個編譯時錯誤,錯誤資訊是「無法修改陣列名」。但是arr =array2卻是合法的,因為arr雖然宣告為乙個陣列但實際上卻是乙個指標。

可以讓指標指向任何乙個元素,這樣傳遞給函式的就是從該元素之後的陣列片段。

1.               用a[i]這樣的形式對陣列進行訪問總是被編譯器「改寫」或解釋為像*(a + i)這樣的指標訪問。

2.               指標始終就是指標。它絕不可以改寫成陣列。可以用下標形式訪問指標,一般都是指標作為函式引數時,而且你知道實際傳遞給函式的是乙個陣列。

3.               在特定的上下文中,也就是它作為函式的引數(也只有這種情況),乙個陣列的宣告可以看做是乙個指標。

4.               因此,當把乙個陣列定義為函式的引數時,可以選擇把它定義為陣列,也可以定義指標。不管選擇哪種方法,在函式內部事實上獲得的都是乙個指標。

5.               在其他所有情況下,定義和宣告必須匹配。如果定義乙個陣列,在其他檔案對它進行宣告時,也必須把它宣告為陣列,指標也是如此。

c語言的方法多少有點獨特:定義和引用多維陣列唯一的方法就是使用陣列的陣列。儘管術語上稱作「多維陣列」,但c語言實際上只支援「陣列的陣列」。

int apricot[2][3][5];

可以按圖所示的任何一種方法為它在記憶體中定位。

在c語言的多維陣列中,最右邊的下標是最先變化的,這個約定稱為「行主序」。由於「行/列主序」這個術語只適用於恰好是二維的多維陣列,所以更確切的術語是「最右的下標先變化」。

如果在陣列的定義裡未標明它的長度,c語言規定按照初始化值的個數來確定陣列的長度。

short cantaloupe[2][5] =

int rhubarb[3] = , ,};

注意,可以在最後乙個初始化值的後面加乙個逗號,也可以省略它。同時,也可以省略左邊下標的長度(也只能是最左邊的下標),編譯器會根據初始化值的個數推斷出它的長度。

如果陣列長度比所提供的初始化值的個數要多,剩餘的幾個元素會自動設定為0,。如果元素的型別是指標,那麼他們被初始化為null;如果元素的型別是float,那麼它們被初始化為0.0。

下面是一種初始化二維字串陣列的方法:

char vegetables[9] = ;

char *vegetables=; /*沒問題*/

只有字串常量才可以初始化指標陣列。指標陣列不能由非字串的型別直接初始化:

int *weights= , , }; /*無法編譯通過*/

如果想用這種方法來對陣列進行初始化,可以建立幾個單獨的陣列,然後用這些陣列名來初始化原先的陣列。

int row_1=;/*-1是行結束標誌*/

int row_2=;

int row_3=;

int *weight = ;

《C 專家程式設計》讀書筆記

前言 程式設計挑戰 計算機日期 第二章 這不是bug,而是語言特徵 switch的乙個bug break中斷了什麼 第三章 分析c語言宣告 程式設計挑戰 把c 語言的宣告翻譯成通俗的語言 include include include include define max len 100 enum ...

《C專家程式設計》讀書筆記

第一章 const float 表示乙個指向float型別常量的指標 第二章 1.在c語言中const並非真正表示 常量 在陣列定義與case中不可以使用 2.case的一些問題 2 3 main 15 這段 列印出來的是 3.函式可見性 void sb any where 2 extern voi...

《C專家程式設計》讀書筆記10

第十章 再論指標 char pea 4 6 的記憶體布局。單個元素的儲存和引用是以線性形式排列在記憶體中的。首先找到pea i 的位置,然後根據偏移量 j 取得字元。因此,pea i j 將被編譯器解析為 pea i j 可以通過宣告乙個一維指標陣列,其中每個指標指向乙個字串來取得類似二維字元陣列的...