C語言學(xué)習(xí)之指針的使用詳解_第1頁(yè)
C語言學(xué)習(xí)之指針的使用詳解_第2頁(yè)
C語言學(xué)習(xí)之指針的使用詳解_第3頁(yè)
C語言學(xué)習(xí)之指針的使用詳解_第4頁(yè)
C語言學(xué)習(xí)之指針的使用詳解_第5頁(yè)
已閱讀5頁(yè),還剩19頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第C語言學(xué)習(xí)之指針的使用詳解目錄一、指針概念1.指針變量2.指針類型3.二級(jí)指針二、野指針1.野指針成因2.規(guī)避野指針三、指針運(yùn)算1.指針整數(shù)2.指針-指針3.指針關(guān)系運(yùn)算四、指針數(shù)組1.指針和數(shù)組2.指針數(shù)組的概念五、字符指針六、數(shù)組指針七、數(shù)組傳參和指針傳參1.一維數(shù)組傳參2.二維數(shù)組傳參3.一級(jí)指針傳參4.二級(jí)指針傳參八、函數(shù)指針九、函數(shù)指針數(shù)組十、回調(diào)函數(shù)

一、指針概念

在學(xué)習(xí)指針之前我們先要了解一下內(nèi)存,內(nèi)存是存儲(chǔ)區(qū)域,我們可以把內(nèi)存劃分成一個(gè)一個(gè)的內(nèi)存單元,最小的內(nèi)存單元是字節(jié)

計(jì)算機(jī)將數(shù)據(jù)存儲(chǔ)在內(nèi)存中,而為了能夠快速查找到所需數(shù)據(jù),計(jì)算機(jī)會(huì)將內(nèi)存進(jìn)行編號(hào),通過查找編號(hào),可以快速查找到數(shù)據(jù)。指針是內(nèi)存中一個(gè)最小單元的編號(hào),內(nèi)存單元的編號(hào)也被稱為地址,指針就是地址。

平時(shí)我們說的指針通常指的是指針變量,是用來存放內(nèi)存地址的變量

1個(gè)字節(jié)(byte)=8個(gè)bit(bit即比特位,由0和1組成)

在32位的機(jī)器上(X86環(huán)境),地址是32個(gè)0或者1組成二進(jìn)制序列,那地址就得用4個(gè)字節(jié)的空間來存儲(chǔ),所以一個(gè)指針變量的大小就應(yīng)該是4個(gè)字節(jié)。在64位的機(jī)器上(X64環(huán)境),地址是64個(gè)0或者1組成二進(jìn)制序列,那地址就得用8個(gè)字節(jié)的空間來存儲(chǔ),所以一個(gè)指針變量的大小是8個(gè)字節(jié)。

無論何種數(shù)據(jù)類型的指針,指針的大小在32位(X86環(huán)境)平臺(tái)下是4個(gè)字節(jié),在64位(X64環(huán)境)平臺(tái)下是8個(gè)字節(jié)。

1.指針變量

我們可以通過(取地址操作符)取出變量的內(nèi)存起始地址,把地址可以存放到一個(gè)變量中,這個(gè)變量就是指針變量。

*(解引用操作符又叫間接訪問操作符):對(duì)指針變量進(jìn)行解引用操作,通過指針變量里面的地址找到指向的內(nèi)容。

#includestdio.h

intmain()

inta=20;

charch;

int*pa=//a向內(nèi)存申請(qǐng)了4個(gè)字節(jié)的空間,所以a的時(shí)候應(yīng)該拿出第1個(gè)字節(jié)的地址

//拿出a的第1個(gè)字節(jié)的地址放在整型指針變量pa里

char*pc=//拿出ch的地址放在字符指針變量pc里

printf("%p\n",//%p打印的是地址

//printf("%p\n",pa);打印出來的地址和a打印出來的一樣

printf("%p\n",ch);

return0;

指針變量是用來存放地址的變量,存放在指針變量中的值都被當(dāng)成地址處理,同時(shí)地址是唯一標(biāo)識(shí)一個(gè)內(nèi)存單元的

2.指針類型

指針的類型根據(jù)你所需要的數(shù)據(jù)類型進(jìn)行使用,如

//char*pc;指針類型是char*//char**pcc;指針類型是char**//int*pa;指針類型是int*//double*pd;指針類型是double*//

但是要注意區(qū)分指針指向的類型和指針類型之間的區(qū)別

//char*pc;其中*指pc是指針,指向的類型是char//char**pcc;其中*指pcc是指針,指向的類型是char*//int*pa;*指pa是指針,指向的類型是int//double*pd;*指pd是指針,指針指向的類型是double//

指針類型決定了指針進(jìn)行解引用操作時(shí)訪問幾個(gè)字節(jié)

char*類型的指針解引用訪問1個(gè)字節(jié);

int*類型的指針解引用訪問4個(gè)字節(jié);

double*類型的指針解引用訪問8個(gè)字節(jié);

例1:

#includestdio.h

intmain()

inta=0x11223344;//用16進(jìn)制表示

int*pa=

*pa=0;

return0;

上述代碼在VS(小端存儲(chǔ))調(diào)試過程中,a在內(nèi)存中顯示的是

執(zhí)行完*pa=0;后,a在內(nèi)存中變?yōu)?/p>

將例1中的指針類型改為char*類型,用char*類型的指針接收a的地址

int*和char*類型的指針都能將int類型的a存放,因?yàn)樵?2位平臺(tái)下,指針類型的大小都是4個(gè)字節(jié)。

#includestdio.h

intmain()

inta=0x11223344;//用16進(jìn)制表示

char*pc=

*pc=0;

return0;

上述代碼在VS(小端存儲(chǔ))調(diào)試過程中,a在內(nèi)存中顯示的是

執(zhí)行完*pc=0;語句后,內(nèi)存變化為

通過上述兩個(gè)代碼塊執(zhí)行后內(nèi)存中的變化可以驗(yàn)證指針類型決定了指針進(jìn)行解引用操作時(shí)訪問幾個(gè)字節(jié)

指針類型決定了指針的步長(zhǎng),指針加減整數(shù)的時(shí)候向前或者向后走一步走多大距離

(char*)+1------跳過一個(gè)char類型的大小,也就是向后走1個(gè)字節(jié);

(int*)+1------跳過一個(gè)int類型的大小,也就是向后走4個(gè)字節(jié);

(double*)+1------跳過一個(gè)double類型的大小,也就是向后走8個(gè)字節(jié);

#includestdio.h

intmain()

inta=0x11223344;

int*pa=

char*pc=

printf("%p\n",pa);

printf("%p\n",pc);

printf("%p\n",pa+1);

printf("%p\n",pc+1);

return0;

上述代碼的運(yùn)行結(jié)果為

說明指針加減整數(shù)時(shí)的步長(zhǎng)和指針指向的類型有關(guān)

練習(xí)1:

我們可以通過一個(gè)練習(xí)對(duì)其有更好的理解:將數(shù)組arr中每個(gè)元素賦值為對(duì)應(yīng)下標(biāo),arr[0]為0;arr[1]為1

#includestdio.h

intmain()

intarr[10]={0};

int*p=arr;//p指向arr數(shù)組的首元素地址

inti=0;

for(i=0;ii++)

*(p++)=i;//將數(shù)組元素賦值;

//后置++,對(duì)p進(jìn)行解引用,賦值之后,再向后走int類型的大小,即4個(gè)字節(jié),依次循環(huán)

for(i=0;ii++)

printf("%d",arr[i]);

return0;

運(yùn)行結(jié)果如圖

3.二級(jí)指針

#includestdio.h

intmain()

inta=10;

int*p=

int**pp=//pp就是二級(jí)指針

*p=20;//可以將a修改成20

**pp=30;//可以將a修改成30

printf("%d\n",a);

return0;

二、野指針

野指針就是指針指向的位置是不可知的,(隨機(jī)的、不正確的、沒有明確限制的)

1.野指針成因

1.指針未初始化

#includestdio.h

intmain()

int*p;//p沒有初始化,p就是野指針

*p=20;//賦值

return0;

2.指針越界訪問

#includestdio.h

intmain()

intarr[10]={0};

inti=0;

intsz=sizeof(arr)/sizeof(arr[0]);//計(jì)算arr數(shù)組中元素個(gè)數(shù)

int*p=arr;

for(i=0;i=sz;i++)//共循環(huán)11次

*p++=i;

return0;

當(dāng)p越過arr已有空間去越界訪問的時(shí)候就是野指針了,之前不是野指針。

當(dāng)指針指向的范圍超出數(shù)組arr的范圍時(shí),p就是野指針

3.指針指向的空間釋放

#includestdio.h

int*test()

intnum=100;//num是局部變量,進(jìn)函數(shù)創(chuàng)建,函數(shù)結(jié)束時(shí)銷毀

returnnum;//返回的是棧空間的地址

intmain()

int*p=test();//接收到地址,但是地址并不指向num,不知道指向的是哪里,所以*p=200并不知道修改的是哪里

//雖然接收到地址,但是num已經(jīng)銷毀

*p=200;

return0;

2.規(guī)避野指針

1.指針初始化

#includestdio.h

intmain()

inta=10;

int*pa=//明確指針

int*pa=NULL;//當(dāng)pa不知道指向哪里時(shí),置空

//NULL就是用來初始化指針的

//*pa=20;//error,在對(duì)指針置空之后不能這樣使用,NULL屬于系統(tǒng)(內(nèi)核),不能訪問

return0;

2.小心指針越界問題

3.指針指向空間釋放,及時(shí)置NULL;

#includestdio.h

#includestdlib.h//malloc的頭文件

intmain()

//動(dòng)態(tài)申請(qǐng)內(nèi)存空間

int*p=(int*)malloc(40);

//使用

//釋放

free(p);

p=NULL;

return0;

4.避免返回局部變量的地址,即避免返回棧空間的地址,這樣可以盡量避免指針指向的空間釋放這種情況。

5.指針使用之前檢查有效性

三、指針運(yùn)算

1.指針整數(shù)

指針整數(shù)是根據(jù)指針指向的數(shù)據(jù)類型大小向前或者向后走多少個(gè)字節(jié)。

//char*pc;pc+1就是向后走一個(gè)char類型大小的字節(jié);//int*pa;pa+1就是向后走一個(gè)int類型大小的字節(jié);//double*pd;pd+1就是向后走一個(gè)double類型大小的字節(jié);//

在練習(xí)1中已經(jīng)對(duì)其用法進(jìn)行簡(jiǎn)單演示。

2.指針-指針

兩個(gè)指針相減的前提是:指針指向的是同一塊連續(xù)的空間,且是同一種類型的指針。

指針和指針相減的絕對(duì)值是指針之間的元素個(gè)數(shù)

#includestdio.h

intmain()

intarr[10]={0};

printf("%d\n",arr[9]-arr[0]);//9

printf("%d\n",arr[9]-arr[0]);//-9

return0;

練習(xí)2:

模擬實(shí)現(xiàn)strlen,strlen函數(shù)在對(duì)字符串中的字符進(jìn)行統(tǒng)計(jì)時(shí),遇見\0停止。

#includestdio.h

intmy_strlen(constchar*arr)

constchar*start=arr;//將arr數(shù)組首元素地址賦給start

constchar*end=arr;

while(*end)

end++;

returnend-start;

intmain()

chararr[]="abcdef";

intlen=my_strlen(arr);

printf("%d",len);//6

return0;

3.指針關(guān)系運(yùn)算

#includestdio.h

intmain()

inti=0;

intarr[10]={0};

int*p=arr[10];

for(p=arr[10];parr[0])

*--p=0;//先將p向前移動(dòng)4個(gè)字節(jié),再對(duì)p賦值;

for(i=0;ii++)

printf("%d",arr[i]);//全為0

return0;

指針關(guān)系運(yùn)算的標(biāo)準(zhǔn)規(guī)定:允許指向數(shù)組元素的指針與指向數(shù)組最后一個(gè)元素后面的那個(gè)內(nèi)存位置的指針比較,但是不允許指向數(shù)組元素的指針與指向數(shù)組第一個(gè)元素前面的那個(gè)內(nèi)存位置的指針進(jìn)行比較。

四、指針數(shù)組

1.指針和數(shù)組

指針和數(shù)組不是一個(gè)東西,指針是一個(gè)變量,是用來存放地址的,4/8個(gè)字節(jié);數(shù)組能夠存放一組數(shù),是一個(gè)連續(xù)的空間,數(shù)組的大小取決于元素個(gè)數(shù)。

聯(lián)系:數(shù)組名就是地址(指針);數(shù)組把首元素的地址交給一個(gè)指針變量之后,可以通過指針來訪問數(shù)組。

2.指針數(shù)組的概念

//chararr[n]字符數(shù)組:存放字符的數(shù)組

//intarr[n]整型數(shù)組:存放整型的數(shù)組

指針數(shù)組:存放指針的數(shù)組

//char*arr[n]字符指針數(shù)組:存放字符指針的數(shù)組

//int*arr[n]整型指針數(shù)組:存放整型指針的數(shù)組

練習(xí)3:

通過指針數(shù)組打印a,b,c,d的值

#includestdio.h

intmain()

inta=10;

intb=20;

intc=30;

intd=40;

int*arr[4]={a,b,c,

for(i=0;ii++)

printf("%d",*(arr[i]));

return0;

運(yùn)行結(jié)果為

練習(xí)4:

用一維數(shù)組模擬二維數(shù)組,打印出各個(gè)數(shù)組的值

#includestdio.h

intmain()

intarr1[4]={1,2,3,4};

intarr2[4]={2,3,4,5};

int*arr[2]={arr1,arr2};//指針數(shù)組中存放的是每個(gè)數(shù)組中首元素的地址

inti=0;

for(i=0;ii++)

intj=0;

for(j=0;jj++)

printf("%d",arr[i][j]);

//arr[i][j]還可以寫為*(arr[i]+j)或者*(*(arr+i)+j);arr是數(shù)組首元素的地址

printf("\n");

return0;

運(yùn)行結(jié)果為

練習(xí)5:

用指針數(shù)組打印字符串

#includestdio.h

intmain()

char*arr[4]={"abc","bcd","cde","def"};//常量字符串

//arr中存放的是每個(gè)字符串中首個(gè)字符的地址

inti=0;

for(i=0;ii++)

printf("%s\n",arr[i]);//%s打印字符串,只要有字符串起始地址就可以打印

return0;

運(yùn)行結(jié)果為

五、字符指針

在指針的類型中,我們知道有一種指針類型叫字符指針char*。

#includestdio.h

intmain()

char*pc="abcdef";

printf("%s\n",pc);//abcdef

printf("%c",*pc);//a

return0;

字符指針可以存放字符串的起始地址,把字符串首元素的地址存在pc中,但這種做法不合理;abcdef是常量字符串,不能修改,這時(shí)讓*pc=w程序會(huì)崩,可以將char*pc=abcdef修改為constchar*pc=abcdef,const放在*的左邊,限制*pc,不能改變字符串內(nèi)容。

練習(xí)6:

判斷下列代碼的輸出內(nèi)容;

#includestdio.h

intmain()

chararr1[]="abcdef";

chararr2[]="abcdef";

constchar*arr3="abcdef";

constchar*arr4="abcdef";

if(arr1==arr2)//數(shù)組名表示數(shù)組首元素的地址,比較地址是否相同

printf("arr1andarr2aresame\n");

else

printf("arr1andarr2arenotsame\n");

if(arr3==arr4)

printf("arr3andarr4aresame\n");

else

printf("arr3andarr4arenotsame\n");

return0;

輸出結(jié)果為

if(arr1==arr2)和if(arr3==arr4)比較的是他們的首元素地址是否相同。

數(shù)組名是數(shù)組首元素的地址,arr1和arr2是數(shù)組,他們的首元素地址不同,所以他們不相同。

而arr3和arr4是char*類型的指針,他們指向的是常量字符串,常量字符串在內(nèi)存中只保存一份,地址相同,所以arr3和arr4指向的都是a的地址。

六、數(shù)組指針

//char*pc字符指針-指向字符的指針,存放字符變量的地址

//int*pa整型指針-指向整型的指針,存放整型變量的地址

//int(*p)[n]數(shù)組指針-指向數(shù)組的指針,存放數(shù)組的地址,p是數(shù)組指針變量

數(shù)組指針在一維數(shù)組里面的應(yīng)用

voidprint(int(*p)[5])

inti=0;

for(i=0;ii++)

printf("%d",(*p)[i]);

intmain()

intarr[5]={1,2,3,4,5};

print(arr);//arr取的是整個(gè)數(shù)組的地址

return0;

運(yùn)行結(jié)果為

注意是數(shù)組指針也是指針,p應(yīng)該先與*結(jié)合,再與[]結(jié)合,(*p)要用()括起來

數(shù)組指針很少在一維數(shù)組中應(yīng)用,一般在二維數(shù)組中應(yīng)用

voidprint(int(*p)[5],introw,intcol)

inti=0;

for(i=0;irow;i++)

intj=0;

for(j=0;jcol;j++)

printf("%d",*(*(p+i)+j));

printf("\n");

intmain()

intarr[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};

print(arr,3,5);

return0;

運(yùn)行結(jié)果

數(shù)組名相當(dāng)于數(shù)組首元素的地址,對(duì)于二維數(shù)組來說,首元素理解為他的第0行,p里面存的是第0行的地址,p是數(shù)組指針類型,p+1相當(dāng)于向后走了5個(gè)int類型的大小,p+1指向第1行,(p+i)指向的就是第i行的地址。*(p+i)相當(dāng)于第i行的數(shù)組名;*(p+i)=p[i]。

擴(kuò)展:int(*p[10])[5]p是數(shù)組,有10個(gè)元素,每個(gè)元素都是數(shù)組指針,每個(gè)數(shù)組指針指向一個(gè)具有5個(gè)int類型的數(shù)組的地址。我們可以說p是存放數(shù)組指針的數(shù)組。

七、數(shù)組傳參和指針傳參

1.一維數(shù)組傳參

數(shù)組傳參,形參可以是數(shù)組,也可以是指針。

intarr[10]={0}傳參,他的參數(shù)用數(shù)組接收可以是intarr[]或者intarr[10];用指針接收是int*arr。

int*arr[10]={0}傳參,他的參數(shù)用數(shù)組接收是int*arr[10],用指針接收是int**arr。

2.二維數(shù)組傳參

intarr[3][5]傳參,他的參數(shù)用數(shù)組接收是intarr[3][5]或者intarr[][5],用指針接收int(*arr)[5]。

3.一級(jí)指針傳參

int*p傳參,參數(shù)部分直接寫成指針形式:int*p。

4.二級(jí)指針傳參

int**p傳參,參數(shù)部分直接寫成指針形式:int**p。

八、函數(shù)指針

#includestdio.h

intAdd(intx,inty)

returnx+y;

intmain()

inta=10;

intb=20;

int(*pf)(int,int)=Add;

//int(*pf)(int,int)中,int是函數(shù)返回類型,pf是函數(shù)指針變量,(int,int)是函數(shù)的參數(shù)類型

//intret=Add(a,b);

intret=(*pf)(a,b);//輸出結(jié)果是30

//使用函數(shù)指針時(shí),也可以省略*

//intret=pf(a,b);

printf("%d",ret);

return0;

九、函數(shù)指針數(shù)組

函數(shù)指針數(shù)組:可以存放多個(gè)返回類型相同和參數(shù)相同的函數(shù)的地址。

我們通過構(gòu)造一個(gè)簡(jiǎn)單的計(jì)算器來實(shí)現(xiàn)對(duì)函數(shù)指針數(shù)組的應(yīng)用

voidmenu()

printf("******************\n");

printf("**1.Add2.Sub**\n");

printf("**3.Mul4.Div**\n");

printf("**0.exit**\n");

printf("******************\n");

intAdd(intx,inty)//加法

returnx+y;

intSub(intx,inty)//減法

returnx-y;

intMul(intx,inty)//乘法

returnx*y;

intDiv(intx,inty)//除法

returnx/y;

intmain()

intinput=0;

intx=0;

inty=0;

intret=0;

int(*pf[5])(int,int)={0,Add,Sub,Mul,Div};//利用數(shù)組下標(biāo)引用函數(shù)

menu();

printf("請(qǐng)選擇

scanf("%d",input);

if(input==0)//input為0時(shí),直接退出計(jì)算器

printf("退出計(jì)算器\n");

break;

if(input=1input=4)//判斷input是否符合要求

printf("請(qǐng)輸入兩個(gè)操作數(shù):");

scanf("%d%d",x,

ret=(*pf[input])(x,y);

printf("結(jié)果為%d\n",ret);

else

printf("選擇錯(cuò)誤\n");//input不符合要求,給與提示

}while(input);

return0;

擴(kuò)展:指向函數(shù)指針數(shù)組的指針int(*(*pf)[5])(int,int)=pf。

十、回調(diào)函數(shù)

回調(diào)函數(shù)就是一個(gè)通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來調(diào)用其所指向的函數(shù)時(shí),我們就說這是回調(diào)函數(shù)。回調(diào)函數(shù)不是

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論