當(dāng)前位置:首頁(yè) > IT課程問(wèn)答
什么是指針?
在C語(yǔ)言中,操作系統(tǒng)屏蔽掉所有的硬件存儲(chǔ)器,為程序員提供了一個(gè)類似數(shù)組的內(nèi)存空間;
這個(gè)內(nèi)存空間的基本單位是字節(jié),也是程序員能夠操作的基本單位。
指針就是每塊基本單位大小的內(nèi)存的地址,通常被叫做地址或者地址編號(hào)。將字節(jié)大小的內(nèi)存
分別進(jìn)行編號(hào),有助于我們對(duì)于內(nèi)存的使用。
用來(lái)存放指針的變量就是指針變量,這也是程序員通常所說(shuō)的指針。以下所有的指針變量統(tǒng)稱
為指針。
聲明指針的格式:
存儲(chǔ)類型指針類型*指針名;
eg:char*p;
int*p;等
存儲(chǔ)類型:
不單獨(dú)聲明時(shí),有兩種情況
情況1:局部定義指針時(shí),默認(rèn)為auto類型。表示當(dāng)進(jìn)入代碼塊時(shí),系統(tǒng)為自動(dòng)變量分配內(nèi)存.
在塊內(nèi),這些變量被定義,并被認(rèn)為他是局部于本塊的.當(dāng)退出塊時(shí),系統(tǒng)釋放分配給自動(dòng)變量的
內(nèi)存,因此,變量值就丟失了.重新進(jìn)入塊,系統(tǒng)會(huì)為自動(dòng)變量再次分配內(nèi)存,原先的值已經(jīng)沒(méi)有
了。
情況2:全局定義指針時(shí),默認(rèn)為extern類型。表示為該變量永久的分配存儲(chǔ),直到當(dāng)前進(jìn)程
運(yùn)行結(jié)束。全局變量在整個(gè)程序執(zhí)行期間都是存在的。
指針類型:
由于指針保存的是地址,所以地址相關(guān)的變量或者結(jié)構(gòu),都可以作為指針的類型;
如:char、short、int、long等基本類型所定義的指針類型就是char*、short*、int*、
long*等
指針也可以保存數(shù)組的地址,該指針就變成了數(shù)組指針;指針也可以保存結(jié)構(gòu)體變量的地址,
該指針就變成了結(jié)構(gòu)體指針;指針也可以保存函數(shù)的地址,該指針就變成了函數(shù)指針;
*號(hào):
*號(hào)有兩個(gè)作用:
作用1:在定義時(shí),和普通變量做區(qū)分,如果沒(méi)有*號(hào),那就和普通變量的定義格式一致,沒(méi)
有任何的區(qū)別了;
作用2:在使用時(shí),*變量名這個(gè)形式表示拿到指針保存的地址上的數(shù)據(jù);后面詳細(xì)說(shuō);
指針名:
指針名是一個(gè)標(biāo)識(shí)符,要符合標(biāo)識(shí)符的命名規(guī)范;
注:標(biāo)識(shí)符的命名規(guī)范:
1、由數(shù)字、字母、下劃線組成
2、不能以數(shù)字開(kāi)頭
3、不能和關(guān)鍵字沖突,嚴(yán)格區(qū)分大小寫(xiě)
指針的大?
指針的大小和類型沒(méi)有關(guān)系,和CPU的運(yùn)行時(shí)的尋址位數(shù)有關(guān)系;
在32位操作系統(tǒng)中,32位CPU一次最大能夠訪問(wèn)32位數(shù)據(jù),所以指針的大小就是32位,即4
字節(jié);
在64位操作系統(tǒng)中,64位CPU一次最大能夠訪問(wèn)64位數(shù)據(jù),所以指針的大小就是64位,即8
字節(jié);
驗(yàn)證:
使用64位編譯器:
linux@ubuntu:~$gcc01test.c
linux@ubuntu:~$./a.out
sizeof(char*)=8
sizeof(short*)=8
sizeof(int*)=8
sizeof(long*)=8
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
printf("sizeof(char*)=%ld\n",sizeof(char*));
printf("sizeof(short*)=%ld\n",sizeof(short*));
printf("sizeof(int*)=%ld\n",sizeof(int*));
printf("sizeof(long*)=%ld\n",sizeof(long*));
return0;
}
使用32位編譯器:
linux@ubuntu:~$gcc01test.c-m32
linux@ubuntu:~$./a.out
sizeof(char*)=4
sizeof(short*)=4
sizeof(int*)=4
sizeof(long*)=4
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
printf("sizeof(char*)=%d\n",sizeof(char*));
printf("sizeof(short*)=%d\n",sizeof(short*));
printf("sizeof(int*)=%d\n",sizeof(int*));
printf("sizeof(long*)=%d\n",sizeof(long*));
return0;
}
指針類型有什么作用?
由于一個(gè)指針只能保存一個(gè)地址,一個(gè)地址僅僅代表一個(gè)字節(jié)內(nèi)存,而通常情況下,程序員定
義變量都不不止使用一個(gè)字節(jié);所以如何讓指針訪問(wèn)到占有多個(gè)字節(jié)內(nèi)存的變量的其他數(shù)據(jù),
就是通過(guò)指針類型;
指針類型決定著指針一次能夠訪問(wèn)的最大內(nèi)存空間;
舉例:
linux@ubuntu:~$./a.out
a=0x12345678
p=0x7fff5eec899c
*p=0x12345678//當(dāng)指針類型和指針?biāo)4孀兞康念愋拖嗤瑫r(shí),能夠正常獲取到變
量的數(shù)據(jù)
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
inta=0x12345678;//定義一個(gè)變量a,保存16進(jìn)制數(shù)0x1234567,總共占4字節(jié)
int*p=&a;//定義一個(gè)指針,保存變量a的地址
printf("a=%#x\n",a);//#號(hào)表示數(shù)字前導(dǎo)符,16進(jìn)制的前導(dǎo)符,是0x,%x表示打印
16進(jìn)制數(shù)
printf("p=%p\n",p);//由于指針p中保存的是地址,打印地址用%p
printf("*p=%#x\n",*p);//*p表示取到指針保存的地址上的數(shù)據(jù),*p<==>a
return0;
}
這是我們正常使用指針,保證使用的指針類型和保存的數(shù)據(jù)類型一致,防止數(shù)據(jù)丟失;以上示
例中,指針能夠正常取到變量a的4個(gè)字節(jié)內(nèi)存上的所有數(shù)據(jù);
如果將上述示例修改:
linux@ubuntu:~$./a.out
a=0x12345678
p=0x7ffe4b4f344c
*p=0x78//當(dāng)指針類型和指針?biāo)4孀兞康念愋筒煌瑫r(shí),不能夠正常獲取變量的數(shù)據(jù)
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
inta=0x12345678;//定義一個(gè)變量a,保存16進(jìn)制數(shù)0x1234567,總共占4字節(jié)
char*p=(char*)&a;//定義一個(gè)char*類型的指針,保存int類型的變量a的地址,
由于類型不一致,編譯器會(huì)報(bào)警告,所以將&a的類型強(qiáng)制轉(zhuǎn)換為char*類型。消除警告;
printf("a=%#x\n",a);
printf("p=%p\n",p);
printf("*p=%#x\n",*p);
return0;
}
由上述示例得知,當(dāng)指針類型和指針?biāo)4孀兞康念愋筒煌瑫r(shí),不能夠正常獲取變量的數(shù)據(jù),
指針?biāo)@取到的數(shù)據(jù)大小由指針決定;
0x78總共占1個(gè)字節(jié),和char*類型的指針,所能訪問(wèn)的數(shù)據(jù)長(zhǎng)度一致;
如何使用指針?
指針的使用只需要記住兩點(diǎn)
1、指針保存的是已定義的變量地址,不能保存未經(jīng)定義的常量和地址;
2、指針提供另一種操作變量數(shù)據(jù)的方法,主要和*號(hào)有關(guān);
指針是怎么進(jìn)行偏移的?
指針的偏移,就是指針的運(yùn)算,指針和普通變量一樣,也是可以進(jìn)行運(yùn)算的,但是和普通變量
不一樣的是,普通變量的運(yùn)算是對(duì)普通變量中保存的數(shù)據(jù)繼續(xù)寧運(yùn)算,而指針的運(yùn)算和指針類
型有關(guān)。
最常使用的指針偏移操作為:p++或者p--等
示例:
linux@ubuntu:~$./a.out
p=0x7ffddc670170//這是指針p中保存的地址
*p=10//這是指針p中保存的地址上的數(shù)據(jù),發(fā)現(xiàn)為*p==str[0]
p=0x7ffddc670174//這是指針p進(jìn)行偏移,即p++之后,指針p中保存的地址
*p=20//這是指針p中保存的地址上的數(shù)據(jù),發(fā)現(xiàn)為*p==str[1]
p=0x7ffddc670178//這是指針p再次進(jìn)行偏移,即p++之后,指針p中保存的地址
*p=30//這是指針p中保存的地址上的數(shù)據(jù),發(fā)現(xiàn)為*p==str[2]
linux@ubuntu:~$cat01test.c
#include<stdio.h>
intmain(intargc,constchar*argv[])
{
intstr[5]={10,20,30,40,50};//定義一個(gè)數(shù)組,有5位元素,每位元素都是int類型
的
int*p=str;//定義一個(gè)int*類型的指針,當(dāng)前保存的是數(shù)組的首地址,也是數(shù)字首位
元素的地址,str作為數(shù)組名,也表示數(shù)組的首地址
printf("p=%p\n",p);//打印當(dāng)前首元素的地址
printf("*p=%d\n",*p);//打印首位元素
p++;//指針進(jìn)行偏移,等價(jià)于p=p+1;表示指針p像后偏移1次,并不是表示p中的
地址加1,地址怎么變化取決于指針類型
printf("p=%p\n",p);
printf("*p=%d\n",*p);
p++;
printf("p=%p\n",p);
printf("*p=%d\n",*p);
return0;
}
由示例可以發(fā)現(xiàn),對(duì)于int*類型的指針,雖然只是進(jìn)行p++操作,但是真正的地址的運(yùn)算卻是
+4;和指針類型有關(guān);
綜上所述:
1、指針保存的是地址,地址是內(nèi)存中每一個(gè)字節(jié)大小空間的編號(hào)
2、指針的*號(hào)可以幫助指針獲得指針保存地址上的數(shù)據(jù)內(nèi)容
3、指針的類型決定指針?biāo)軌蛟L問(wèn)的內(nèi)存大小,指針類型還和指針偏移有關(guān)
4、指針大小固定,32位系統(tǒng)中占4字節(jié),64位系統(tǒng)中占8字節(jié)
5、指針不能使用常量和未使用的地址進(jìn)行初始化,會(huì)出現(xiàn)野指針