版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第C語言全方位講解指針與地址和數(shù)組函數(shù)堆空間的關(guān)系目錄一、一種特殊的變量-指針二、深入理解指針與地址三、指針與數(shù)組(上)四、指針與數(shù)組(下)五、指針與函數(shù)六、指針與堆空間七、指針專題經(jīng)典問題剖析
一、一種特殊的變量-指針
指針是C語言中的變量
因?yàn)槭亲兞?,所以用于保存具體值特殊之處,指針保存的值是內(nèi)存中的地址內(nèi)存地址是什么
內(nèi)存是計(jì)算機(jī)中的存儲(chǔ)部件,每個(gè)存儲(chǔ)單元有固定唯一的編號(hào)內(nèi)存中存儲(chǔ)單元的編號(hào)即內(nèi)存地址
需要弄清楚的事實(shí)
程序中的一切元素都存在于內(nèi)存中,因此,可通過內(nèi)存地址訪問程序元素。
內(nèi)存示例
獲取地址
C語言中通過操作符獲取程序元素的地址可獲取變量,數(shù)組,函數(shù)的起始地址內(nèi)存地址的本質(zhì)是一個(gè)無符號(hào)整數(shù)(4字節(jié)或8字節(jié))
下面看一個(gè)簡單的例子:
#includestdio.h
intmain()
intvar=0;
printf("varvalue=%d\n",var);
printf("varaddress=%p\n",var);
return0;
}
下面為輸出結(jié)果:
注意事項(xiàng)
只有通過內(nèi)存地址+長度才能確定一個(gè)變量中保存的值。
指針定義語法:
type*point;
type-數(shù)據(jù)類型,決定訪問內(nèi)存時(shí)的長度范圍*標(biāo)志,意味著定義一個(gè)指針變量pointer變量名,遵循C語言命名規(guī)則
例如:
intmain()
char*pChar;
short*pShort;
int*pInt;
float*pFloat;
double*pDouble;
return0;
}
指針內(nèi)存訪問:
*pointer
指針訪問操作符(*)作用于指針變量即可訪問內(nèi)存數(shù)據(jù)指針的類型決定通過地址訪問內(nèi)存時(shí)的長度范圍指針的類型統(tǒng)一占用4字節(jié)或8字節(jié)
即:sizeof(type*)==4或sizeof(type*)==8
下面看一段代碼,感受一下:
#includestdio.h
intmain()
intvar=0;
intanother=0;
int*pVar=NULL;
printf("1.var=%d\n",var);
printf("1.pVar=%p\n",pVar);
pVar=var;//使用指針保存變量的地址
*pVar=100;//*pVar等價(jià)于var,var=100;
printf("2.var=%d\n",var);
printf("2.pVar=%p\n",pVar);
pVar=another;//改變了pVar的指向,使得pVar保存another的地址
*pVar=1000;//another=1000;
printf("3.another=%d\n",another);
printf("3.pVar=%p\n",pVar);
printf("4.add==%d\n",var+another+*pVar);//100+1000+1000==2100
return0;
}
下面為輸出結(jié)果:
注意NULL地址為00000000
小結(jié)
指針是C語言中的變量(本質(zhì)為容器)指針專用于保存程序元素的內(nèi)存地址可使用*操作符通過指針訪問程序元素本身指針也有類型,指針類型由數(shù)據(jù)類型+*構(gòu)成
二、深入理解指針與地址
靈魂三問
指針類型和普通類型之間的關(guān)系是什么何看待內(nèi)存地址+長度才能訪問內(nèi)存中的數(shù)據(jù)不同類型的指針可以相互賦值嗎
初學(xué)指針的軍規(guī)
Type*類型的指針只保存Type類型變量的地址禁止不同類型的指針相互賦值禁止將普通數(shù)值當(dāng)作地址賦值給指針
注意:指針保存的地址必須是有效地址
下面看一段代碼:
#includestdio.h
intmain()
inti=10;
floatf=10;
int*pi=//WARNING
float*pf=//OK
printf("pi=%p,pf=%p\n",pi,pf);
printf("*pi=%d,*pf=%f\n",*pi,*pf);
pi=i;//WARNING
*pi=110;//OOPS
printf("pi=%p,*pi=%d\n",pi,*pi);
return0;
}
下面為輸出結(jié)果:
這個(gè)程序犯了兩個(gè)錯(cuò)誤:
1、將不同類型的指針相互賦值,雖然int類型的指針變量保存的地址是對(duì)的,但是其所保存的值是錯(cuò)的。
2、將普通數(shù)值當(dāng)作地址賦值給指針,這會(huì)導(dǎo)致嚴(yán)重的錯(cuò)誤,不能正確輸出
編寫函數(shù)交換兩個(gè)變量的值
想要編寫函數(shù)交換變量的值,那么,必須有能力在函數(shù)內(nèi)部修改函數(shù)外部的變量!!!
看下面的代碼:
#includestdio.h
voidfunc(int*p)
*p=100;//修改內(nèi)存中4字節(jié)的數(shù)據(jù),即:修改一個(gè)整型變量的值
voidswap(int*pa,int*pb)
intt=0;
t=*pa;
*pa=*pb;
*pb=t;
intmain()
intvar=0;
inta=1,b=2;
printf("1.var=%d\n",var);
func(var);
printf("2.var=%d\n",var);
printf("3.a=%d,b=%d\n",a,b);
swap(a,
printf("4.a=%d,b=%d\n",a,b);
return0;
}
下面為輸出結(jié)果:
小結(jié)論
可以利用指針從函數(shù)中返回多個(gè)值(return只能返回一個(gè)值)!!
下面看一段代碼:
#includestdio.h
intcalculate(intn,longlong*pa,longlong*pm)
intret=1;
if((1=n)(n=20))
inti=0;
*pa=0;
*pm=1;
for(i=1;ii++)
*pa=*pa+i;
*pm=*pm*i;
else
ret=0;
returnret;
intmain()
longlongar=0;
longlongmr=0;
if(calculate(5,ar,mr))
printf("ar=%lld,mr=%lld\n",ar,mr);
return0;
}
下面為輸出結(jié)果:
這段代碼中的子函數(shù)通過指針,計(jì)算了1加到5以及1乘到5的值,這就間接地通過指針從子函數(shù)返回多個(gè)值
小結(jié)
指針是變量,因此賦值時(shí)必須保證類型相同
指針變量保存的地址必須是有效地址
通過指針參數(shù)
一能夠?qū)崿F(xiàn)函數(shù)交換變量的值一能夠從函數(shù)中返回多個(gè)值
三、指針與數(shù)組(上)
問題
數(shù)組的本質(zhì)是一片連續(xù)的內(nèi)存,那么,數(shù)組的地址是什么?如何獲取
一些事實(shí)
使用取地址操作符獲取數(shù)組的地址數(shù)組名可看作一個(gè)指針,代表數(shù)組中0元素的地址當(dāng)指針指向數(shù)組元素時(shí),可進(jìn)行指針運(yùn)算(指針移動(dòng))
深入理解數(shù)組地址(inta[]={1,2,3,4,5};)
a與a在數(shù)值上相同,但是意義上不同a代表數(shù)組地址,類型為:int(*)[5]a代表數(shù)組0號(hào)元素地址,類型為:int*指向數(shù)組的指針:int(*pName)[5]=
下面看一段代碼:
#includestdio.h
intmain()
inta[]={1,2,3,4,0};
int*p=a;//a的類型為int*,a[0]==int*
int(*pa)[5]=
printf("%p,%p\n",p,a);
p++;
*p=100;//a[1]=100;
printf("%d,%d\n",*p,a[1]);
printf("%p,%p\n",a,a);
p=pa;//WARNING!!!!
p=a;
while(*p)
printf("%d\n",*p);
p++;
return0;
}
下面為運(yùn)行結(jié)果:
需要注意的是,p和pa不是一個(gè)指針類型,所以令p=pa這種做法是不正確的。
注意
數(shù)組名并不是指針,只是代表了0號(hào)元素的地址,因此可以當(dāng)作指針使用。
四、指針與數(shù)組(下)
指針與數(shù)組的等價(jià)用法
假如:
inta[]={1,2,3,4,5}
int*p=a;
則以下等價(jià):
a[i]--*(a+i)--*(p+i)--p[i]
下面看一段代碼,加深理解:
#includestdio.h
intmain()
inta[]={1,2,3,4,5};
int*p=a;
inti=0;
//a[i]==*(a+i)==*(p+i)==p[i]
for(i=0;ii++)
printf("%d,%d\n",a[i],*(a+i));
printf("\n");
for(i=0;ii++)
printf("%d,%d\n",a[i],p[i]);
printf("\n");
for(i=0;ii++)
printf("%d,%d\n",p[i],*(p+i));
printf("\n");
printf("a=%p,p=%p\n",a,p);
printf("a=%p,p=%p\n",a,
return0;
}
下面為輸出結(jié)果:
這里可以看到a和p的地址不同,因?yàn)樗鼈兪莾蓚€(gè)不同的指針變量。
字符串拾遺
字符串常量是char*類型,一種指針類型
指針移動(dòng)組合拳:
intv=*p++;
解讀:
指針訪問操作符(*)和自增運(yùn)算操作符(++)優(yōu)先級(jí)相同
所以,先從p指向的內(nèi)存中取值,然后p進(jìn)行移動(dòng)
等價(jià)于:
intv=*p;
p++;
下面看一段代碼,體會(huì)一下:
#includestdio.h
intmain()
inta[]={1,2,3};
int*p=a;
intv=*p++;
char*s=NULL;
printf("%p\n","D.T.Software");
printf("%p\n","D.T.Software");
printf("v=%d,*p=%d\n",v,*p);
printf("First=%c\n",*"D.T.Software");
s="D.T.Software";
while(*s)printf("%c",*s++);
printf("\n");
return0;
}
下面為輸出結(jié)果:
因?yàn)镈.T.Software在全局?jǐn)?shù)據(jù)區(qū)的起始地址一樣,所以兩次打印出來的地址一樣。
小結(jié)
數(shù)組名可看作一個(gè)指針,代表數(shù)組中0元素的地址a與a在數(shù)值上相同,但是意義上不同C語言中的字符串常量的類型是char*當(dāng)指針指向數(shù)組元素時(shí),才能進(jìn)行指針運(yùn)算
五、指針與函數(shù)
問題
函數(shù)調(diào)用時(shí)會(huì)跳轉(zhuǎn)到函數(shù)體對(duì)應(yīng)的代碼處執(zhí)行,那么,如何知道函數(shù)體代碼的具體位置
深入函數(shù)之旅
函數(shù)的本質(zhì)是一段內(nèi)存中的代碼(占用一片連續(xù)內(nèi)存)函數(shù)擁有類型,函數(shù)類型由返回類型和參數(shù)類型列表組成例:
函數(shù)申明類型intsum(intn);int(int)voidswap(int*pa,int*pb)void(int*,int*)voidg(void);void(void)
函數(shù)的一些事實(shí)
函數(shù)名就是函數(shù)體代碼的起始地址(函數(shù)入口地址)通過函數(shù)名調(diào)用函數(shù),本質(zhì)為指定具體地址的跳轉(zhuǎn)執(zhí)行因此,可定義指針,保存函數(shù)入口地址
函數(shù)指針(Typefunc(Type1a,Type2b))
函數(shù)名即函數(shù)入口地址,類型為Type(*)(Type1,Type2)對(duì)于func的函數(shù),func與func數(shù)值相同,意義相同指向函數(shù)的指針:Type(*pFunc)(Type1,Type2)=func;
函數(shù)指針參數(shù)
函數(shù)指針的本質(zhì)還是指針(變量,保存內(nèi)存地址)可定義函數(shù)指針參數(shù),使用相同代碼實(shí)現(xiàn)不同功能
注意
函數(shù)指針只是單純的保存函數(shù)的入口地址
因此
只能通過函數(shù)指針調(diào)用目標(biāo)函數(shù)不能進(jìn)行指針移動(dòng)(指針運(yùn)算)
下面看一段代碼,理解一下:
#includestdio.h
intadd(inta,intb)
returna+b;
intmul(inta,intb)
returna*b;
intcalculate(inta[],intlen,int(*cal)(int,int))
intret=a[0];
inti=0;
for(i=1;ii++)
ret=cal(ret,a[i]);
returnret;
intmain()
inta[]={1,2,3,4,5};
int(*pFunc)(int,int)=NULL;
pFunc=add;
printf("%d\n",pFunc(1,2));
printf("%d\n",(*pFunc)(3,4));
pFunc=mul;
printf("%d\n",pFunc(5,6));
printf("%d\n",(*pFunc)(7,8));
printf("1+...+5=%d\n",calculate(a,5,add));
printf("1*...*5=%d\n",calculate(a,5,mul));
return0;
}
下面為輸出結(jié)果:
這里注意,只有調(diào)用的時(shí)候,才能確定calculate()子函數(shù)中的cal是什么函數(shù)。
再論數(shù)組參數(shù)
函數(shù)的數(shù)組形參退化為指針!因此,不包含數(shù)組實(shí)參的長度信息。使用數(shù)組名調(diào)用時(shí),傳遞的是0號(hào)元素的地址。
voidfunc(inta[])--voidfunc(int*a)
--voidfunc(inta[1])
--voidfunc(inta[10)
--voidfunc(inta[100)
下面看一段代碼:
#includestdio.h
intdemo(intarr[],intlen)//intdemo(int*arr,intlen)
intret=0;
inti=0;
printf("demo:sizeof(arr)=%d\n",sizeof(arr));
while(ilen)
ret+=*arr++;
i++;
returnret;
intmain()
inta[]={1,2,3,4,5};
//intv=*a++;
printf("returnvalue:%d\n",demo(a,5));
return0;
}
下面為輸出結(jié)果:
定義的形參arr[]可以進(jìn)行*arr++的操作,這就說明函數(shù)的數(shù)組形參退化為指針,因?yàn)閿?shù)組不可以進(jìn)行++的運(yùn)算。
小結(jié)
函數(shù)名的本質(zhì)是函數(shù)體的入口地址函數(shù)類型由返回類型和參數(shù)類型列表組成可定義指向函數(shù)的指針:Type(*pFunc)(Type1,Type2);函數(shù)指針只是單純的保存函數(shù)的入口地址(不能進(jìn)行指針運(yùn)算)
六、指針與堆空間
再論內(nèi)存空間
內(nèi)存區(qū)域不同,用途不同
全局?jǐn)?shù)據(jù)區(qū):存放全局變量,靜態(tài)變量??臻g:存放函數(shù)參數(shù),局部變量堆空間:用于動(dòng)態(tài)創(chuàng)建變量(數(shù)組)
堆空間的本質(zhì)
備用的內(nèi)存?zhèn)}庫,以字節(jié)為單位預(yù)留的可用內(nèi)存程序可在需要時(shí)從倉庫中申請(qǐng)使用內(nèi)存(動(dòng)態(tài)借)當(dāng)不需要再使用申請(qǐng)的內(nèi)存時(shí),需要及時(shí)歸還(動(dòng)態(tài)還)
問題
如何從堆空間申請(qǐng)內(nèi)存如何歸還
預(yù)備知識(shí)--void*
void類型是基礎(chǔ)類型,對(duì)應(yīng)的指針類型為void*void*是指針類型,其指針變量能夠保存地址通過void*指針無法獲取內(nèi)存中的數(shù)據(jù)(無長度信息)
void*總結(jié)
不可使用void*指針直接獲取內(nèi)存數(shù)據(jù)。void*指針可與其它數(shù)據(jù)指針相互賦值。
下面看一段代碼:
#includestdio.h
intmain()
charc=0;
inti=0;
floatf=2.0f;
doubled=3.0;
void*p=NULL;
double*pd=NULL;
int*pi=NULL;
/*void*指針可以保存任意類型的地址*/
p=
p=
p=
p=
printf("%p\n",p);
//void*類型的指針無法訪問內(nèi)存中的數(shù)據(jù)
//printf("%f\n",*p);
/*void*類型的變量可以直接合法的賦值給其他具體數(shù)據(jù)類型的指針變量*/
pd=p;
pi=p;
//void*是例外,其他指針類型的變量不能相互賦值
//pd=pi;
return0;
}
下面為輸出結(jié)果:
注意幾個(gè)問題:
1.void*指針可以保存任意類型的地址
2.void*類型的指針無法訪問內(nèi)存中的數(shù)據(jù)
3.void*類型的變量可以直接合法的賦值給其他具體數(shù)據(jù)類型的指針變量
4.void*是例外,其他指針類型的變量不能相互賦值
堆空間的使用
工具箱:stdlib.h申請(qǐng):void*malloc(unsignedbytes)歸還:voidfree(void*p)
堆空間的使用原則
有借有還,再借不難(杜絕只申請(qǐng),不歸還)malloc申請(qǐng)內(nèi)存后,應(yīng)該判斷是否申請(qǐng)成功free只能釋放申請(qǐng)到的內(nèi)存,且不可多次釋放(free釋放的是堆空間的地址)
下面看一段代碼感受一下:
#includestdio.h
#includestdlib.h
intmain()
int*p=malloc(4);//從堆空間申請(qǐng)4個(gè)字節(jié)當(dāng)作int類型的變量使用
if(p!=NULL)//如果申請(qǐng)失敗p為0,即:空值
*p=100;
printf("%d\n",*p);
free(p);
p=malloc(4*sizeof(int));
if(p!=NULL)
inti=0;
for(i=0;ii++)
p[i]=i*10;
for(i=0;ii++)
printf("%d\n",p[i]);
free(p);
return0;
}
下面為輸出結(jié)果:
小結(jié)
堆空間是程序中預(yù)留且可用的內(nèi)存區(qū)域void*指針只能能夠保存地址,但無法獲取內(nèi)存數(shù)據(jù)void*指針可與其它數(shù)據(jù)指針相互賦值malloc申請(qǐng)內(nèi)存后,應(yīng)該判斷是否申請(qǐng)成功free只能釋放申請(qǐng)到的內(nèi)存,且不可多次釋放
七、指針專題經(jīng)典問題剖析
多級(jí)指針
可以定義指針的指針保存其它指針變量的地址
如:
Typev;
Type*pv=
Type**ppv=
type***pppv=ppv;
下面看一段代碼:
#includestdio.h
#includestdlib.h
intmain()
inta=0;
intb=1;
int*p=
int**pp=
**pp=2;//a=2;
*pp=//p=
*p=3;//b=3;
printf("a=%d,b=%d\n",a,b);
return0;
}
下面為輸出結(jié)果:
*pp就是取pp里面的內(nèi)容,而pp里面存的內(nèi)容是p的地址,所以*pp就相當(dāng)于p的內(nèi)容,而p的內(nèi)容就是a的地址,所以說**p就相當(dāng)于a,**p=2也就是把2賦值給a,*pp=b即為p=b,所以*p=3,就是把3賦值給b。
下面再看一段代碼:
#includestdio.h
#includestdlib.h
intgetDouble(double**pp,unsignedn)
intret=0;
double*pd=malloc(sizeof(double)*n);
if(pd!=NULL)
printf("pd=%p\n",pd);
*pp=pd;
ret=1;
returnret;
intmain()
double*p=NULL;
if(getDouble(p,5))
printf("p=%p\n",p);
free
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 車工高級(jí)工考試題及答案
- 中藥學(xué)解剖學(xué)試題及答案
- 浪漫的英文詩詞
- 1-3單元英語語音題目及答案
- 心肌梗塞病人的家庭護(hù)理
- 腸道微生物代謝產(chǎn)物與IBD癌變的相關(guān)性
- 衛(wèi)生執(zhí)法美容院管理制度
- 衛(wèi)生院犬傷門診工作制度
- 衛(wèi)生院防火安全管理制度
- 衛(wèi)生保潔防疫制度
- 學(xué)校教師情緒管理能力提升
- 2026年中國郵政儲(chǔ)蓄銀行招聘試題含答案
- 2025年度電氣工程師述職報(bào)告
- 檔案館機(jī)房設(shè)施設(shè)備管理制度
- 2025年中國抑郁障礙防治指南
- 2024年輕工行業(yè)經(jīng)濟(jì)運(yùn)行報(bào)告
- 電解銅銷售合同范本
- FGR的基因檢測策略與臨床解讀
- 建筑施工工地安全隱患排查清單
- 電力工程安全培訓(xùn)課件
- 中糧貿(mào)易錄用通知書
評(píng)論
0/150
提交評(píng)論