版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、第十章 指針用戶在程序設(shè)計中用戶在程序設(shè)計中定義一個定義一個變量變量內(nèi)存區(qū)每一個字節(jié)內(nèi)存區(qū)每一個字節(jié)有一個編號有一個編號地址地址編譯過程中:編譯過程中:1、根據(jù)變量類型,分配一定長度、根據(jù)變量類型,分配一定長度的內(nèi)存空間;的內(nèi)存空間;2、變量名變量名轉(zhuǎn)換為所分配內(nèi)存的轉(zhuǎn)換為所分配內(nèi)存的地址地址2、用戶存取數(shù)據(jù)方式、用戶存取數(shù)據(jù)方式變量名變量名地址地址地址所標(biāo)志的地址所標(biāo)志的內(nèi)存段內(nèi)存段一個比方一個比方: 旅旅 客客 變量數(shù)據(jù)變量數(shù)據(jù) 旅旅 客客 名名 字字 變量名變量名 旅館房間旅館房間 內(nèi)內(nèi) 存存 區(qū)區(qū) 旅館房間號旅館房間號 地地 址址 查找旅客查找旅客:旅客名字:旅客名字房間號碼房間號碼房
2、房 間間找到旅客找到旅客 存取數(shù)據(jù)存取數(shù)據(jù): 變量名變量名 內(nèi)存地址內(nèi)存地址內(nèi)存區(qū)內(nèi)存區(qū)數(shù)數(shù) 據(jù)據(jù)注意注意: 內(nèi)存單元的地址內(nèi)存單元的地址與與內(nèi)存單元的內(nèi)容內(nèi)存單元的內(nèi)容是不同的。是不同的。 內(nèi)存單元內(nèi)存單元地址地址旅館房間旅館房間號碼號碼 內(nèi)存單元內(nèi)存單元內(nèi)容內(nèi)容住在房間內(nèi)的住在房間內(nèi)的旅客旅客。 內(nèi)存地址內(nèi)存地址 331 220 2000 2002 20042006內(nèi)存用戶數(shù)據(jù)區(qū)內(nèi)存用戶數(shù)據(jù)區(qū)內(nèi)存中存內(nèi)存中存放的數(shù)據(jù)放的數(shù)據(jù)3、數(shù)據(jù)存取舉例、數(shù)據(jù)存取舉例 內(nèi)存地址內(nèi)存地址3 6 9 2000 2002 2004內(nèi)存用戶數(shù)據(jù)區(qū)內(nèi)存用戶數(shù)據(jù)區(qū)變量變量 變量變量 變量變量 相加得相加得9 送到送
3、到K占用的占用的2004,20054、直接訪問與間接訪問、直接訪問與間接訪問 直接訪問:直接訪問: 在數(shù)據(jù)存取中,直接得到變量在數(shù)據(jù)存取中,直接得到變量 i 地址然后地址然后 按變量按變量 i 的地址存取變量的地址存取變量 i 的值的方式。的值的方式。 間接訪問:間接訪問: 在數(shù)據(jù)存放中,變量在數(shù)據(jù)存放中,變量 i 的地址不是直接得到,的地址不是直接得到, 而是而是存存 放在另一個變量放在另一個變量i_pointer中,須先從變量中,須先從變量i_pointer中中 獲取變量獲取變量 i 地址,然后按變量地址,然后按變量i地址存取變量值地址存取變量值i的方式。的方式。一個比方(取抽屜一個比方(
4、取抽屜A中的東西):中的東西):直接訪問:直接訪問: 直接得到鑰匙直接得到鑰匙A 打開抽屜打開抽屜A,取出東西,取出東西 (直接獲得變量(直接獲得變量 i 地址地址按變量按變量 i 地址存取變量的地址存取變量的 i 值值 ) 間接訪問:間接訪問: 鑰匙鑰匙A在抽屜在抽屜B中中用鑰匙用鑰匙B打開抽屜打開抽屜B得到鑰匙得到鑰匙A打開抽打開抽屜屜A取得東西取得東西變量變量i地址放在地址放在 變變量量i_pointer中中讀取變量讀取變量i_pointer值得到變量值得到變量i的地址的地址按變量按變量i地址存取地址存取i值值 內(nèi)存地址內(nèi)存地址3 6 92000 2000 2002 20043010內(nèi)存
5、用戶數(shù)據(jù)區(qū)內(nèi)存用戶數(shù)據(jù)區(qū)變量變量 變量變量 變量變量 變量變量 對地址的操作對地址的操作之前我們可以通過之前我們可以通過&運算符得到變量的地址。既然有了地址,運算符得到變量的地址。既然有了地址,就應(yīng)該可以對該地址進行讀寫。就應(yīng)該可以對該地址進行讀寫。 int i=300; int j;j = &i ; 變量變量j 中存放的是一個數(shù),是中存放的是一個數(shù),是i的地址的地址但我們要如何才能把一個數(shù)如但我們要如何才能把一個數(shù)如 200 存放到變量存放到變量i所在的內(nèi)存所在的內(nèi)存中呢?中呢?最簡單的方式最簡單的方式 i=200;這是賦值語句,編譯器會自動的把這是賦值語句,編譯器會自動的把
6、200送到送到i所在的內(nèi)存單元所在的內(nèi)存單元但我們?nèi)绾螌崿F(xiàn)直接對地址操作?但我們?nèi)绾螌崿F(xiàn)直接對地址操作? j = 200;不可行。此語句是把不可行。此語句是把200送到變量送到變量j所在內(nèi)存單元,所在內(nèi)存單元,對變量對變量i沒有任何影響沒有任何影響指針指針C語言和其他語言的一個重要區(qū)別在于:語言和其他語言的一個重要區(qū)別在于:C語言提供了一種方法,使程序員可以不通語言提供了一種方法,使程序員可以不通過變量名,而通過變量地址直接對變量所過變量名,而通過變量地址直接對變量所在的內(nèi)存單元進行操作。這樣,在的內(nèi)存單元進行操作。這樣,C語言就語言就有了低級語言的特性,直接對地址進行操有了低級語言的特性,直
7、接對地址進行操作也更高效。作也更高效。C中要直接對地址(內(nèi)存)進行操作,需中要直接對地址(內(nèi)存)進行操作,需要使用指針變量要使用指針變量指針和指向指針和指向 int i; int * i_pointer; 定義一個指針變量定義一個指針變量 i=3; i_pointer=&i;分配一塊分配一塊2字節(jié)的內(nèi)存,假設(shè)地址為字節(jié)的內(nèi)存,假設(shè)地址為2000,并用符號,并用符號i表示這表示這個地址個地址分配一塊分配一塊2字節(jié)的內(nèi)存,假設(shè)地址為字節(jié)的內(nèi)存,假設(shè)地址為2004,并用符號,并用符號i_pointer代表這個地址代表這個地址i3; 然后把然后把3寫入寫入i的地址,就是寫到內(nèi)存的地址,就是寫到
8、內(nèi)存2000處處i_pointer=&i; 然后把然后把i的地址的地址2000寫入寫入i_pointer的地址,的地址,就是寫到內(nèi)存就是寫到內(nèi)存2004處處指針和指向指針和指向i_pointerC C語言提供一種特殊的表示方式:語言提供一種特殊的表示方式: i_pointer 用它表示用它表示i_pointeri_pointer所指向的內(nèi)存單元所指向的內(nèi)存單元20003內(nèi)存內(nèi)存2000i_pointer與與 i 是等效的,都表示同一變量,該變量存放地址為是等效的,都表示同一變量,該變量存放地址為2000。因此:因此: i5; i_pointer5 兩語句作用相同,后者直接操作內(nèi)存兩語句
9、作用相同,后者直接操作內(nèi)存內(nèi)存內(nèi)存2004現(xiàn)在,內(nèi)存中的情況如下現(xiàn)在,內(nèi)存中的情況如下我們稱:我們稱:i_pointer指向變指向變量量i,為什么?,為什么?i_pointer存放存放i的地址,通的地址,通過過i_pointer,可以找到,可以找到i問題:如何給問題:如何給i賦值為賦值為5?i_pointer = 5;5*i_pointer = 5; 把把5寫入到寫入到i_pointer所指向的內(nèi)存單元所指向的內(nèi)存單元 510.2.1定義一個指針變量定義一個指針變量例例: int i, j ;int pointer_1 , pointer_2 ;第一條命令定義了兩個整型變量第一條命令定義了兩個
10、整型變量 i, j;第二條命令定義了第二條命令定義了 兩個指針變量兩個指針變量 pointer_1, pointer_2,它們,它們指向整型變量;指向整型變量; 兩個整型變量兩個整型變量pointer_1, pointer_2,它們與它們與 i,j為相同類型,被為相同類型,被pointer_1, pointer_2兩個指針?biāo)赶?;兩個指針?biāo)赶?;基類型基類型?指針變量的基類型是指該指針變量可以指向的變量的指針變量的基類型是指該指針變量可以指向的變量的類型;類型;定義指針變量的一般形式定義指針變量的一般形式: 基類型基類型 指針變量名指針變量名例:例: float pointer_3; (po
11、inter_3是指向?qū)嵭妥兞康闹羔樧兞?,即其中存放是指向?qū)嵭妥兞康闹羔樧兞?,即其中存放的?yīng)該是一個的應(yīng)該是一個float類型變量的地址)類型變量的地址) char pointer_4; (pointer_4是指向字符型變量的指針變量)是指向字符型變量的指針變量)pointer_1=& ipointer_1ipointer_1i執(zhí)行賦值語句之前執(zhí)行賦值語句之前執(zhí)行賦值語句之后執(zhí)行賦值語句之后例例10.2.2指針變量的引用指針變量的引用說明說明1: 指針變量中只能存放地址(指針),而且指針變量中只能存放地址(指針),而且“地址地址”也有類型,不能把其它類型的數(shù)據(jù)賦給指針變量。也有類型,不能
12、把其它類型的數(shù)據(jù)賦給指針變量。例例:int p ; 為整型指針變量為整型指針變量 float f; p = &f; p=100; 都為非法賦值。實際運行時,編譯器只提出警告,程都為非法賦值。實際運行時,編譯器只提出警告,程序仍可以運行,但是往往會導(dǎo)致系統(tǒng)錯誤。序仍可以運行,但是往往會導(dǎo)致系統(tǒng)錯誤。- “該程序執(zhí)行了非法操作該程序執(zhí)行了非法操作” . 遇到問題問題需要關(guān)閉,我們對此引起的不便遇到問題問題需要關(guān)閉,我們對此引起的不便表示抱歉表示抱歉思考思考指針變量也是變量,指針變量占多少字節(jié)指針變量也是變量,指針變量占多少字節(jié)呢?它的大小又有什么含義呢?呢?它的大小又有什么含義呢?i_po
13、inter20003內(nèi)存內(nèi)存2000內(nèi)存內(nèi)存2004整型變量整型變量i在在16位計算機中指針是位計算機中指針是2字節(jié),在字節(jié),在32位計算機中是位計算機中是4字節(jié):字節(jié):4字節(jié)表示指針變量字節(jié)表示指針變量i_pointer占占4字節(jié),而不管它所指向的字節(jié),而不管它所指向的是什么,即指針變量只和編譯器相關(guān),和指向類型無關(guān)是什么,即指針變量只和編譯器相關(guān),和指向類型無關(guān)指針的大小表示了它的指針的大小表示了它的”尋址能力尋址能力“,4字節(jié)最多可以表示字節(jié)最多可以表示的地址是:的地址是:0 xffffffff,即,即2324G指針的運算符指針的運算符有關(guān)的兩個運算符:有關(guān)的兩個運算符: (1)&
14、; :取地址運算符;:取地址運算符; (2):指針運算符(或稱為:指針運算符(或稱為“間接訪問間接訪問”運算符)運算符)例:例:&a為變量為變量a的的地址地址,p為指針變量為指針變量p所指所指向的向的存儲單元存儲單元;注意:注意:*有多重含義:有多重含義: int* p; *p=3; p*3;例程說明例程說明 例例二二. 指針變量的引用指針變量的引用例例10.1main( ) int a , b ; int *p1 , *p2 ; a = 100 ; b = 10 ; p1 = &a ; p2 = &b ; printf ( “ %d , %d n ”, a , b )
15、 ; /*直接訪問方式直接訪問方式*/ printf ( “ %d , %d n ”, *p1 , *p2 ) ; /*間接訪問間接訪問 結(jié)果結(jié)果: 100 , 10 100 , 10 程序中程序中: *p1表示指針變量表示指針變量 p1所指向的變量所指向的變量,即即 a . *p2表示指針變量表示指針變量 p2所指向的變量所指向的變量,即即 b .p1 a&a&b10010p2 b *p1*p2關(guān)于關(guān)于 & 與與 * 運算符的說明運算符的說明: 1: & 是取地址運算符是取地址運算符. 如如: &a , &b 等等. * 是指針運算符是指針運算
16、符. 用于定義時表示其后的標(biāo)識用于定義時表示其后的標(biāo)識符是指針變量符是指針變量.而在程序中而在程序中*p 則表示指針變量則表示指針變量 p所指向的變量所指向的變量,即即目標(biāo)變量目標(biāo)變量。 2. & , * ,+ + , 同優(yōu)先級同優(yōu)先級, 按從右至左方向結(jié)合按從右至左方向結(jié)合. a: 如如: int a, *p1, *p2 ; p1 = &a ; 則則: &*p1 與與 &a 等效等效 p2=&*p1 ; 或或 p2=&a ; 則則: p2 也指向變量也指向變量 a .b: 如如: int a, *p1 ; p1 = &a ; 則則: *
17、&a 與與 *p1 等效等效, 即等價于變量即等價于變量a . c: 如如: int a, *p1; p1 = &a ; 則則: (*p1) + + 等價于等價于 a + + 但注意但注意 *p1+ + 不等價于不等價于 (*p1) + + &ap1*p1*&a a*p1+ + 等價于等價于 *( p1+ + ) 即先得即先得 p1 所指向變量的值所指向變量的值,再使再使指針變量指針變量 p1的值自增的值自增,此時此時 p1 已不在指向原來的變量了已不在指向原來的變量了.例例 10.2 main ( ) int *p1 , *p2 , *p , a , b ;
18、scanf ( “ %d , %d ” , &a , &b ) ; p1 = &a ; p2 = &b ; if ( a b ) p = p1 ; p1 = p2 ; p2 = p ; (進行地址交換進行地址交換) printf ( “ a = %d , b = %d n”, a , b ) ; printf ( “ max = %d , min = %d n ”, *p1 , *p2 ) ; 如輸入如輸入: 5 , 9 輸出輸出: a = 5 , b = 9 max = 9 , min = 5 ( 注意注意: 本程序是采用交換變量本程序是采用交換變量 a 和和
19、 b 的地址來的地址來實現(xiàn)兩個數(shù)的比較的實現(xiàn)兩個數(shù)的比較的.且比較前后且比較前后 a , b 的值并未的值并未發(fā)生變化發(fā)生變化 )&a&b59&b&a95p1p2p pp1p2aba bswap ( int p1 ,int p2 ) int p ; p = p1 ; p1 = p2 ; p2 = p ;main( ) int a , b; scanf ( “ %d , %d ” , &a , &b ) ; if( ab ) swap ( a , b ) ; printf ( “ n %d , %d n ”, a , b ) ;為什么為什么C語言不
20、讓實參和形參雙向傳遞呢語言不讓實參和形參雙向傳遞呢?這種情況會出錯這種情況會出錯: swap( 2, 3);1.大多數(shù)情況大多數(shù)情況, 函數(shù)參數(shù)都是單向傳遞的函數(shù)參數(shù)都是單向傳遞的, 通過返回值通過返回值得到結(jié)果得到結(jié)果, 這樣更符合結(jié)構(gòu)化程序設(shè)計的思想這樣更符合結(jié)構(gòu)化程序設(shè)計的思想, 在不在不主動要求改變的情況下主動要求改變的情況下, 函數(shù)不應(yīng)該改變實參的值函數(shù)不應(yīng)該改變實參的值, 否則可能導(dǎo)致程序設(shè)計時情況變得復(fù)雜否則可能導(dǎo)致程序設(shè)計時情況變得復(fù)雜三三. 指針變量作為函數(shù)的參數(shù)指針變量作為函數(shù)的參數(shù) 指針變量可以作函數(shù)的參數(shù)指針變量可以作函數(shù)的參數(shù),其作用是將一個其作用是將一個變量的變量的
21、地址地址傳送到另一個函數(shù)中。傳送到另一個函數(shù)中。例例 10.3 swap (int * p1 , int * p2 ) int p ; p = *p1 ; *p1 = *p2 ; *p2 = p ;main( ) int a=1, b=2 , *pa , *pb ; pa = &a ; pb = &b ; swap ( pa , pb ) ; printf ( “%d , %d n ”, a , b ) ; swap (int * p1 , int * p2 ) int p ; p = *p1 ; *p1 = *p2 ; *p2 = p ;main( ) int a=5, b=
22、9 , *pa , *pb ; pa = &a ; pb = &b ; swap ( pa , pb ) ; printf ( “%d , %d n ”, a , b ) ; abpap1p2p向向00寫寫5向向02寫寫9000204080a0cpb59060002調(diào)用調(diào)用swap交換交換0002595 如果把如果把 swap 函數(shù)改成函數(shù)改成 : swap (int * p1 , int * p2 ) int *p ; *p = *p1 ; (此句有問題此句有問題 ) *p1 = *p2 ; *p2 = * p ; 又如又如: swap ( int x , int y ) i
23、nt t ; t = x ; x = y ; y = t ; P無確定的地址值無確定的地址值,它,它的的值不可預(yù)見,的的值不可預(yù)見,*p所指向的單元也是不可所指向的單元也是不可預(yù)見,對預(yù)見,對*p賦值可能賦值可能會破壞系統(tǒng)的正常狀態(tài)會破壞系統(tǒng)的正常狀態(tài)。注意參數(shù)的傳遞注意參數(shù)的傳遞類型為類型為“值傳遞值傳遞”55995995abxya bxy(a) (b) 說明說明: 1. 不能通過改變不能通過改變形參指針變量的值形參指針變量的值而使而使實參指針變實參指針變量的值量的值改變改變. 2. 可以通過改變形參指針變量所指向的變量可以通過改變形參指針變量所指向的變量的值來改變實參指針變量所指向的變量的
24、值的值來改變實參指針變量所指向的變量的值. 3. 如想通過函數(shù)調(diào)用得到如想通過函數(shù)調(diào)用得到 n 個要改變的值個要改變的值,可以可以: (1) 在主調(diào)函數(shù)中設(shè)在主調(diào)函數(shù)中設(shè) n 個變量個變量,并用并用 n 個指針變量指個指針變量指 向它們向它們; (2) 將指針變量作實參將指針變量作實參,使使 n 個變量的地址傳給所調(diào)個變量的地址傳給所調(diào)用的函數(shù)形參用的函數(shù)形參; (3) 通過形參指針變量通過形參指針變量,改變該改變該 n 個變量的值個變量的值; (4) 主調(diào)函數(shù)中就可以使用這些改變了值的變量。主調(diào)函數(shù)中就可以使用這些改變了值的變量。swap (int * p1 , int * p2 ) int
25、 *p ; p = p1 ; p1 = p2 ; p2 = p ;main( ) int a=1, b=2 , *pa , *pb ; pa = &a ; pb = &b ; swap ( pa , pb ) ; printf ( “ n %d , %d n ”, a , b ) ;本函數(shù)中試圖通過改變形參本函數(shù)中試圖通過改變形參指針變量的值來使實參指針指針變量的值來使實參指針變量的值改變變量的值改變.swap (int * p1 , int * p2 ) int *p ; p = p1 ; p1 = p2 ; p2 = p ;main( ) int a=1, b=2 , *p
26、a , *pb ; pa = &a ; pb = &b ; swap ( pa , pb ) ; printf ( “%d , %d n ”, a , b ) ;abpap1p2p向向00寫寫1向向02寫寫2000204080a0cpb12060002調(diào)用調(diào)用swap交換交換0002交換交換p1,p2的值的值0200雖然改變了雖然改變了“指向指向”,但沒有,但沒有改變實參的值,即改變實參的值,即Pa和和Pb沒變,沒變,a,b也沒有變也沒有變printf ( “%d %d n ”, *pa , *pb ) ;總結(jié):指針總結(jié):指針(地址地址)做為函數(shù)參數(shù)的意義做為函數(shù)參數(shù)的意義:
27、因為變量的作用域的關(guān)系因為變量的作用域的關(guān)系, 調(diào)用函數(shù)和被調(diào)用函數(shù)中調(diào)用函數(shù)和被調(diào)用函數(shù)中的變量盡管名字可以相同的變量盡管名字可以相同, 但內(nèi)存地址不同但內(nèi)存地址不同. 實參和形參實參和形參的內(nèi)存地址也不同的內(nèi)存地址也不同, 而且是而且是”單向傳遞單向傳遞”,想要通過形參想要通過形參改變而影響實參是做不到的改變而影響實參是做不到的, 要在被調(diào)用函數(shù)中通過要在被調(diào)用函數(shù)中通過”變量名變量名”對調(diào)用函數(shù)中的變量操作也不可行對調(diào)用函數(shù)中的變量操作也不可行. 唯一的辦法是唯一的辦法是, 在被調(diào)用函數(shù)中直接對在被調(diào)用函數(shù)中直接對”調(diào)用調(diào)用”函數(shù)函數(shù)中變量的中變量的”內(nèi)存地址內(nèi)存地址”操作操作. 可行的
28、原因在于可行的原因在于”函數(shù)函數(shù)”中局部變量的中局部變量的”生存期生存期”是隨著函數(shù)的消亡而消亡的是隨著函數(shù)的消亡而消亡的, 主調(diào)函數(shù)還沒有結(jié)束時主調(diào)函數(shù)還沒有結(jié)束時, 其中的局部變量仍然存在于內(nèi)其中的局部變量仍然存在于內(nèi)存中存中, 只是由于種種原因只是由于種種原因,通過變量名無法訪問通過變量名無法訪問. 最終的手段是直接操作地址最終的手段是直接操作地址, 而函數(shù)間的通信可以通而函數(shù)間的通信可以通過參數(shù)傳遞過參數(shù)傳遞, 所以所以, 把地址做為參數(shù)就達到了我們的目的把地址做為參數(shù)就達到了我們的目的思考思考:既然這樣既然這樣,假設(shè)知道了假設(shè)知道了”被調(diào)用函數(shù)被調(diào)用函數(shù)”中某個中某個變量地址變量地址
29、, 我們是否可以直接在我們是否可以直接在”主調(diào)用函數(shù)主調(diào)用函數(shù)”中中直接對直接對”被調(diào)用函數(shù)被調(diào)用函數(shù)”中的變量進行操作呢中的變量進行操作呢?#include int* test(int x)int k=111;return &k;int main(int argc, char* argv )int a=5; int *pa;pa=test(a);printf(%dn,*pa);return 0;#include int* test(int x)int k=111;return &k;void tt( )int t=3,b=4;b=t;int main(int argc, ch
30、ar* argv)int a=5; int *pa;pa=test(a);tt( );printf(%dn,*pa);return 0;什么時候需要地址傳遞:什么時候需要地址傳遞: 1. 傳遞整個數(shù)組傳遞整個數(shù)組 2. 需要在被調(diào)用函數(shù)中修改調(diào)用函數(shù)需要在被調(diào)用函數(shù)中修改調(diào)用函數(shù)中的變量中的變量 3. 需要多個需要多個”返回值返回值”,但不想使用全但不想使用全局變量局變量, 可以在調(diào)用函數(shù)中設(shè)置多個指針可以在調(diào)用函數(shù)中設(shè)置多個指針, 而被調(diào)用函數(shù)中則把要而被調(diào)用函數(shù)中則把要”返回的值返回的值”寫入寫入到相應(yīng)的內(nèi)存地址到相應(yīng)的內(nèi)存地址例例 10.4輸入輸入a,b,c3個整數(shù),按大小順序輸出個整數(shù)
31、,按大小順序輸出swap ( pt1 , pt2 )int *pt1 , *pt2 ; int p ; p = *pt1 ; *pt1 = *pt2 ; *pt2 = p ;exchange (int *q1, *q2 , *q3 ;) if (*q1 *q2) swap ( q1 , q2 ) ; if (*q1 *q3) swap ( q1 , q3 ) ; if (*q2 *q3) swap ( q2 , q3 ) ;main ( ) int a , b , c , *p1 , *p2 , *p3 ; scanf ( “ %d , %d , %d ”, &a , &b ,
32、 &c) ; p1 = &a ; p2 = &b ; p3 = &c ; exchange ( p1 , p2 , p3 ) ; printf ( “ n%d, %d, %dn ”, a , b , c );10.3 數(shù)組的指針和指向數(shù)組的指針變量數(shù)組的指針和指向數(shù)組的指針變量 C語言中,指針變量可以指向變量,也可以指向數(shù)組語言中,指針變量可以指向變量,也可以指向數(shù)組和數(shù)組元素和數(shù)組元素. 數(shù)組的指針數(shù)組的指針: 數(shù)組的起始地址數(shù)組的起始地址. 數(shù)組元素的指針數(shù)組元素的指針: 數(shù)組元素的地址數(shù)組元素的地址.一一.指向數(shù)組的指針變量的定義與賦值指向數(shù)組的指針變量的
33、定義與賦值 指向數(shù)組的指針變量的定義同指向變量的指針變量指向數(shù)組的指針變量的定義同指向變量的指針變量的定義相同的定義相同. 如如: int a10 ; int * p ; 若若: p = &a0 ; 則則 p 指向了指向了a 數(shù)組的第數(shù)組的第 0 號元素號元素. 由于由于數(shù)組名代表數(shù)組的首地址數(shù)組名代表數(shù)組的首地址(即起始地址即起始地址). 故故: p = &a0 ; 等價于等價于 p = a ; 也可也可: int a10 ; int *p = &a0 ; int * p = a ; 注意注意 int *p = &a0 ; 的含義是將數(shù)組首地址賦給指的含義是將
34、數(shù)組首地址賦給指針變量變量 p ,而不是賦給而不是賦給 ( *p ).二二. 通過指針引用數(shù)組元素通過指針引用數(shù)組元素 如如: int a10 , *p ; p = a ; 則則: (1) p a0的地址的地址; p + 1 a1的地址的地址; p + i ai的地址的地址. (2) *p = = a0 , *(p +1) = = a1 , *(p +i) = = ai 說明說明: 1. 數(shù)組元素在內(nèi)存中是連續(xù)存放的數(shù)組元素在內(nèi)存中是連續(xù)存放的,C語言語言規(guī)定規(guī)定,指針變量指針變量 p + 1 指向下一個元素指向下一個元素 (不是簡單的不是簡單的加加 1 ). &a0 1 320 a0
35、a1a9p2. ( p + i ) 表示指向表示指向 ai 的地址的地址, 而而 a + i 也表示也表示 ai 的地址的地址,故故 程序中程序中( p + i ) 等價于等價于a + i . 如如: p + 2 ; a + 2 ;3. 指向數(shù)組的指針變量可以帶下標(biāo)指向數(shù)組的指針變量可以帶下標(biāo). 如如: pi *(p +i) a數(shù)組數(shù)組 p p+1,a+1 p+i ,a+i p+9 ,a+9 a0 a1 ai a9 * *(p +i)綜上所述綜上所述: 數(shù)組元素的引用可以數(shù)組元素的引用可以: (假定假定: int a10 , *p = a ; )(1) 下標(biāo)法下標(biāo)法: 數(shù)組名數(shù)組名下標(biāo)下標(biāo) 或
36、或 指針變量名指針變量名下標(biāo)下標(biāo) ai pi(2) 指針法指針法: *(p +i) 或或 *(a +i) 思考:思考: 數(shù)組的指針數(shù)組的指針 和和 數(shù)組名有何數(shù)組名有何異同?異同?int a10 ,b10 , *p = a ; 相同點:相同點: p和和a都表示地址,都可以進行地址的運都表示地址,都可以進行地址的運算,如:算,如:p+1, a+1, p5, a5, *a 等等不同點:不同點: p是變量,可以被改變。而數(shù)組名是變量,可以被改變。而數(shù)組名a是是“常量常量”,只能引用不能被改變(賦值),只能引用不能被改變(賦值)p+1, a+3, p+ 可以,可以, a+ 錯錯p=p3;可以,;可以,
37、 a = a+3錯錯p = b; p=&b2 可以,可以, a = &b3 , a=b 錯錯例例 10.5 用四種方法輸出數(shù)組各元素用四種方法輸出數(shù)組各元素.(1)下標(biāo)法下標(biāo)法 main ( ) int a10 , i ; for ( i = 0 ; i 10 ; i + + ) scanf ( “ %d ”, &ai ) ; printf ( “ n” ) ; for ( i = 0 ; i 10 ; i + + ) printf ( “%d ”, ai ) ; (2)用數(shù)組名計算元素地址用數(shù)組名計算元素地址. main( ) int a10 , i ; for (
38、i = 0 ; i 10 ; i + + ) scanf ( “ %d ”, &ai ) ; printf ( “ n” ) ; for ( i = 0 ; i 10 ; i + + ) printf ( “%d ”, *(a +i) ) ; 例例 10.5 用四種方法輸出數(shù)組各元素用四種方法輸出數(shù)組各元素.(3)指針下標(biāo)指針下標(biāo) main ( ) int a10 , i , *p=a; for ( i = 0 ; i 10 ; i + + ) scanf ( “ %d ”, & pi ) ; printf ( “ n” ) ; for ( i = 0 ; i 10 ; i +
39、 + ) printf ( “%d ”, pi ) ; (4)指針計算指針計算 main( ) int a10 , i , *p=a; for ( i = 0 ; i 10 ; i + + ) scanf ( “ %d ”, p+i ) ; printf ( “ n” ) ; for ( i = 0 ; i 10 ; i + + ) printf ( “%d ”, *(p +i) ) ; main( ) int a10 , i , *p=a; for ( i = 0 ; i 10 ; i + + ) scanf ( “ %d ”, p+i ) ; 注意是注意是p+i不是不是&(p+i)
40、 printf ( “ n” ) ; for ( i = 0 ; i 10 ; i + + ) printf ( “%d ”, *(p +i) ) ; 思考:既然指針可以替代數(shù)組,那么上面的程序中思考:既然指針可以替代數(shù)組,那么上面的程序中是否可以省略掉數(shù)組定義,只使用指針呢?像下面是否可以省略掉數(shù)組定義,只使用指針呢?像下面這樣這樣:main( ) int i , *p; for ( i = 0 ; i 10 ; i + + ) scanf ( “ %d ”, p+i ) ; for ( i = 0 ; i 10 ; i + + ) printf ( “%d ”, *(p +i) ) ; 指
41、針指向不確定指針指向不確定即使指針指向確定,但系統(tǒng)只給指針分配了一塊即使指針指向確定,但系統(tǒng)只給指針分配了一塊內(nèi)存,只有這塊內(nèi)存才可以內(nèi)存,只有這塊內(nèi)存才可以“安全,合理安全,合理”使用使用的的如果有一塊連續(xù)的安全內(nèi)存可用,當(dāng)然可以不用如果有一塊連續(xù)的安全內(nèi)存可用,當(dāng)然可以不用數(shù)組數(shù)組注意上面條件,注意上面條件,“連續(xù)連續(xù)”,如果不連續(xù),又有什,如果不連續(xù),又有什么問題?么問題?注意幾點注意幾點: (1) 指針變量可以作自增指針變量可以作自增,自減運算自減運算. 如如: + + p , p . 而數(shù)組名不能作自增而數(shù)組名不能作自增,自減運算自減運算. 如如 a + + , a 等等, 均不合法
42、均不合法.因為因為數(shù)組名是常量數(shù)組名是常量. (2) 注意指針變量的當(dāng)前值注意指針變量的當(dāng)前值. 如如: 例例 10.6: main( ) int a10 , i , *p ; p = a ; for ( i = 0 ; i 10 ; i + + ) scanf ( “ %d ”, p+ ) ; printf ( “ n” ) ; for ( i = 0 ; i 10 ; i+ , p+ ) printf ( “%d ”, *p ) ; (3) 注意指針變量的運算注意指針變量的運算. 如如: int a10 , i , *p ; p = a ; 則則:a. p+ (或或 p+=1 ) 表示表示
43、 p 指向指向 a1 , 此時若執(zhí)行此時若執(zhí)行*p ,則則 取出取出 a1 元素的值元素的值.b. “*” 與與 “+ +” 同優(yōu)先級同優(yōu)先級,自右往左結(jié)合自右往左結(jié)合. 如如: *p+ + 等效于等效于 *(p+ + ) , 即先取即先取 p 所指向所指向變量的值變量的值, 再使再使 p + 1 . 而而 *(p + + ) 與與*(+ + p ) 的作用不同的作用不同.前者先取前者先取*p 的值的值,后使后使p + 1 ; 后者后者是先使是先使 p + 1 ,再取再取*p的值的值 .(*p)+ + d.表示使目標(biāo)變量的值加表示使目標(biāo)變量的值加 1 . 而不是指針變量而不是指針變量的值加的值
44、加 1。e. *(p + + ) 等價于等價于 ai + + . *(+ + p ) 等價于等價于 a+ + i 即先使即先使 p 自增自增,再作再作 * 運算運算.如如: main( ) int a100 , *p ; p = a ; while ( p a +100 ) printf ( “ %d ”, *p + + ) ; main( ) int a100 , *p ; p=a; while ( p a +100 ) printf ( “ %d ”, *p ) ; p + + ; 三三. 數(shù)組名作函數(shù)參數(shù)數(shù)組名作函數(shù)參數(shù) 數(shù)組名作函數(shù)參數(shù)時數(shù)組名作函數(shù)參數(shù)時,實際上是將實際上是將實參實參
45、數(shù)組的首地址傳給形參數(shù)組的首地址傳給形參。這樣實參數(shù)組與這樣實參數(shù)組與形參數(shù)組共占同一段內(nèi)存形參數(shù)組共占同一段內(nèi)存。使得在。使得在 調(diào)用函調(diào)用函數(shù)過程中,形參數(shù)組中元素值發(fā)生變化也數(shù)過程中,形參數(shù)組中元素值發(fā)生變化也就使實參數(shù)組的元素值隨之而發(fā)生變化。就使實參數(shù)組的元素值隨之而發(fā)生變化。如:如: main( ) int array10 ; f ( array , 10 ) ; f( arr , n ) int arr , n ; arrayarr1)實參傳遞給形參后實參傳遞給形參后arr和和arry指向同一內(nèi)存地址;指向同一內(nèi)存地址;2)將將“10”傳遞給形參傳遞給形參n后,界后,界定了形參數(shù)
46、組的范圍;定了形參數(shù)組的范圍;3)這種這種“數(shù)組名數(shù)組元素數(shù)組名數(shù)組元素個數(shù)個數(shù)”的參數(shù)形式是常用的。的參數(shù)形式是常用的。例例 10.7 將數(shù)組將數(shù)組 a 中中 n 個整數(shù)按相反順序存放個整數(shù)按相反順序存放.題意分析:題意分析: 本題的關(guān)鍵是最后交換的兩個元素的上下標(biāo)值的確本題的關(guān)鍵是最后交換的兩個元素的上下標(biāo)值的確定。即將第一個元素和最后一個元素對換定。即將第一個元素和最后一個元素對換,將第二個同倒將第二個同倒數(shù)第二個對換數(shù)第二個對換. .即兩兩對換即兩兩對換,直到直到:a (n 1) /2 與與 an int( n 1 ) / 2) 對換為止。其中對換為止。其中an int( n 1 )
47、/ 2) 與與an 1 ( n 1 ) / 2)等效。等效。 3 7 9 11 0 6 7 5 4 2 2 4 5 7 6 0 11 9 7 3imjvoid inv( x , n )int x , n ; int t ,i,j,m=(n 1)/2; for( i=0; i=m ; i+ + ) j = n1i; t = xi; xi = xj; xj = t ; return;main( ) static int i , a10 = 3,7,9,11,0,6,7,5,4,2 ; printf ( “ The original array : n ” ) ; for ( i = 0 ; i10
48、 ; i+ ) printf ( “ %d ”, ai ) ; printf ( “ n ” ) ; inv ( a , 10 ) ; printf ( “ The array has been inverted : n ” ) ; for ( i = 0 ; i 10 ; i + + ) printf ( “ %d ”, ai ) ; printf ( “ n ” ) ;例10.8 從 10 個數(shù)中找出其中最大值和最小值int max , min ; void max_min_value (int array , int n ) int *p , *array_end ; array_end
49、 = array + n ; max = min = *array ; for ( p=array+1; pmax ) max = *p ; else if( *p min ) min = *p ; main( ) int i, number10 ; printf ( “ enter 10 data n ”) ; for( i=0; i10; i+ ) scanf ( “ %d ”, &numberi ) ; max_min_value( number, 10 ) ; printf ( “max = %d , min = %d n ”, max , min ) ;等效于等效于 *(ar
50、ray + 0) 即即 array0此例也可改用指針變量來傳送地址此例也可改用指針變量來傳送地址,程序可改為程序可改為:int max , min ;void max_min_value (int * array , int n ) int *p , *array_end ; array_end = array + n ; max = min = *array ; for( p = array + 1 ; p max ) max = *p ; else if ( *p min ) min = *p ; return ;main( ) int i , number10 , *p ; p=numb
51、er ; printf ( “ enter 10 data n ”) ; for ( i = 0 ; i 10 ; i + + , p + + ) scanf ( “ %d ”, p ) ; printf ( “ the 10 data : n ” ) ; for(p=number, i=0; i10; i+, p+ ) printf( “%d”, *p ) ; p=number ; max_min_value( p , 10 ) ; printf ( “ n max = %d , min = %d n ”, max , min ) ; for(p=number;p(number+10);p+
52、)等效于:等效于:不使用全局變量void max_min_value (int * array , int n , int* max,int* min; ) int *p , *array_end ; array_end = array + n ; max = min = *array ; for( p = array + 1 ; p *max ) *max = *p ; else if ( *p *min ) *min = *p ;main( ) int i , number10 , max , min; for ( i = 0 ; i 10 ; i + + , p + + ) scanf
53、( “ %d ”, &number i ) ; max_min_value( number , 10, &max, &min ) ; printf ( “max=%d , min=%d n ”, max , min ) ; 數(shù)組名是地址, 故可以傳送給 int * array 綜上所述綜上所述,對于實參數(shù)組對于實參數(shù)組,想在被調(diào)函數(shù)中想在被調(diào)函數(shù)中改變此數(shù)組改變此數(shù)組元素的值元素的值,實參與形參的對應(yīng)關(guān)系實參與形參的對應(yīng)關(guān)系可以如下可以如下:(1) 二者都用數(shù)組名二者都用數(shù)組名 main ( ) int a10; f( a, 10 ); f( x, n) int x ,
54、 n ; 特點特點: a 和和 x 數(shù)組共用同數(shù)組共用同一段內(nèi)存單元。一段內(nèi)存單元。 (2) 實參為數(shù)組名實參為數(shù)組名,形參用形參用指針變量指針變量.main ( ) int a10 ; f( a,10); f( x, n )int *x , n ; 特點特點: 實參將數(shù)組的首地址傳給實參將數(shù)組的首地址傳給形參指針變量形參指針變量,通過指針變量指通過指針變量指向數(shù)組中的任一元素向數(shù)組中的任一元素,進而作相進而作相應(yīng)的處理。應(yīng)的處理。(3) 二者都用指針變量。二者都用指針變量。 main ( ) int a10 , *p ; p = a ; f ( p , 10 ) ; f( x , n ) i
55、nt *x , n ; 特點特點: 先使先使 p 指向指向 a 數(shù)組數(shù)組,再將再將 p 傳給傳給 x , 使使 x 也指向也指向 a 數(shù)組數(shù)組,從而進行處理從而進行處理.(4)實參為指針變量實參為指針變量,而形參而形參為數(shù)組名。為數(shù)組名。 main ( ) int a10 , *p ; p = a ; f ( p , 10 ) ; f( x , n ) int x , n ; 特點特點:利用指針變量將利用指針變量將 a 數(shù)組數(shù)組的首地址傳給的首地址傳給 x 數(shù)組數(shù)組.使兩數(shù)組使兩數(shù)組共用同一段內(nèi)存單元共用同一段內(nèi)存單元.利用利用xi值值的變化的變化,使使ai的值也發(fā)生變化的值也發(fā)生變化. 注意
56、注意: 在上述四種處理方式中在上述四種處理方式中,當(dāng)用當(dāng)用指針變量作實指針變量作實參時,必須先使指針變量有確定的值,即指向一參時,必須先使指針變量有確定的值,即指向一個已定義的數(shù)組。個已定義的數(shù)組。四、四、 指針與二維數(shù)組指針與二維數(shù)組1、指針與二維數(shù)組、指針與二維數(shù)組 一個數(shù)組的名字代表該數(shù)組的首地址,并一個數(shù)組的名字代表該數(shù)組的首地址,并可看成是地址常量,這一規(guī)定對二維數(shù)組或更高可看成是地址常量,這一規(guī)定對二維數(shù)組或更高維數(shù)組同樣適用。維數(shù)組同樣適用。若有定義:若有定義: float *p, d35;則:則:d24d23d22d21d20d14d13d12d11d10d04d03d02d0
57、1d00d2d1d0d2. 二維數(shù)組元素和二維數(shù)組元素的地址二維數(shù)組元素和二維數(shù)組元素的地址假設(shè)數(shù)組名為假設(shè)數(shù)組名為a,起始地址設(shè)為起始地址設(shè)為200 int a34=1,3,5,7,9,11,13,15,17,19,21,23;則:則: a代表整個二維數(shù)組的首地址,即第代表整個二維數(shù)組的首地址,即第0行的首地址行的首地址 a+1是數(shù)組是數(shù)組a第第1行首地址行首地址(208) a0,a1,a2是二維數(shù)組中三個一維數(shù)組的名字(地是二維數(shù)組中三個一維數(shù)組的名字(地址),是第址),是第0行,第行,第1行,第行,第2行的首地址,即:行的首地址,即:a0=a+0、a1=a+1、a2=a+2 ai+j是第
58、是第i行行j列的地址列的地址 *(ai+j)是該地址存儲的值,是該地址存儲的值, 即即aij考慮考慮 *(a2+3)=?a0a1a2a數(shù)組數(shù)組a (200)a+1a+2(216)注意:注意: ai和和*(a+i)無條件等價無條件等價 a+i、ai、*(a+i)、&ai0均表示第均表示第i行首地址;行首地址; &aij、 ai+j、*(a+i)+j都是第都是第i行行j列元素的列元素的地址地址; aij、 *(ai+j)、*(*(a+i)+j)都是第都是第i行行j列元素的列元素的值值;例例: 將將a矩陣與矩陣與b矩陣相加矩陣相加,和存入和存入c矩陣。矩陣。int i,j;main(
59、 ) int *p, a34, b34, c34; printf(The value of a:n); for(i=0; i3; i+) for(j=0; j4; j+) scanf(%d,ai+j); printf(The value of b:n); for(i=0; i3; i+) for(j=0; j4; j+) scanf(%d, *(b+i)+j); matrix(*a, b0, &c00); printf(The value of c:); for(i=0,p=c0;pc0+12;p+,i+) if (i%4=0) printf(n); printf(%-4d,*p);
60、matrix(int *x, int *y, int *z) for(i=0; i3; i+) for(j=0; jy) z=x; else z=y; return( z );main ( ) int max( int, int) ; int a ,b, c ; int (*p)(int, int); scanf( “ %d ,%d ” , &a ,&b) ; p = max; c = p(a,b); printf(“ max=%d”,c ) ; 注意注意:int (*p)(int, int); 不能寫成不能寫成int (*p)( );否則導(dǎo)致否則導(dǎo)致 max 不能賦給不能賦給 p, 因為二者因為二者類型不一致類型不一致說明說明: 1. C語言中語言中,函數(shù)調(diào)用可以有兩種形式函數(shù)調(diào)用可以有兩種形式.即即 函數(shù)名調(diào)用和函函數(shù)名調(diào)用和函數(shù)指針調(diào)用數(shù)指針調(diào)用.2. (*p ) ( ) 表示一個指向函數(shù)的指針變量,用于存放函數(shù)表示一個指向函數(shù)的指針變量,用于存放函數(shù)的入口地址的入口地址. 若把某一個函數(shù)的入口地址賦給它若把某一個函數(shù)的入口地址賦給它,它就指向它就指向該函數(shù)該函數(shù).即在程序中一個函數(shù)指針變量可以先后指向不同即在程序中一個函數(shù)指針變量可以先后指向不同的函數(shù)的函數(shù).3. 對于指向函數(shù)的指針變量作自增或自減運算均無意義對于
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- DB42-T 2343-2024 城鎮(zhèn)人行天橋設(shè)計標(biāo)準(zhǔn)
- (2篇)2024 年幼兒園大班教師年度考核表個人總結(jié)
- 美國跨境電商市場情況
- 學(xué)生營養(yǎng)日活動方案
- 二零二五年環(huán)保廚房設(shè)計與施工承包協(xié)議5篇
- 九年級語文上冊第六單元檢測卷作業(yè)課件新人教版
- 第二章中國歷史常識
- 二零二五年駕校場地租賃與市場拓展合作合同3篇
- 四年級上語文課件-田園詩情-蘇教版(精)
- 冪級數(shù)學(xué)習(xí)教學(xué)教案
- 廣東省惠州市2024-2025學(xué)年高一上學(xué)期期末考試英語試題(含答案)
- 醫(yī)院骨科2025年帶教計劃(2篇)
- 2024-2025學(xué)年北京市東城區(qū)高一上學(xué)期期末考試數(shù)學(xué)試卷(含答案)
- 環(huán)境保護應(yīng)急管理制度執(zhí)行細則
- 2024-2030年中國通航飛行服務(wù)站(FSS)行業(yè)發(fā)展模式規(guī)劃分析報告
- 機械制造企業(yè)風(fēng)險分級管控手冊
- 非計劃性拔管風(fēng)險評估表二
- 外貿(mào)財務(wù)對賬單英文版-帶公式
- 北教版四年級綜合實踐下冊 第十一課飲料中的學(xué)問
- TCVN22-越南建筑防火規(guī)范(中文版)
- 英語蘇教版譯林五年級下冊單詞默寫表
評論
0/150
提交評論