C語言課件:第12章 指針和數組_第1頁
C語言課件:第12章 指針和數組_第2頁
C語言課件:第12章 指針和數組_第3頁
C語言課件:第12章 指針和數組_第4頁
C語言課件:第12章 指針和數組_第5頁
已閱讀5頁,還剩44頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、1第 12 章指針和數組C語言允許對指向數組元素的指針進行算術運算:加法和減法。這一特性表明能夠用指針代替數組下標對數組進行處理。C語言中指針和數組的關系非常緊密。2指針的算術運算指針可以指向數組元素:int a10, *p;p = &a0;用圖形方式表示為:3指針的算術運算可以通過p訪問a0,例如,可以采用如下的方式將數值5存入a0 中: *p = 5;更新后的圖形表示為:4指針的算術運算如果指針p指向數組a的元素,則可以通過對指針p進行指針算術運算(或地址算術運算)訪問數組a中其他元素:C語言支持三種類型的指針算術運算(且僅有這三種類型)指針加上整數指針減去整數兩個指針相減5指針加上整數指

2、針p加上整數j產生一個新的指針,指向p 當前所指的元素位置之后j個元素的位置。如果 p指向數組元素 ai,則 p + j 指向數組元素 ai+j。6指針加上整數指針加法運算示例:p = &a2;q = p + 3;p += 6;7假設有如下聲明:int a10, *p, *q, i;指針減去整數如果p 指向 ai,則p - j 指向 ai-j。示例:p = &a8;q = p - 3;p -= 6;8兩個指針相減當兩個指針相減時,結果為指針之間的距離(以數組元素的個數作為度量)。如果p指向ai ,q指向aj,則 p q等于i j示例:p = &a5;q = &a1;i = p - q; /*

3、i is 4 */i = q - p; /* i is -4 */9兩個指針相減下列操作會導致未定義的行為:對一個并未指向數組元素的指針執行算術運算當兩個指針并非指向同一數組中的元素時,對其執行減法操作;10指針比較指針可以采用關系運算符 (, , =) 和判等運算符 (= 和 !=)進行比較:只有在兩個指針指向同一數組(中的元素)時,用關系運算符進行指針比較才有意義。指針比較的結果依賴于指針指向的數組元素在數組中的相對位置。例如:通過如下的賦值操作p = &a5;q = &a1;有 p = q 的值為 1。11指針用于數組處理指針的算術運算使我們能夠通過對指針變量進行重復自增來逐一訪問數組大

4、元素。下例采用循環對數組a中的元素進行求和:#define N 10int aN, sum, *p;sum = 0;for (p = &a0; p &aN; p+) sum += *p;12指針用于數組處理第一輪迭代結束時:第二輪迭代結束時:第三輪迭代結束時:13指針用于數組處理for 語句中的循環條件 p &aN 值得引起特別的注意。盡管元素aN并不存在,但對其進行取地址運算是合法的。采用指針算術運算通常可以節省執行時間。然而,對某些編譯器而言,采用數組下標來遍歷數組的效率可能更高。14* 和 + 運算符的組合C程序員常在處理數組元素的語句中組合使用 *(間接訪問)和 + 操作符。下述語句修

5、改當前位置(下標i)的數組元素值,并修改下標前進到下一個元素的位置:ai+ = j;相應地,可以采用指針實現同樣功能:*p+ = j;由于后綴的 + 運算符的優先級高于*,編譯器將上述語句解釋為:*(p+) = j;15* 和 + 運算符的組合可能的 * 和 +運算符的組合:表達式含義*p+ or *(p+)自增前表達式的值為 *p,然后自增p;(*p)+自增前表達式的值為 *p,然后自增*p;*+p or *(+p)先自增 p,自增后表達式的值為 *p;+*p or +(*p)先自增 *p,自增后表達式的值為 *p; 16* 和 + 運算符的組合最常見的組合是 *p+,在循環中十分方便。例如

6、:下述代碼對數組a的元素進行求和for (p = &a0; p &aN; p+) sum += *p;可以改寫為:p = &a0;while (p &aN) sum += *p+;17* 和 + 運算符的組合 * 和 運算符的組合類似于* 和 +的組合早期的實現利用整型變量top來跟蹤記錄contents數組中“棧頂”位置的變化情況。 這里我們使用一個指針變量來替換top ,該變量指向contents 數組的第零個元素:int *top_ptr = &contents0;18* 和 + 運算符的組合新的 push 和 pop 函數:void push(int i) if (is_full()

7、stack_overflow(); else *top_ptr+ = i;int pop(void) if (is_empty() stack_underflow(); else return *-top_ptr;19用數組名作為指針指針的算術運算體現了數組與指針間相互關聯的關系。另一種重要的關系是:可以用數組名作為指向數組第一個元素的指針這種關系簡化了指針的算術運算,并且使得數組和指針更加通用。20用數組名作為指針假設用如下方式聲明數組a :int a10;使用數組名 a 作為指針的示例如下:*a = 7; /* stores 7 in a0 */*(a+1) = 12; /* stores

8、 12 in a1 */通常情況下,a + i 和 &ai是等同的均表示指向數組 a 中元素 i 的指針同樣地, *(a+i) 與 ai也是等同的均表示數組 a 中的元素 i自身21用數組名作為指針數組名可以用作指針這一事實,使得編寫遍歷數組的循環更加容易。例如對于如下的循環:for (p = &a0; p &aN; p+) sum += *p;可以簡化為如下形式:for (p = a; p a + N; p+) sum += *p;22用數組名作為指針盡管數組名可以用作指針,但不能對其賦值試圖使其指向其它位置會導致錯誤發生:while (*a != 0) a+; /* WRONG */這一限

9、制對我們不會造成太大損失,可以通過將a 賦值給一個指針變量,實現對其的修改:p = a;while (*p != 0) p+;23程序:數列反向(改進版)第八章的程序reverse.c實現了讀入10個數,然后對其進行逆序輸出 。該程序將這些讀入的數字存儲到一個數組中,并利用下標來訪問數組中的元素。reverse3.c 是利用指針的算術運算取代數組下標運算后,得到的改進版本。24reverse3.c/* Reverses a series of numbers (pointer version) */#include #define N 10int main(void) int aN, *p;

10、printf(Enter %d numbers: , N); for (p = a; p = a; p-) printf( %d, *p); printf(n); return 0;25數組型參數 (改進版)當數組名被傳遞給函數時,總是被視為指針示例:int find_largest(int a, int n) int i, max; max = a0; for (i = 1; i max) max = ai; return max;對 find_largest函數的調用:largest = find_largest(b, N);該調用會把指向數組b第一個元素的指針賦值給a,注意:數組b自身并

11、未被復制。26數組型參數 (改進版)將數組型參數作為指針處理會產生一些重要的影響和后果。后果 1: 當向函數傳遞普通變量時,變量的值會被復制,函數對形參的任何修改都不會影響到該變量自身。與之形成對比的是,當數組名被用作實參進行參數傳遞時,無法保護函數對數組元素的修改27數組型參數 (改進版)例如,下述函數將對傳入的數組進行修改,結果是數組中前n個元素的值將被置為零。void store_zeros(int a, int n) int i; for (i = 0; i n; i+) ai = 0;28數組型參數 (改進版)為指示函數不要對傳入的數組參數進行修改,可以在形參聲明中加上const 關

12、鍵字:int find_largest(const int a, int n) 如果存在 const 關鍵字,編譯器會檢查find_largest函數,確保其中沒有對數組a的元素進行賦值的操作。29數組型參數 (改進版)后果2: 向函數傳遞數組所需的時間與數組的大小無關。由于沒有對數組進行復制操作,所以傳遞大數組不會對性能構成影響。30數組型參數 (改進版)后果 3: 如果需要,可以將數組型形式參數聲明為指針。例如:find_largest 可以定義如下:int find_largest(int *a, int n) 將 a聲明為指針,等同于將其聲明為數組,編譯器將這兩種聲明方式看做是完全一樣

13、的。 31數組型參數 (改進版)盡管對形參而言,聲明為數組和聲明為指針是一樣的,但是對于變量而言,二者是不同的。例如,如下聲明會導致編譯器預留10個整型變量的空間:int a10;而如下的聲明只會導致編譯器預留一個指針變量的空間:int *a;32數組型參數 (改進版)在第二個聲明中,a并不是一個數組,如果將其作為數組使用會導致災難性后果。 例如:如下的賦值操作*a = 0; /* WRONG */會將 0存儲到 a指向的位置。 由于我們并不知道a究竟指向哪里,因此該語句對程序的影響是無法預料的。33數組型參數 (改進版)后果 4: 如果一個函數以數組作為形參,則可以向其傳遞一個數組“片段”:

14、即一個連續存儲的數組元素構成的序列。例如:可以利用find_largest找出數組b中第5到第14號元素中的最大者: largest = find_largest(&b5, 10);34使用指針作為數組名C語言允許我們將指針視為數組名,并對其執行下標操作:#define N 10int aN, i, sum = 0, *p = a;for (i = 0; i N; i+) sum += pi;編譯器會將 pi 和 *(p+i)等同進行處理35指針和多維數組正如指針可以指向一維數組的元素一樣,指針也可以指向多維數組的元素。36處理多維數組的元素C語言按行主序存儲二維數組一個 r 行的數組可以表示

15、如下: 如果指針 p 指向二維數組中的第一個元素(0行0列),則可以通過反復自增 p 的方式訪問數組中的每一個元素。37處理多維數組的元素示例:將如下二維數組中的所有元素初始化為0:int aNUM_ROWSNUM_COLS;顯然我們可以采用嵌套的 for 循環:int row, col;for (row = 0; row NUM_ROWS; row+) for (col = 0; col NUM_COLS; col+) arowcol = 0;但是,如果將 a 視為一維的整型數組,一重循環就夠了:int *p;for (p = &a00; p = &aNUM_ROWS-1NUM_COLS-1

16、; p+) *p = 0;38處理多維數組的元素盡管將二維數組作為一維數組處理有點“取巧”的嫌疑,但絕大多數編譯器都接受這樣的做法然而這種做法顯然破壞了程序的可讀性,不過對于某些老舊的編譯器而言,這種做法能夠在程序執行效率方面得到一些補償。對于大多數現代編譯器而言,這樣做對于程序性能的提高往往極少,甚至沒有。39處理多維數組的行指針變量 p 也可以用于處理二維數組中的某一行元素。為了訪問二維數組a中的第i行元素,可以采用如下方式初始化指針p ,使之指向數組a中第i行的第0個元素:p = &ai0;或者,可以簡單地寫為:p = ai;對于任意二維數組a,表達式ai的結果是一個指針,指向數組a中第

17、i行的首元素。40處理多維數組的行ai和 *(a + i)的等同關系由此可知,&ai0 等同于 &(*(ai + 0),因此也等同于 &*ai。顯然,&*ai就是 ai,因為&和 *運算符的作用相互抵消。 41處理多維數組的行下述循環語句將數組a中第i行元素清零:int aNUM_ROWSNUM_COLS, *p, i;for (p = ai; p ai + NUM_COLS; p+) *p = 0;由于ai 是指向數組a中第i行元素的指針,因此可以將其作為參數傳遞給一個接受一維數組作為形參的函數。換言之,以一維數組為形參的函數,同樣可以接受二維數組中的一行作為參數傳入。42處理多維數組的行以

18、 find_largest函數為例,該函數用于找出一維數組中的最大元素。我們可以簡單地使用 find_largest 來找出二維數組a中第i行的最大元素 :largest = find_largest(ai, NUM_COLS);43處理多維數組的列處理二維數組中的一列元素要稍微麻煩一些,因為數組是逐行存儲的(而不是逐列)。下述循環語句對二維數組a中第i列元素清零:int aNUM_ROWSNUM_COLS, (*p)NUM_COLS, i;for (p = &a0; p &aNUM_ROWS; p+) (*p)i = 0;44用多維數組名作為指針無論數組維數高低,任意數組的名字均可用作指針,

19、但是在實際應用中需要十分小心。例如:int aNUM_ROWSNUM_COLS;a 并不是指向a00的指針,而是指向a0的指針C語言將a視為一維數組,且該數組的元素為一維數組 當作為指針時,a的類型為int (*)NUM_COLS,即指向長度為NUM_COLS的整型數組的指針。 45用多維數組名作為指針了解a指向 a0有助于簡化處理二維數組元素的循環。例如可以對如下循環進行簡化:for (p = &a0; p &aNUM_ROWS; p+) (*p)i = 0;改寫為(對數組a第i列元素進行清零):for (p = a; p a + NUM_ROWS; p+) (*p)i = 0;可以通過這種方式讓函數將多維數組看成一維數組。46用多維數組名作為指針如果嘗試用find_largest 找出數組 a中最大元素:largest = find_largest(a, NUM_ROWS * NUM_CO

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論