




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第6章 指針6.1 指針概念 6.2 指針變量的定義和使用6.3 指針運算6.4 指針與數組及字符串 6.5 指針數組和多級指針 6.1 指針概念變量的直接地址訪問(指針常量的概念引入)查看VC6.0代碼的反匯編變量的間接地址訪問(指針變量的概念引入)區(qū)分指針變量的定義和建立(何為“建立指針”)指針變量的靈活性指針變量的兩個空間概念(自身空間+目標空間)2/26.1 指針概念6.1.1 變量的地址(指針常量) 程序一旦被執(zhí)行,則該程序的指令、常量和變量等都要存放在計算機的內存中。計算機的內存是以字節(jié)為單位的一片連續(xù)的存儲空間,每個字節(jié)都有一個編號,這個編號就稱為內存的地址。注意 : 存儲單元的
2、地址和它里面存放的內容完全是兩回事。 地址值相當于該內存字節(jié)在整個內存條中的序號,從0開始遞增,地址值n的含義為前面有n個字節(jié)&aa 如果在程序中定義了一個變量,系統(tǒng)會根據變量的數據類型給它分配一定字節(jié)數的內存空間。例如: 在一個源程序中定義了如下變量: double d = 1.0; long int c = 8;int b = 100; short a = 3;1001002100410083100100081. 16位系統(tǒng)給變量a分配的地址是0 x1000,變量b分配的地址是0 x1002,變量c分配的地址是0 x1004變量d分配的地址是0 x1008,得到如上圖所示的內存示意圖。4B
3、2B2B2/4在VC6.0中,變量a、b、c、d的地址分別為ebp-*,對應的空間為:dword ptr ebp-8dword ptr ebp-0chdword ptr ebp-10hword ptr ebp-14h注:便于講解方便,0 x1000為假設值注意這里相差4字節(jié)a變量為short型,why 4B?注意這里可以看出在源碼中的變量名,在目標碼中都是地址,這就是常說的“直接地址訪問”6.1.2 指針變量 除了前面介紹的普通變量之外,還使用另外一種特殊性質的變量,即指針變量。 指針變量是存放地址的變量。它和普通變量一樣占用一定的存儲空間。但是,它與普通變量不同之處在于,指針變量的存儲空間中
4、存放的不是普通的數據,而是一個地址,例如一個變量的首地址。 設某指針變量的名字是px,同時存在另外一個名字為x的普通變量,將變量x的地址送入指針px的存儲區(qū)域,即px的內容就是變量x的地址,如下圖所示:因此我們可以看出,訪問一個變量有兩種方法:(1)通過變量本身直接訪問,x,即直接地址訪問(2)通過指向該變量的指針間接訪問,*px,即間接地址訪問2/6指針變量自身空間重要:任一個指針變量都有值,哪怕是殘值,因此,指針變量都有指向。但不一定其指向合理/安全!指針變量指向的目標變量空間,簡稱:指針的目標空間1、什么叫建立指針2、忘記給指針變量賦值的害處!“野指針”3、指針變量使用的規(guī)則定義指針變量
5、指明該指針只能指向哪種類型變量建立指針明確該變量從此時開始指向哪個變量借助指針變量間接訪問其指向的對象通過給指針變量賦值來確定指向關系建立指針建立指針指針變量空間訪問時用px目標變量空間訪問時用x或*px3/9指針變量的靈活性:通過多次建立指針,使得該指針變量在不同時刻指向不同變量!何為野指針:1、目標空間位置不確定,如指針變量定義時未賦值,其值為殘值2、指向位置確定,但該位置的內存空間屬于哪一個變量,不確定。比如pi指針開始時指向i,隨后i變量內存釋放,但pi仍取值&i,但目標空間已經不是i定義指針變量時常常賦初值為NULL6.2 指針變量的定義和使用6.2.1 指針變量的定義及初始化 1
6、. 指針變量的定義 指針變量在程序中使用之前,必須進行定義。 *指針名;例如: int *px; char *name; static int *pa; 上面定義了名字為px,name和pa的三個不同類型指針。變量名由用戶命名,使用字符的起名規(guī)則與變量名相同。1/10 指針變量的存儲類型是指針變量本身的存儲類型。它與普通變量一樣,分為: auto(在函數內部定義,可以缺?。?register static extern(在函數外部定義時可以缺?。?不同存儲類型的指針使用的存儲區(qū)域不同,這與普通變量完全相同。指針存儲類型和指針在程序中的定義位置決定指針的壽命和可見性。即指針變量也分為內部的和外部
7、的,全局的和局部的。1/112 . 指針變量的初始化/賦初值建立指針 指針變量在定義的同時,也可以被賦予初值,初始化時賦予它的初值必須是地址量: *指針名=初始地址值;例如: int *pa=&a;它把變量a的地址作為初值賦給了int型指針pa。注意:從表面上看,似乎把一個初始地址量賦給了指針的目標變量*pa。其實不然,初始化形式中*pa=&a不是一個運算表達式,而是一個說明性語句,說明指針pa的值等于a的地址。等價于int *pa;pa=&a;指針的類型中包含哪些信息?int* 指針自身類型目標變量類型2/13定義語句中的*是指針類型標記符,而不是運算符 下面的例子是把變量n的地址賦予指針p
8、,并且把已經初始化好的指針p賦給指針q: int n; int *p=&n; int *q=p; 指針變量中只能存放地址,不要將一個整型量賦給一個指針變量,下面的賦值是不合法的: int *pointer=1000;下面的賦值合法但很危險 int *pointer=(int *)1000;1/14例6.1 指針的概念#include void main() int a; int *pa = & a ; /定義并建立指針pa a = 10; printf(a:%dn,a); printf(*pa:%dn,*pa); printf(&a:%x(HEX)n,&a); printf(pa:%x(HEX
9、)n,pa); printf(&pa:%x(HEX)n,&pa);運行結果:a:10*pa:10&a:fff4(HEX)pa:fff4(HEX)&pa:fff2(HEX)注意: 上述輸出結果中,后三行的結果每次運行時可能不一樣,但第一行和第二行輸出值應該是相等的。一旦建立指針a和*pa等價若未建立,則二者不等價3/17例 求地址量數據長度的程序#include void main( ) / 定義字符串數組str,定義一char型指針ps指向它 char str = abcdefghi, *ps = str; / 定義int型變量i,并定義一個int型指針pi指向它 int i = 6, * p
10、i = &i; / 定義float型變量f,定義一float型指針pf指向它 float f = 6.4f, *pf = &f; / 定義double型變量d,和一double型指針pd指向它 double d = 3.1415926, *pd = &d; printf(1) size of strings pointer is %d byte = %d bits.n, sizeof(ps), 8 * sizeof(ps); printf(2) size of INTs pointer is %d bytes = %d bits.n, sizeof(pi), 8 * sizeof(pi); p
11、rintf(3) size of FLOATs pointer is %d bytes = %d bits.n,sizeof(pf), 8 * sizeof(pf); printf(4) size of DOUBLEs pointer is %d bytes = %d bits.n, sizeof(pd), 8 * sizeof(pd); 該程序在Borland C+ V3.1上的運行結果為:(1) size of strings pointer is 2 byte = 16 bits.(2) size of INTs pointer is 2 bytes = 16 bits.(3) size
12、 of FLOATs pointer is 2 bytes = 16 bits.(4) size of DOUBLEs pointer is 2 bytes = 16 bits.等價于sizeof(char *)3/203. void指針(void *) void型指針變量:用來指向一種抽象數據的指針類型,但不指明它指向哪種具體的數據類型,稱為“無類型指針”。 定義的方法是在該指針變量的定義語句中,用void作為目標數據類型,即: void * 指針變量名; 定義時目標數據類型指定為void型,則可以將已定義的各種類型指針直接賦給void型指針;將void型指針賦給其他各種類型指針時,必須采用
13、強制類型轉換,將它變成指向相應數據類型的指針。抽象指針 定義抽象指針的目的? 2/22int *pIntArr;pIntArr=(int *)malloc(10*sizeof(int);pIntArr=new int10;int *其返回值類型為void *6.2.2 指針的使用1. 取地址運算符&和取內容運算符*(1).取地址運算符& 單目&是取地址運算符,單目&運算表達式的形式為: &變量例:設變量說明為 int x; char y; double z;則地址表達式&x,&y和&z的結果類型分別為: int*(整型指針), char*(字符型指針) double*(雙精度浮點型指針)。1/
14、23 由于數組名和常量不是左值表達式,而寄存器變量沒有存儲地址,因此數組名、常量和寄存器變量均不能做單目&的操作對象。 例:設變量說明為 int i ,a 4; register int k;&i,&ai,&a0(或a):合法的地址表達式其類型均為int*(整型指針)。&k,&a :非法1/24(2)指針運算符 * 單目*是間接訪問運算符。通過指針間接訪問指針所指對象(即目標變量),而不是通過變量名字訪問變量,稱為間接訪問。間接訪問的表示形式為: * 指針 例如: char c, *pc = &c; *(&c) = a; *pc = a; c = a;取目標變量內容的運算符2/26(3)單目*
15、和 &的運算關系 單目*和 &互為逆運算,它們之間的運算關系可表達為: *(& 左值表達式) 等價于 左值表達式 &(*地址表達式) 等價于 地址表達式上面兩個式子表明: 二者為互逆運算。但要注意:&后面必須跟隨變量名*后面必須跟隨指針(常量或變量均可)1/272. 指針的正確用法 使用指針的正確方法是:(1) 必須按被間接訪問變量的類型來定義指針變量;必須用被間接訪問變量的地址給指針變量賦值(或用指針變量初始化方式),使指針指向確定的目標對象,然后才能使用指針來引用變量。 下面這個代碼段說明了一個極為常見的錯誤: int *p; *p = 5;沒有辦法預測5這個值存放在什么地方,也不會“創(chuàng)建
16、”用于存儲整型值5的內存空間。3/30通常定義時不確定指向時,暫時賦值為NULL 3.NULL指針 NULL指針的概念是非常有用的。它提供了一種方法,表示某個特定的指針目前并未指向任何目標變量。 ANSI C+標準定義NULL指針,它作為指針變量的一個特殊狀態(tài),表示不指向任何東西。要使一個指針變量為NULL,可以給它賦一個零值。為了測試指針變量是否為NULL,可以將它和零進行比較。NULL指針并未指向任何東西,對一個NULL指針進行取內容運算*是非法的,在對指針進行取內容運算*之前,首先必須確保它并非NULL指針。1/316.3 指針運算 由于指針是持有地址的變量這一特性,指針的運算與某些普通
17、變量的運算在種類上和意義上都是不同的。指針運算的種類是有限的,它只能進行: 算術運算 關系運算 賦值運算6.3.1 指針的算術運算 不是簡單的+ -*/運算,其結果與指針的類型有關,準確地說是與指針類型中的目標數據類型(即去掉一個*后的類型)有關。 設p1和p2是指向具有相同數據類型的一組數據的指針變量,n是整數,則指針可以進行的算術運算有如下幾種: p1+n, p1-n, p1+, +p1, p1-, -p1, p1-p23/341. 指針與整數的加減運算 指針作為地址加上或減去一個整數n,仍為一個指針含義:以指針當前指向位置為基準,向高地址端或低地址端跳過n個目標類型對象后,得到一個新的指
18、向。 3/37各種指針變量進行加1運算后的地址變化量 指針類型指針加1運算后的地址變化量char * ptr;1short *ptr;2signed short *ptr;2unsigned short *ptr;2int *ptr;2signed int *ptr;2unsigned int*ptr;2longint*ptr; 4signed long int*ptr;4unsigned long int *ptr;4float *ptr;4double *ptr;8long double *ptr;102. 指針自增、自減運算 指針+、-單目運算也是地址計算,它具有上述的計算特點,指針的+
19、、-單目運算是指針變量本身值的變化,變化前指向某個對象,變化后將指向另一個對象。指針+運算后就指向了下一個同類型數據的位置,- -運算后就指向上一個同類型數據的位置。運算后指針變量本身值的變化量取決于它指向的目標數據類型。 3/40例如,指針px指向int型(2字節(jié)長)數據,py的內容假設為地址值f000,當執(zhí)行px+后,py的內容加2,成為f002,它是下一個數據的地址。指針加一前后的變化如圖所示:3/43 y= * px+; 相當于: y= * (px+); 但要注意,不是先移動px指針,再取其指向的目標!這里是后置運算。因此該表達式的運算順序是,訪問當前指針指向的目標,把目標變量的值賦予
20、y,然后,px加1后得到新的px值,指向下一個目標。 2/45 【例】看一個用指針運算實現字符串復制函數的程序的例子:char *strcpy(char *dest, char *src) char *temp=dest; while( (*dest+=*src+)!=0 ); return temp; /返回目的字符串的首地址 這是標準函數庫中的函數,函數體中使用了指針后置運算: (*dest+=*src+)!=0; 運算過程:把src的目標變量的值賦予dest的目標變量,然后判斷賦值表達式的結果值,即賦的值是否不等于0。dest和src的值使用后執(zhí)行加一運算,分別指向下一個目標。函數中循環(huán)
21、體是空語句。5/503. 指針的相減 設指針p和q是指向同一組數據類型一致的數據,則p-q運算的結果值是兩指針指向的地址位置之間的數據個數。由此看出,兩指針相減實質上也是地址計算。它執(zhí)行的運算不是兩指針持有的地址值相減,而是按下列公式得出結果: 式中(p)和(q)分別表示指針p和q的地址值,所以,兩指針相減的結果值不是地址量,而是一個整數。 3/53例6.3 統(tǒng)計輸入字符串的字符個數#include void main() char s20; char * p; printf (“Enter a string (less than 20 characters):n”); scanf (“ %s
22、”,s); p=s; /將字符指針指向字符數組的入口 while (*p!=0) /逐個移動字符指針直到字符串結束 p+; printf (“The string length:%dn”,p-s) ; /p-s就是字符串的長度運行結果:Enter a string (less than 20 characters):abcdefghiThe string length :94/57while (*p+!=0) ;改成上面代碼后p-s還是串長?!程序運行過程示意圖如圖所示:1/586.3.2 關系運算 兩個指向同一組類型相同數據的指針之間可以進行各種關系運算。兩指針之間的關系運算表示它們指向的地
23、址位置之間的關系。 對于兩指針p1和p2間的關系表達式: p1p2若p1指向高地址空間,p2指向低地址空間,該表達式結果值為1,反之為0。兩指針相等的概念是兩指針指向同一位置。 指向不同數據類型的指針之間的關系運算是沒有意義的。指針與一般整數變量之間的關系運算也是無意義的。指針的有效性判斷: 指針可以和NULL指針之間進行等于或不等于的關系運算,即: p=NULL或p!=NULL它們用于判斷指針p是否為一個空指針。2/60(void *)0)6.3.3 指針的賦值運算 向指針變量賦值時,賦的值必須是地址常量或同類型的其他指針變量,不能是整數。指針賦值運算常見有以下幾種形式:(1)把一個變量的地
24、址賦予一個指向相同數據類型的指針 例如: char c, *pc; pc=&c;6.3.3 指針的賦值運算 向指針變量賦值時,賦的值必須是地址常量或同類型的其他指針變量,不能是整數。指針賦值運算常見有以下幾種形式:(1)把一個變量的地址賦予一個指向相同數據類型的指針 例如: char c, *pc; 正確: pc=&c;錯誤:int i;char *pc;pc=&i;(3)把數組的入口地址賦予指向相同數據類型的指針例如: char name20, *pname; pname=name;(2)把一個指針的值賦予指向相同數據類型的另一個指針 例如: int i,*p, *q; q=&i; /q指向
25、一個確定目標ip=q;10/70(4)動態(tài)內存分配 在C+中,對于定義的每一個變量,系統(tǒng)都自動在計算機中分配一個或多個字節(jié)單元以存放將要保存的變量值。 當程序所要處理的某種數據無法確定其數據量時,便需要在程序運行期間動態(tài)地分配存儲空間,所以我們要在程序的運行過程中,現場判斷實際數據的數據量,并分配內存;當處理完所要處理的數據時,再將這些內存釋放。 為了實現動態(tài)存儲技術,標準函數庫特設置了一對標準函數,它們的原型在malloc.h中并用到stdlib.h。因此,在使用它們的程序開頭處,必須寫有: #include #include /或malloc.h(VC6) 它們的原型是: void * m
26、alloc(unsigned size); void free(void * ptr); 2/721)由malloc( )函數所分配的內存空間放在數據區(qū)的堆 (Heap)中。如圖所示:程序代碼區(qū)存放外部變量和靜態(tài)變量堆區(qū)存放自動變量和函數的形參數據區(qū)棧區(qū)靜態(tài)存儲區(qū)動態(tài)存儲區(qū)2) malloc( )函數有一個無符號整數型的形參size,用來指定所分配內存空間的大?。ㄒ宰止?jié)為單位給出)。 對字符串都是采用表達式“strlen(“字符串”) + 1”或 “strlen(指向字符串的指針) + 1”作為實參。其中,加1個字節(jié)是用來存放字符串的結尾符0。2/723)當malloc( )函數執(zhí)行成功時,其
27、返回值是大小為size的內存空間首地址,可采用地址賦值操作把它的返回值賦給一個指向相同數據類型的指針變量,這樣就生成了一個新的變量,稱為“動態(tài)變量”,該指針變量名就是動態(tài)變量名;當它執(zhí)行失敗時將返回一個空指針。因此在使用malloc( )函數時,必須檢測其返回值不為空指針,不然可能因堆區(qū)的內存資源耗盡而出錯。其一般格式為:if(指針名 = (類型 * )malloc(空間大小) = NULL) 出錯處理操作 或簡化寫成:if( ! (指針名 = (類型 * )malloc(空間大小) ) 出錯處理操作 出錯處理操作,常包含 exit(1);該動態(tài)變量又被稱作“匿名堆對象”,指針是其等價名,要求
28、指針值不能改變,一旦改變,則指針不再作為匿名堆對象的等價名4/774)由于指針函數malloc( )的返回值是無類型指針(void * 型),把void型指針賦給其他各種非void型指針時,還必須用強制類型轉換,把它的數據類型轉換成與“指針名”相同的數據類型。 5)free( )函數用來釋放由malloc( )函數在堆區(qū)中所分配的內存空間,以便這些內存空間成為再分配時的可用空間。6)free( )函數的形參ptr也是無類型指針,它專門用來接受malloc( )函數在堆區(qū)中所分配的內存空間首地址,對其他地址量將不發(fā)生作用,因此,free( )函數是malloc( )函數的配對物,即在整個源程序內,它們是成對出現的。4/817)free僅僅回收堆對象所占空間的使用權,被free的堆對象原來的數據遺留在內存中,不會被清0處理。一旦free成功執(zhí)行,從那刻起被釋放的內存空間即可能再次部分或全部地被分配給另外的堆對象。因此,原有的“動態(tài)變量”將不存在,對應的指針也將不再有意義。但指針變量仍然存在,其值仍然為原值,但已經變化成“野指針”。8)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 創(chuàng)業(yè)城物業(yè)合同范本
- 糾紛收樓合同范本
- 合同范本寫作
- 光纖外包安裝合同范例
- 代理食品的合同范本
- 合同范本中英對照
- 買賣新房子合同范本
- 合同范本員工拒續(xù)簽合同
- 合金采購合同范例
- it行業(yè)員工合同范本
- 2025年舞蹈培訓機構學員培訓合同范本
- 2025年保險銷售業(yè)務人員崗位職業(yè)技能資格知識考試題(附答案)
- 兒科護理模擬考試題與參考答案
- 2025年南網數字集團公開選聘高頻重點模擬試卷提升(共500題附帶答案詳解)
- 西門子S7-1200 PLC應用技術項目教程(第3版) 考試復習題
- 注意缺陷與多動障礙疾病科普幼兒心理健康教育課件
- 人工智能在招聘行業(yè)的應用
- 課件:《科學社會主義概論(第二版)》第一章
- 水利行業(yè)知識培訓課件
- 區(qū)域臨床檢驗中心
- 2025-2030年中國人力資源服務行業(yè)全國市場開拓戰(zhàn)略制定與實施研究報告
評論
0/150
提交評論