版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第六章第六章 指針指針 指針是C+ 提供的一種頗具特色的數(shù)據(jù)類型,允許直接獲取和操縱數(shù)據(jù)地址,實(shí)現(xiàn)動態(tài)存儲分配。 指針是C和C+的精華所在,也是C和C+的一個十分重要的概念。 主要內(nèi)容:主要內(nèi)容: 指針的概念; 指針數(shù)據(jù)對象及其定義; 指針運(yùn)算; 指針數(shù)據(jù)對象的引用; 重點(diǎn):重點(diǎn): 指針的概念指針的概念 利用指針實(shí)現(xiàn)動態(tài)存儲分配(動態(tài)數(shù)組) 指針運(yùn)算;指針運(yùn)算; 課堂時數(shù):課堂時數(shù):67學(xué)時學(xué)時 內(nèi)存操作函數(shù)和動態(tài)存儲分配。內(nèi)存操作函數(shù)和動態(tài)存儲分配。上機(jī)時數(shù):上機(jī)時數(shù):23學(xué)時學(xué)時 課外上機(jī)時數(shù):課外上機(jī)時數(shù):23學(xué)時學(xué)時 6.1 指針的概念指針的概念1. 什么叫指針什么叫指針 一個數(shù)據(jù)對象
2、的內(nèi)存地址稱為該數(shù)據(jù)對象的指針 。 指針可以表示各種數(shù)據(jù)對象,例如:簡單變量、數(shù)組、數(shù)組元素、結(jié)構(gòu)體甚至函數(shù)。 換句話說:指針具有不同的類型,可以指向不同的數(shù)據(jù)存儲體。 int *point1,a=123,b=567; double point220; point1=&a; point1和point2都是指針; point1 a變量a的地址123 例6-1 分析下面的變量說明語句和賦值表達(dá)式: 執(zhí)行point1=&a操作后,point1存放變量a的地址,它指向變量a 的存儲空間。如下圖所示:注意:指針中的內(nèi)容是可以動態(tài)改變的,例如point1原來指向變量a,當(dāng)執(zhí)行了point1
3、 = &b操作后,即指向變量b: point2 雙精度型數(shù)組的存儲空間 point2數(shù)組的首地址 point1 b變量b的地址567 point2是數(shù)組名,又是指向數(shù)組第一個元素的指針,如下圖所示:2 指針的作用指針的作用(1) 實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),例如數(shù)組、鏈表、實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),例如數(shù)組、鏈表、隊(duì)列和堆棧等;隊(duì)列和堆棧等; (2)能方便地表示和處理字符串;)能方便地表示和處理字符串; 例如: char s120=a,b,0,*sp1; sp1=s1;/s1和sp1都代表字符串 “ab” (3) 實(shí)現(xiàn)動態(tài)存儲分配;實(shí)現(xiàn)動態(tài)存儲分配; 對于程序中所包含的大存儲量的數(shù)據(jù)對象,一般用預(yù)先
4、定義的指針變量來表示,當(dāng)實(shí)際使用時才臨時申請實(shí)際的存儲空間,使用完畢立即釋放。(4) 在函數(shù)之間進(jìn)行數(shù)據(jù)的雙向傳遞。在函數(shù)之間進(jìn)行數(shù)據(jù)的雙向傳遞。 指針變量所占的內(nèi)存空間與所表示的數(shù)據(jù)對象的存儲空間相比實(shí)在是微乎其微,因?yàn)樗皇怯脕泶娣艑?yīng)空間的首地址,而不是存放數(shù)據(jù)本身,所以可以節(jié)省大量的存儲空間,提高內(nèi)存空間的利用率。 將形參定義成指針類型,對應(yīng)的實(shí)參必須是某個數(shù)據(jù)對象的地址或首地址,也即采用傳地址的方式,這樣就可以實(shí)現(xiàn)數(shù)據(jù)的雙向傳遞。 3指針類型指針類型 指針類型屬于非標(biāo)準(zhǔn)類型,其取值是所表示的數(shù)據(jù)對象的內(nèi)存地址,所以其值域是內(nèi)存地址集。 指針類型用來定義各種類型的指針變量,例如整型指針
5、、字符指針等等。其語法如下: * 類型標(biāo)識符,是指針類型的基類型,也即指針?biāo)赶虻臄?shù)據(jù)對象的類型。 *,作用在各個標(biāo)識符上,表示該標(biāo)識符所標(biāo)識的變量是指針變量。例 6-2 分析說明語句:int *a,b;。 該語句既定義了整型指針int *,同時又聲明了整型指針變量a和整型變量b。 指針類型定義和指針變量聲明是同時進(jìn)行的。 6.2 聲明指針變量聲明指針變量 1. 指針變量指針變量 用變量說明語句來聲明指針變量,其語法如下:解釋:解釋: *,*, *; 類型標(biāo)識符:用來指明指針類型的基類型,可以是基本類型,例如int,char,double等等,也可以是結(jié)構(gòu)類型,例如數(shù)組、結(jié)構(gòu)體、文件等等。 標(biāo)
6、識符:標(biāo)識指針數(shù)據(jù)對象,被標(biāo)識的對象可以是基本變量、數(shù)組、結(jié)構(gòu)體變量、函數(shù)等。 所謂指針變量就是類型為指針類型的變量。2指針變量的作用域指針變量的作用域 指針變量也有全局和局部之分: 在函數(shù)外部聲明的指針變量是全局的;在函數(shù)內(nèi)部聲明的指針變量是局部于該函數(shù)的。 3實(shí)例實(shí)例 例6-4 分析和比較語句char s1,s2100,*s3,*s4100;所聲明的四種不同數(shù)據(jù)對象。int *x, *y,z; 例6-3 在函數(shù)中聲明三個變量x,y,z,其中x、y是整型指針,z是整型變量,對應(yīng)的語句如下: 上面的語句定義了四個變量: 例如,執(zhí)行如下的操作序列后,則s2等價于s3:s1是字符型變量,用來存放單
7、個字符 ;s2是字符數(shù)組,最多可以存放100個字符; s3是字符型指針變量,用來存放字符數(shù)據(jù)的內(nèi)存地址或字符串的首地址。如果其中存放的是字符串的首地址,則它指向一個字符串,或者說它代表一個字符串;strcpy(s2,abcd);s3=s2; s2,s3兩者的關(guān)系如下圖所示: s2s3abcd s4是字符型指針數(shù)組,最多可以存放100個字符串的指針(地址),也即每一個元素都可能指向一個字符串,如下圖所示: 4. 指針變量的初始化指針變量的初始化 可以看出,一個一維字符指針數(shù)組可以表示一個n行m列的的文本,它是特殊的二維字符數(shù)組。 我們可以在定義指針變量的同時給其賦初值,指針的初值是某個數(shù)據(jù)對象的
8、內(nèi)存地址,也即使得該指針指向?qū)?yīng)的數(shù)據(jù)對象。 這一過程也稱為建立指針。 例如: int i=10; int *iptr = &i; 上面的說明語句在聲明指針變量iptr的同時即賦予初值,其初值是i的地址。 也即iptr指向整型變量i,對于iptr的引用(可以表示成*iptr)也就是對i的引用。 5幾點(diǎn)說明幾點(diǎn)說明 (1)標(biāo)識符前面的“*”并不是名稱的一部分,而表示該數(shù)據(jù)對象的類型為指針類型,也即聲明該數(shù)據(jù)對象是指針類型數(shù)據(jù)對象。(2)指針變量可以和其它變量在同一語句中聲明。 例如: double d1,*d2;(3)指針變量只能存放相同基類型數(shù)據(jù)對象的內(nèi)存地址,換句話說,一個指針變量在
9、任何時候都只能指向同一基類型的數(shù)據(jù)對象。 這就是所謂“指針類型與實(shí)際存儲的匹配”問題 ,例如: char *c;int i; c=&i; 錯誤的賦值,因?yàn)閏只能指向字符串。 6.3 指針運(yùn)算指針運(yùn)算 指針運(yùn)算實(shí)際上是地址操作,包括算術(shù)運(yùn)算(加減運(yùn)算)、關(guān)系運(yùn)算、賦值以及取地址和間接訪問等。 1指針的賦值指針的賦值 操作指針之前必須賦予確定的值,可以在定義指針的同時賦予初值,也可以用賦值表達(dá)式對指針變量賦值。 例如:int grade,*p; p=&grade; (1)賦空值(NULL); (2)賦予某個變量的地址。 (3)將一個指針變量的值賦予另一指針變量。2指針的加減運(yùn)算指針
10、的加減運(yùn)算 1)運(yùn)算符:)運(yùn)算符:+、-、+、- 。 2)一個指針量加上(或減去)一個整型量n,表示地址偏移了n個單位,具體向上或向下偏移多少字節(jié),取決于其基類型。 例如:例如一個整型指針變量加上4等于原存放的地址值加上8(字節(jié));而一個雙精度型指針變量加上4等于原存放的地址值加上32(字節(jié))。 注意:參加運(yùn)算的指針變量必須是已賦值的。注意:參加運(yùn)算的指針變量必須是已賦值的。 3)對數(shù)組名施加)對數(shù)組名施加+,- 運(yùn)算運(yùn)算 數(shù)組名的初值是數(shù)組的首地址,也即指向數(shù)組的第一個元素,數(shù)組名+i,表示指向數(shù)組的第i+1個元素。 例如:ai與*(a+i)這兩種表示法是等價的。 都表示a數(shù)組的第i+1個元
11、素。4)指針變量的)指針變量的+、-運(yùn)算運(yùn)算 +:原地址加上一個地址單位(基類型的實(shí)際字節(jié)數(shù)); -:原地址減去一個地址單位(基類型的實(shí)際字節(jié)數(shù)); 例如: int *iptr; iptr+;/ iptr=iptr+1,向下移動兩個字節(jié) iptr-;/ iptr=iptr-1,向上移動兩個字節(jié) 下圖給出指針的移動示意: 3. 取地址運(yùn)算取地址運(yùn)算 1) 運(yùn)算符:& 2) 作用:獲取數(shù)據(jù)對象的內(nèi)存地址,如果是結(jié)構(gòu)數(shù)據(jù)對象則獲取其內(nèi)存首地址。 例6-5 下面的程序段包含著對幾種不同類型的數(shù)據(jù)對象的取地址運(yùn)算,試分析之。 分析:分析: (2)取字符變量c1的內(nèi)存地址賦予字符型指針變量c2,使
12、c2指向c1。 程序段:char c1,s1100,*c2;scanf(“%c”,&c1);/(1)c2=&c1; / (2)c2=&s10; / (3) (1)scanf函數(shù)的第二個參數(shù)的類型是指針類型,調(diào)用該函數(shù)時,對應(yīng)的實(shí)參必須是數(shù)據(jù)對象的實(shí)際地址或存放數(shù)據(jù)對象地址的另一指針變量。 4. 間接訪問間接訪問 所謂間接訪問是指通過指針變量訪問該變量所指向的數(shù)據(jù)對象。由于不是對數(shù)據(jù)對象的直接訪問,故稱為間接訪問。(4)c2=s10和c2=&s1都是錯誤的運(yùn)算,為什么? 該運(yùn)算與c2=s1是等價的,為什么? (3)取字符數(shù)組s1的第1個元素的地址賦予指針變量c2,
13、使c2指向s10。1) 運(yùn)算符運(yùn)算符 :* 該運(yùn)算符作用在指針變量上,表示訪問指針變量所指向的數(shù)據(jù)對象。 2)作用:)作用: 實(shí)現(xiàn)對指針?biāo)赶虻臄?shù)據(jù)對象的間接訪問,包括引用和賦值等基本運(yùn)算。 例6-6 下面的程序段包含著對指針的間接訪問。 int a,b=2,c,*p;p=&b;scanf(%d,&a);c=a+*p; 通過指針p實(shí)現(xiàn)對b的間接訪問(引用)c=a+* pc=a+b(3)關(guān)于)關(guān)于“*”的說明的說明 “*”作為算術(shù)運(yùn)算符,表示乘法,例如:a*b。 例6-7 下面的函數(shù)包含著對指針類型參數(shù)的間接訪問。 void max(int x,int y,int *max) i
14、f (xy) *max=x;/間接賦值 else *max=y; /間接賦值; “*”作為類型標(biāo)識符,用來定義指針類型(出現(xiàn)在數(shù)據(jù)定義部分),例如:int *p。 5指針應(yīng)用實(shí)例指針應(yīng)用實(shí)例 “*”作為指針運(yùn)算符,表示間接訪問,例如:a+*p(p是指針變量)。 例6-8 用指針表示字符串并實(shí)現(xiàn)字符串比較。 #include int strcmp (char *,char *);void main( ) char s1100,s2100; int ret; cin s1 s2; ret=strcmp(s1,s2); cout ret endl;/* strcmp *int strcmp(char
15、 *s,char *t) for (;*s=*t;s+,t+) if (*s=0) return 0; return *s-*t; 程序的幾點(diǎn)說明:程序的幾點(diǎn)說明: (1) s和t都是指針,分別指向字符數(shù)組s1和s2; (2) *s和*t表示間接引用s1和s2的當(dāng)前數(shù)組元素; (3) s+和t+用來改變指針值,使其指向下一 個數(shù)組元素; (4) *s-*t得到兩個字符串中首次出現(xiàn)的不相等的字符的差值,用來決定兩個字符串的大小。 6.4 指針與數(shù)組指針與數(shù)組 我們知道數(shù)組名用來存放數(shù)組的內(nèi)存首地址,也即第一個數(shù)組元素的內(nèi)存地址,因此數(shù)組名是一種特殊的指針變量。 1. 數(shù)組名是指向數(shù)組元素的指針變
16、量數(shù)組名是指向數(shù)組元素的指針變量 對于數(shù)組a而言,數(shù)組名a和a中各個元素的關(guān)系如下: a等于&a0;a+i等于&ai(參見下圖)。 2. 通過指針間接訪問數(shù)組元素通過指針間接訪問數(shù)組元素 這一特性意味著我們可以用數(shù)組名(指針)的地址偏移來代替數(shù)組元素的下標(biāo)描述。 因?yàn)閿?shù)組元素的下標(biāo)描述可以用數(shù)組名指針的偏移來代替,所以我們可以用指針來間接訪問數(shù)組元素。例如,對于數(shù)組a,有: 當(dāng)執(zhí)行了aptr=a后,*aptr等于ao,*(aptr+i)等于ai。 *a等于等于a0,*(a+i)等于ai。 例6-9 試比較以下三個程序。 程序1void main() int a10; int i
17、; for (i=0;i10;i+) scanf(%d,&ai); for (i=0;i10;i+) printf(%d,ai); 功能:功能: 輸入輸入10個整數(shù)到整型數(shù)組個整數(shù)到整型數(shù)組a中,然后原樣輸出。中,然后原樣輸出。程序2void main() int a10; int i; for (i=0;i10;i+) scanf(%d,(a+i); for (i=0;i10;i+) printf(%d,*(a+i);功能:功能: 輸入輸入10個整數(shù)到整型數(shù)組個整數(shù)到整型數(shù)組a中,然后原樣輸出。中,然后原樣輸出。/ (a+i)等價于&ai/ * (a+i)等價于ai程序3vo
18、id main()int a10;int i,*p; for (i=0;i10;i+) scanf(%d,(a+i);for (p=a;p(a+10);p+) printf(%d,*p);功能:功能: 輸入輸入10個整數(shù)到整型數(shù)組個整數(shù)到整型數(shù)組a中,然后原樣輸出。中,然后原樣輸出。/ (a+i)等價于&ai/ * p等價于ai/ p指向a數(shù)組結(jié)論:上面的三個程序執(zhí)行結(jié)果是相同的。結(jié)論:上面的三個程序執(zhí)行結(jié)果是相同的。 分析:此操作稱為“復(fù)制右子串”。其處理方法如下:例6-10 設(shè)有字符串s1,將該串從第5個字符開始直至最后一個字符的右子串部分復(fù)制到s2中。(1)確定起始位置(2)將由
19、起始字符開始的m個字符復(fù)制到s2中。問題:如何表示右子串?#include #include void RightString(char *,char *,int); void main( ) char s1100,s2100; int n1; cin s1 n1; RightString(s1,s2,n1); cout s1= s1 s2= s2 endl;void RightString(char *s1,char *s2,int n) char *p; p=s1+n-1; strcpy(s2,p);p指向s1n-1 p表示的數(shù)組是s1的一部分 試問,如果沒有引入p指針,本問題應(yīng)如何解決?
20、 通過上面的例子我們可以看出,用字符指針表示字符數(shù)組,在處理字符串時會顯得特別靈活3指針數(shù)組指針數(shù)組 (1)什么叫指針數(shù)組)什么叫指針數(shù)組 元素的數(shù)據(jù)類型是指針的數(shù)組稱為指針數(shù)組。 例如name是表格中的一個列,該列有3個單元格,分別存放3個同學(xué)的姓名,則name可以表示成字符指針數(shù)組: char *name=Lin,Ding,Zhan; 賦初值后,name數(shù)組的每一個元素的值并不是學(xué)生的姓名(字符串)而是對應(yīng)字符串的首地址,也即每一個元素的值是一個字符指針,該指針指向?qū)?yīng)的字符串(如下圖所示)。 可以看出:name0本身是一個字符指針,它存放的是Lin的首地址,實(shí)際上可以認(rèn)為name0指向一
21、個一維字符數(shù)組,name1同樣也指向一個一維字符數(shù)組,所以字符指針數(shù)組和二維字符數(shù)組有相似之處。 (2)指向指針的指針)指向指針的指針 對于指針數(shù)組而言,其數(shù)組名是指針,而且是指向指針的指針,稱為二級指針。因此除了描述成指針數(shù)組之外,還可以描述成 *類型。 執(zhí)行 pname=name后,pname可以表示指針數(shù)組name。也即:pname指向name0,pname+1指向name1,依此類推。 例如:char *name=Lin,Ding,Zhan;char *pname; pname=name; 分析:分析:(1)cout *pname *(pname+1);等價于: cout name0
22、name1 例6-11 分析下面程序的執(zhí)行結(jié)果。 #include void main() char *name=Lin,Ding,Zhan; char *pname; pname=name; cout *pname *(pname+1); (2)程序執(zhí)行結(jié)果:輸出LinDing 例6-12 下面的程序?qū)⒆址羔様?shù)組傳遞給函數(shù),也即傳遞二級指針給函數(shù)。 #include void PrintString(char *,int);void main() char *pn=Fred,Barney,Wilma,Betty; int num = sizeof(pn)/sizeof(char *); P
23、rintString(pn,num);void PrintString(char *arr,int len) for (int i=0;ilen;i+) cout (int) arri arri endl;分析:分析:(1)函數(shù)參數(shù)描述成二級指針*arr,對應(yīng)的實(shí)參應(yīng)該是二級指針或指針數(shù)組名;而對參數(shù)的引用則應(yīng)描述成arri。(2)cout (int) arri是輸出字符指針(字符串地址);cout arri是輸出字符指針?biāo)赶虻淖址?6.5 指針與函數(shù)指針與函數(shù) 函數(shù)和指針的關(guān)系體現(xiàn)在以下三方面: 函數(shù)的參數(shù)是指針類型數(shù)據(jù),例如數(shù)組參數(shù)、指針變量參數(shù)等等。 函數(shù)返回值類型本身就是指針類型
24、,這種函數(shù)稱為指針函數(shù)。 例如:char *strcpy(char *,char *) 函數(shù)名本身就是指向函數(shù)入口地址的指針,因此可以聲明一種指針數(shù)據(jù)用來存放函數(shù)名,這樣的指針稱為函數(shù)指針。1函數(shù)的指針類型參數(shù)函數(shù)的指針類型參數(shù) 1)形式:可以定義成指針變量或數(shù)組。 2)作用3)帶有指針參數(shù)的函數(shù)的實(shí)現(xiàn)過程: (1)在函數(shù)的參數(shù)表中定義指針類型參數(shù); 返回函數(shù)對指針的修改,實(shí)質(zhì)上是返回函數(shù)對指針?biāo)赶虻臄?shù)據(jù)對象的修改,這樣可以返回不止一個值,同時還可以節(jié)省大量的內(nèi)存空間,因此具有很大的靈活性和實(shí)用性。 例如 :void s *x,int *y); (3)函數(shù)的執(zhí)行部分對指針形參進(jìn)行間接訪問。(
25、2)在函數(shù)調(diào)用時提供相應(yīng)的變量或數(shù)組地址(傳地址); 例如s); 例如,對*x和*y的操作 。 4)使用指針類型參數(shù)的副作用)使用指針類型參數(shù)的副作用 指針類型參數(shù)的靈活性體現(xiàn)在它使函數(shù)可以訪問本函數(shù)的局部空間(棧空間)以外的內(nèi)存區(qū)域,這顯然破壞了函數(shù)的黑盒特性,帶來以下副作用: (1)可讀性問題:因?yàn)閷?shù)據(jù)對象的間接訪問比直接訪問相對難以理解。 (2)重用性問題:函數(shù)調(diào)用依賴于上層函數(shù)或整個外部內(nèi)存空間環(huán)境,喪失其封裝特性(黑盒特性),所以無法作為公共模塊來使用。 (3)調(diào)試的復(fù)雜性問題:跟蹤錯誤的區(qū)域從函數(shù)的局部數(shù)據(jù)區(qū)擴(kuò)大到整個內(nèi)存空間,不但要跟蹤變量,還要跟蹤地址,錯誤現(xiàn)象從簡單的不能得
26、到相應(yīng)返回結(jié)果,衍生到系統(tǒng)環(huán)境遭破壞甚至死機(jī)。 2指針函數(shù)指針函數(shù) 函數(shù)返回值的類型是指針類型,這樣的函數(shù)稱為指針函數(shù)。例如: char * strcat(char *s1,const *s2) ; 該函數(shù)返回值的數(shù)據(jù)類型是字符指針,也即該函數(shù)調(diào)用結(jié)果返回字符串s1的地址(兩串連接后所形成的新串的地址)。 例6-13 分析下面程序的執(zhí)行結(jié)果?3 .函數(shù)指針函數(shù)指針#include #include main( ) char s1100,s2=aaa;cout strcpy(s1,s2);輸出:aaa(1) 什么叫函數(shù)指針什么叫函數(shù)指針 程序運(yùn)行時,每個函數(shù)都存放在代碼區(qū)中,有一個入口地址,稱為
27、函數(shù)地址,函數(shù)名就表示該地址。 指向函數(shù)地址的指針稱為函數(shù)指針,通過該指針可以調(diào)用相應(yīng)的函數(shù)。 (2)聲明函數(shù)指針)聲明函數(shù)指針 語法: (*)(); 例如:int (*fp)(int); fp被聲明成整型函數(shù)指針,可以存放一個整型函數(shù)名。 例如:int fn1(int); . int (*fp)(int); fp=fn1; / fp被聲明成函數(shù)指針/ fp被賦予fn1函數(shù)的地址(2) 用函數(shù)指針調(diào)用函數(shù)用函數(shù)指針調(diào)用函數(shù)語法:語法: ();或:(*)(); 例如:int fn1(int); . int (*fp)(int); fp=fn1; y=fp(5); / fp被聲明成函數(shù)指針/ fp
28、被賦予fn1函數(shù)的地址/ 用fp調(diào)用fn1函數(shù)#include int fn1(int);void main()int x,y;int (*fp1)(int);x=1;fp1=fn1;y=fp1(x);int fn1(int x)cout x*5;return (x*5);y=fn1(x)輸出?(3)函數(shù)指針用作函數(shù)參數(shù))函數(shù)指針用作函數(shù)參數(shù) 當(dāng)函數(shù)形參是函數(shù)指針時,對應(yīng)的實(shí)參必須是函數(shù)名,例如:實(shí)參是函數(shù)名,在函數(shù)調(diào)用時實(shí)現(xiàn)函數(shù)地址的傳遞,這樣可以在被調(diào)函數(shù)體內(nèi),通過對函數(shù)指針形參的引用來調(diào)用另一函數(shù),而且對應(yīng)不同的實(shí)參值可以調(diào)用不同的函數(shù)。(p179) 這就是要使用函數(shù)指針形參的原因。ch
29、ar f2(int (*fp1(int); f2(f1);6.6 堆內(nèi)存管理堆內(nèi)存管理 允許程序運(yùn)行過程中直接進(jìn)行內(nèi)存管理,這是C+的一大特色。 (1)程序(函數(shù))中定義的數(shù)組,其大小事先難以確定,如果定義過大,會造成存儲空間的浪費(fèi)。采用即時申請內(nèi)存空間的辦法,不但可以動態(tài)地建立數(shù)組,而且可以保證其大小總是符合實(shí)際情況。 通過直接內(nèi)存管理可以實(shí)現(xiàn)動態(tài)存儲分配,提高內(nèi)存使用率。以下幾種情況尤其需要這一技術(shù)的支持: (2)函數(shù)中包含太多的數(shù)組,一旦該函數(shù)被調(diào)用,就必須占據(jù)大量的棧空間。通常這些數(shù)組并不是同時使用的,這同樣造成太大的浪費(fèi)。 采用堆內(nèi)存管理技術(shù),可以控制程序在實(shí)際需要使用某一數(shù)據(jù)對象時
30、才去申請數(shù)據(jù)空間,一旦用完,馬上釋放。 (3)程序中定義了結(jié)構(gòu)體、類或其它數(shù)據(jù)對象,這樣的數(shù)據(jù)對象有時需要超乎尋常的內(nèi)存空間,因此更需要堆內(nèi)存的支持。 1堆內(nèi)存堆內(nèi)存 堆(Heap)是區(qū)別于棧區(qū)、全局?jǐn)?shù)據(jù)和代碼區(qū)的另一內(nèi)存區(qū)域,允許用戶程序運(yùn)行過程中動態(tài)申請與釋放。 管理堆內(nèi)存的函數(shù)有:malloc、calloc、free、memcpy、memmove、memset等等。 直接操縱堆內(nèi)存的操作符有:new和delete,這是C+所獨(dú)有的。 下面分別討論。 2申請堆內(nèi)存申請堆內(nèi)存 通過調(diào)用calloc函數(shù)、malloc函數(shù)或通過new操作符均可以為程序中的數(shù)據(jù)對象申請堆內(nèi)存空間。 1)callo
31、c函數(shù)函數(shù) (1)格式(函數(shù)原型)格式(函數(shù)原型) void *calloc(size_t n,size_t size); 解釋:解釋: n:數(shù)組的長度(數(shù)組元素個數(shù)),size_t等同于unsigned long; size:數(shù)組元素的字節(jié)數(shù),可以用sizeof來計(jì)算。 函數(shù)的返回值函數(shù)的返回值 函數(shù)類型為void *,也即無符指針類型,在實(shí)際調(diào)用時,必須依據(jù)數(shù)據(jù)對象的類型進(jìn)行強(qiáng)制轉(zhuǎn)換。 例如:char *s;int *a;s = (char *)calloc(10,sizeof(char); a = (int *) calloc(100,sizeof(int);將返回值轉(zhuǎn)換成字符指針 ;n
32、ull:申請失敗 被分配的堆內(nèi)存空間首地址:申請成功。 例如:sizeof (int)計(jì)算整型數(shù)據(jù)的長度。 為一個具有n個元素的數(shù)組分配內(nèi)存空間,每個元素的長度為size字節(jié)。 (2)功能)功能 注意: calloc函數(shù)的原型在malloc.h文件中。 凡是調(diào)用calloc申請的內(nèi)存空間(由對應(yīng)數(shù)據(jù)指針指向),必須調(diào)用free函數(shù)按對應(yīng)數(shù)據(jù)指針進(jìn)行釋放。 例6-14 將例6-9的s1和s2兩個字符數(shù)組改成通過字符指針動態(tài)申請空間。#include #include #include #include void RightString(char *,char *,int);main() char
33、 *s1,*s2; int len,n1; if (s1=(char *)calloc(100,sizeof(char)=NULL) cout s1 n1; len=strlen(s1); /獲取s1的實(shí)際長度 cout len= len; if (s2=(char *)calloc(len-n1+2,sizeof(char)=NULL) /len-n1+2是s2的實(shí)際長度 cout 申請不到內(nèi)存空間; free(s1); exit(-1); RightString(s1,s2,n1); cout s1= s1 s2= s2 endl; free(s1); free(s2); ;/釋放s1所指
34、向的內(nèi)存/釋放s1所指向的內(nèi)存 /釋放s2所指向的內(nèi)存;2)malloc函數(shù)函數(shù) (1)格式(函數(shù)原型) void RightString(char *s1,char *s2,int n) char *p; p=s1+n-1;/p指向s1n-1,p表示的數(shù)組是s1的一部分。 strcpy(s2,p); void *malloc(size_t size); 解釋:解釋: 參數(shù)size:數(shù)據(jù)對象所需內(nèi)存空間的大小(字節(jié)數(shù)); 注意,如果要申請數(shù)組空間,其size的計(jì)算方法是:數(shù)組的長度(元素個數(shù))*數(shù)組元素的長度 例如, 給例6-13中的s1申請空間,其參數(shù)描述:100*sizeof(char)。
35、 函數(shù)類型為void *,也即無符指針類型,在實(shí)際調(diào)用時,必須依據(jù)數(shù)據(jù)對象的類型進(jìn)行強(qiáng)制轉(zhuǎn)換,轉(zhuǎn)換方法與calloc函數(shù)相同。 函數(shù)的返回值 null:申請失敗 被分配的堆內(nèi)存空間首地址:申請成功。 (2)功能)功能 為指定數(shù)據(jù)對象動態(tài)分配一個size大小的內(nèi)存空間,數(shù)據(jù)對象可以是一般變量、數(shù)組以及結(jié)構(gòu)體變量等等。 (3)注意)注意 凡是調(diào)用malloc申請的內(nèi)存空間(由對應(yīng)數(shù)據(jù)指針指向),必須調(diào)用free函數(shù)按對應(yīng)數(shù)據(jù)指針進(jìn)行釋放。 malloc函數(shù)的原型在malloc.h文件中。例6-15 下面的程序在堆內(nèi)存中動態(tài)地建立整型數(shù)組array所需的空間,給每一個元素賦值并輸出。 #includ
36、e #include void main() int arraysize;/數(shù)組長度 int *array,count; cout arraysize; if (array=(int *)malloc(arraysize* sizeof(int)=NULL) cout 申請不到內(nèi)存空間; 分析:分析: 程序通過調(diào)用malloc函數(shù),在運(yùn)行過程中動態(tài)建立array數(shù)組; else for (count=0;countarraysize;count+) arraycount = count*2; /賦值 for (count=0;countarraysize;count+) cout arrayc
37、ount ; /輸出 cout endl; free(array); 該數(shù)組的空間大小由arraysize*sizeof(int)動態(tài)確定(因?yàn)閍rraysize可以由用戶輸入)。 輸入:10輸出:0 2 4 6 8 10 12 14 16 18 3)new操作符操作符 new操作符是c+專有的,用來分配堆內(nèi)存,其功能類似于malloc和calloc,但不同之處在于, new是操作符而不是函數(shù),因而更為簡潔和高效。 (1)格式)格式 new 解釋:解釋: 操作數(shù)描述為:類型名初始化值表 例如:new char為單個字符變量申請內(nèi)存空間。new int10為整型數(shù)組申請內(nèi)存空間。 例如:new
38、char100,申請能存放100個字符的內(nèi)存空間,等同于建立一個有100個元素的字符數(shù)組。 初始化值表可以指明數(shù)據(jù)個數(shù),也可以直接給出各個數(shù)據(jù)的初始值。 new操作返回一個指針,該指針的類型與操作數(shù)中的類型名相同 。例如:new char100;返回字符類型指針。 (2)new操作的應(yīng)用實(shí)例操作的應(yīng)用實(shí)例 注意:可以將返回值直接賦予同類型指針,請看下面的例子: char *s;s=new char100; /等同于s=(char *)calloc(100,sizeof(char) 例6-16 將例6-15中給array申請內(nèi)存空間,改為用new操作實(shí)現(xiàn)。#include #include vo
39、id main( ) int arraysize; /數(shù)組長度數(shù)組長度 int *array,count; cout arraysize; if (array=new intarraysize)=NULL) cout 申請不到內(nèi)存空間申請不到內(nèi)存空間; else for (count=0;countarraysize;count+) arraycount = count*2; /賦值賦值 for (count=0;countarraysize;count+) cout arraycount ; /輸出輸出 cout endl; deletearray; 3釋放堆內(nèi)存釋放堆內(nèi)存 凡是調(diào)用call
40、oc函數(shù)、malloc函數(shù)或執(zhí)行new操作申請的內(nèi)存空間,在函數(shù)調(diào)用結(jié)束后并不會自動釋放,只能由程序自行釋放,所以使用完畢或退出函數(shù)之前一定要釋放。 調(diào)用calloc函數(shù)、malloc函數(shù)申請的空間,可調(diào)用free函數(shù)來釋放;用new操作申請的空間則用delete操作來釋放。 1)free函數(shù)函數(shù) 格式:(函數(shù)原型)格式:(函數(shù)原型) void free(void *p); 解釋:解釋: 參數(shù)p,是一個無符指針,該指針指向要釋放的內(nèi)存空間首地址。 該函數(shù)的類型是void,故沒有返回值。2)delete操作符操作符 格式格式 : delete pointer 或 delete pointer 解
41、釋解釋 : pointer是delete的操作數(shù),它是new所返回的指針。 當(dāng)要釋放的內(nèi)存空間是分配給數(shù)組的,必須帶上。 4其它堆內(nèi)存操作函數(shù)其它堆內(nèi)存操作函數(shù) 下面簡單地介紹其它一些比較常用的堆內(nèi)存操作函數(shù),這些函數(shù)的原型也都在malloc.h文件中。 1) memcpy函數(shù)函數(shù) 格式:void *memcpy(void *dest,const void *src,size_t length); 功能:從src指向的源緩沖區(qū)中復(fù)制length個字符到dest指向的目的緩沖區(qū)中。 2) memset函數(shù)函數(shù) 格式:void *memset(void *s,int c,size_t length
42、); 格式:格式:void *memcmp(const void *s1, const void *s2, size_t length); 功能:功能:比較由s1和s2指向的兩個緩沖區(qū)的內(nèi)容,長度為length個字符。稱為內(nèi)存比較函數(shù)。 3) memcpy函數(shù)函數(shù)功能:將s指向的長度為length的緩沖區(qū)填充為字符c。稱為內(nèi)存填充函數(shù) 6.7 指針的應(yīng)用指針的應(yīng)用 下面的程序?qū)斫庵羔樀膽?yīng)用有很大的幫助,通過程序的分析也可以幫助我們歸納本章的主要內(nèi)容。 例6-16 對若干字符串按字母順序排序后逐串輸出,需要排序輸出的字符串是任意的,例如若干個地址或者若干個課程名稱等等。 1)方法)方法 (1)設(shè)置一個字符指針數(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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工廠勞動合同關(guān)鍵條款
- 裝修合同范本簡化版
- 房屋出租簡約合同樣式
- 出租車承包合同
- 線上辦公信息安全協(xié)議
- 旅館承包合同范例
- 房地產(chǎn)經(jīng)紀(jì)公司代理合同模板
- 技術(shù)成果轉(zhuǎn)讓股權(quán)協(xié)議
- 2024年汽車租賃合同范本
- 抵押物借款合同的社會責(zé)任
- 汽車起重機(jī)日常檢查維修保養(yǎng)記錄表
- 中國醫(yī)科大學(xué)2023年12月《康復(fù)工程學(xué)》作業(yè)考核試題-【答案】
- 浙江省9+1高中聯(lián)盟2022-2023學(xué)年高一上學(xué)期11月期中考物理試題(解析版)
- 七年級上冊英語期中專項(xiàng)復(fù)習(xí)-補(bǔ)全對話(含答案)
- 鐵的單質(zhì)(導(dǎo)學(xué)案)高一化學(xué)
- 絞吸式挖泥船水下疏挖河渠施工工法
- 反腐倡廉廉潔行醫(yī)
- 心血管內(nèi)科醫(yī)療質(zhì)量評價體系與考核標(biāo)準(zhǔn)
- 2022-2023學(xué)年廣州市南沙區(qū)小升初全真模擬數(shù)學(xué)檢測卷含答案
- 2023年食品安全糧食類理論知識考試題庫(含答案)
- 人教版五年級上冊數(shù)學(xué)《可能性》作業(yè)設(shè)計(jì)
評論
0/150
提交評論