指針是c語(yǔ)言的一個(gè)重要的數(shù)據(jù)類型,在C語(yǔ)言程序設(shè)計(jì)中,利用指針可以直接對(duì)內(nèi)存中的各種不同的數(shù)據(jù)進(jìn)行快速處理,同時(shí)也為函數(shù)之間各類數(shù)據(jù)的傳遞提供了便捷的方法,指針操作是與計(jì)算機(jī)系統(tǒng)內(nèi)部資源密切相關(guān)的一種處理方式.
- 地址
我們知道,一個(gè)程序一旦被執(zhí)行,程序中的指令,常量,變量等都要儲(chǔ)存在計(jì)算機(jī)內(nèi)存中.計(jì)算機(jī)的內(nèi)存是以字節(jié)為單位的一片連續(xù)的存儲(chǔ)空間.每個(gè)字節(jié)都有一個(gè)編號(hào).這個(gè)編號(hào)就稱為內(nèi)存地址.沒(méi)有地址,沒(méi)有編號(hào).系統(tǒng)則無(wú)法對(duì)內(nèi)存進(jìn)行管理.
內(nèi)存的存儲(chǔ)空間是連續(xù)的,所以其地址(編號(hào))也是連續(xù)的.地址與儲(chǔ)存單元一一對(duì)應(yīng).而且是存儲(chǔ)單元的唯一標(biāo)志.需要注意的是儲(chǔ)存單元的地址與儲(chǔ)存單元中的內(nèi)容是兩回事.
我們知道,在高級(jí)語(yǔ)言中,變量可以直接通過(guò)變量名,變量類型來(lái)開(kāi)辟一個(gè)內(nèi)存空間,儲(chǔ)存我們的變量?jī)?nèi)容,并且我們可以直接通過(guò)變量名來(lái)對(duì)該變量的內(nèi)容進(jìn)行操作,這是因?yàn)楦呒?jí)語(yǔ)言中,變量在聲明時(shí),就為我們創(chuàng)建了一張對(duì)應(yīng)的表,將變量名與開(kāi)辟的內(nèi)存空間地址聯(lián)系起來(lái).歸根結(jié)底,還是通過(guò)變量的地址來(lái)對(duì)對(duì)應(yīng)的內(nèi)存空間進(jìn)行訪問(wèn)與操作的.
- 指針變量
而c語(yǔ)言中則提供了這樣一種變量.指針變量.指針類型的變量是用來(lái)存放地址的變量.從定義來(lái)看,指針變量是一個(gè)變量,它和普通變量一樣,是占用一定內(nèi)存空間的.但是它是用來(lái)存放地址的.這意味著它一般是用來(lái)對(duì)其他變量進(jìn)行操作的.
當(dāng)把某一個(gè)地址量賦予指針變量時(shí),則該指針變量就指向了那個(gè)地址的內(nèi)存區(qū)域.這樣做的目的就是為了能夠通過(guò)這種指向變量地址的方式,來(lái)實(shí)現(xiàn)間接對(duì)某一內(nèi)存區(qū)域中存儲(chǔ)的內(nèi)容進(jìn)行處理.
指針變量指向的內(nèi)存區(qū)域中的數(shù)據(jù)稱為指針的目標(biāo),如果它指向一個(gè)變量的內(nèi)存空間,則該變量稱為指針的目標(biāo)變量.通過(guò)指針變量訪問(wèn)目標(biāo)變量的方式叫間接訪問(wèn)方式.
指針不僅僅可以指向變量的地址,還可以指向內(nèi)存中的其他任何數(shù)據(jù)結(jié)構(gòu),如數(shù)組,結(jié)構(gòu),和聯(lián)合體,還可以指向函數(shù).這將使指針能夠做的事情更加強(qiáng)大.
在程序中參與處理的量不是指針,指針本身只是一個(gè)地址量,其指向的目標(biāo)才是要處理的數(shù)據(jù).
- 指針的定義:
類別名 數(shù)據(jù)類型 *指針名
int *px
char *pchar
static int *pa
指針的數(shù)據(jù)類型不是指針變量本身的數(shù)據(jù)類型,而是指向目標(biāo)的數(shù)據(jù)類型,因?yàn)橹羔樧兞恐甘居脕?lái)存放其指向目標(biāo)的地址,所以其類型也應(yīng)當(dāng)與其保持一致.
- 指針的初始化:
int a;
int *p = &a;
&a就是一個(gè)地址常量.它就是變量a的內(nèi)存地址.當(dāng)將一個(gè)變量的地址賦值給一個(gè)指針時(shí),它必須是已經(jīng)聲明過(guò)的(定義),因?yàn)樽兞康目臻g是動(dòng)態(tài)分配的,只有預(yù)先聲明了該變量.才會(huì)為其分配內(nèi)存空間.
當(dāng)然指針變量還可以被指向一個(gè)地址變量.也就是指針之間可以進(jìn)行賦值操作.將一個(gè)指針變量賦值給另一個(gè)指正變量.
int n;
int *p = &n;
int *q = p;
看兩個(gè)例子:
// 指針概念
void PointConcept(int b) {
int a = b;
int* pa = &a;
printf("a:%d\n",a);
printf("*pa:%d\n",*pa);
printf("&a:%x(HEX)\n",&a); // %x以十六進(jìn)制輸出.
printf("pa:%x(HEX)\n",pa);
printf("&pa:%x(HEX)\n",&pa);
}

這里可以看到,&a,pa指向的都是變量a的內(nèi)存地址.而&pa指向是指針變量pa的內(nèi)存地址.這說(shuō)明指針變量具有與普通變量一樣性質(zhì),只不過(guò)它的內(nèi)存空間存放的是目標(biāo)數(shù)據(jù)的地址.所以其本身的地址是不同的.
- 指針變量的長(zhǎng)度:
// 指針長(zhǎng)度
void PointerLen() {
char str[] = "abcdefg", * ps =str;
int i = 10, * pi = &i;
float f = 45.45, * pf = &f;
double d = 354.33, * pd = &d;
printf("size of str pointer is byte=%d,bit=%d\n",sizeof(ps),8*sizeof(ps));
printf("size of str pointer is byte=%d,bit=%d\n",sizeof(pi),8*sizeof(pi));
printf("size of str pointer is byte=%d,bit=%d\n",sizeof(pf),8*sizeof(pf));
printf("size of str pointer is byte=%d,bit=%d\n",sizeof(pd),8*sizeof(pd));
}

我們可以看到,四種類型的指針變量的長(zhǎng)度都是相同的,所以指針變量的長(zhǎng)度不是根據(jù)指針變量的類型來(lái)定的,指針變量的類型只是對(duì)應(yīng)其指向目標(biāo)的數(shù)據(jù)類型.
指針存放的是其指向目標(biāo)的首地址,而不是其目標(biāo)數(shù)據(jù)全部地址
為什么指針只需要指向目標(biāo)數(shù)據(jù)的首地址,并且其類型必須要與其指向的目標(biāo)數(shù)據(jù)類型保持一致呢.這就是因?yàn)閮?nèi)存單元的連續(xù)性,其地址都是連續(xù),指針只需要知道指向目標(biāo)的首地址,和指向目標(biāo)的數(shù)據(jù)類型(相當(dāng)于知道了數(shù)據(jù)長(zhǎng)度).就可以實(shí)現(xiàn)完全讀取到目標(biāo)數(shù)據(jù)的所有內(nèi)存地址了.
所以,指針變量在內(nèi)存中的長(zhǎng)度大小是不變的,4byte,32bit.只需要用來(lái)存放目標(biāo)數(shù)據(jù)的首地址就可以了.
- &(取地址運(yùn)算符)和*(指針運(yùn)算符)
&運(yùn)算符
我們?cè)谥羔樀亩x與初始化中了解到了,我們需要使用到*號(hào)來(lái)聲明一個(gè)指針變量,使用&獲取到目標(biāo)變量的地址,然后賦值給指針變量.
使用&運(yùn)算符操作的對(duì)象必須是左值表達(dá)式(即變量或有名存儲(chǔ)區(qū)).
int x; // 則&x的類型就是int*(整形指針)
char y; // 則&y的類型就是 char* (字符型指針)
double z; // &z的類型就是double* (雙精度浮點(diǎn)型指針)
需要注意的一點(diǎn)是:數(shù)組,常量,不是左值表達(dá)式.而寄存器變量沒(méi)有存儲(chǔ)地址,所以他們都不能作為單目運(yùn)算符&的操作對(duì)象.
int a[4];
register int k;
// 使用&a[0],&a[1]都是合法的,但是不能使用&a,&k.
指針運(yùn)算符*
單目是間接訪問(wèn)運(yùn)算符,它通過(guò)指針間接訪問(wèn)所指的對(duì)象.而不是通過(guò)名稱訪問(wèn)的,所以稱為間接訪問(wèn).與訪問(wèn)對(duì)象組成的表達(dá)式,稱為間接訪問(wèn)表達(dá)式:
* 操作對(duì)象
char a;
* (&a); // 地址表達(dá)式
*pa=&a; //地址表達(dá)式,將a變量的地址賦值給了pa,然后通過(guò)*指針?lè)赶騪a指向的本身.
操作對(duì)象必須是一個(gè)地址表達(dá)式.即指針(地址表達(dá)式,或地址常量),運(yùn)算結(jié)果為指針?biāo)傅膶?duì)象(變量本身).結(jié)果類型為指針?biāo)笇?duì)象的類型.
char c,*pc=&c; //變量聲明且初始化了指針變量pc存放c的地址.
*pc='a'; // 通過(guò)指針?lè)?間接訪問(wèn)指針變量pc所指向的c變量的內(nèi)存區(qū)),賦值.
*(&c)='a'; // 直接通過(guò)指針?lè)?間接訪問(wèn)c地址指向的數(shù)據(jù)內(nèi)存區(qū)),賦值
c='a'; // 直接通過(guò)變量名賦值.
單目運(yùn)算符*和&的運(yùn)算關(guān)系
他們互為逆運(yùn)算,即*指向的是指針變量的指向目標(biāo)變量,&獲取的是指向目標(biāo)的內(nèi)存地址.即:
*(&左值表達(dá)式)=左值表達(dá)式;
int c;
*(&c); //指向的就是c本身.
&(*左值表達(dá)式)=地址表達(dá)式;