概述
指針也就是內(nèi)存地址,指針變量是用來(lái)存放內(nèi)存地址的變量, 不同類(lèi)型的指針變量所占用的存儲(chǔ)單元長(zhǎng)度是相同的,而存放數(shù)據(jù)的變量因數(shù)據(jù)的類(lèi)型不同,所占用的存儲(chǔ)空間長(zhǎng)度也不同 。有了指針以后,不僅可以對(duì)數(shù)據(jù)本身,也可以對(duì)存儲(chǔ)數(shù)據(jù)的變量地址進(jìn)行操作。 指針是一個(gè)占據(jù)存儲(chǔ)空間的實(shí)體在這一段空間起始位置的相對(duì)距離值。在C/C++語(yǔ)言中,指針一般被認(rèn)為是指針變量,指針變量的內(nèi)容存儲(chǔ)的是其指向的對(duì)象的首地址,指向的對(duì)象可以是變量(指針變量也是變量),數(shù)組,函數(shù)等占據(jù)存儲(chǔ)空間的實(shí)體。
指針
數(shù)據(jù)存儲(chǔ)在內(nèi)存中,內(nèi)存又被分為一塊一塊的,每一塊都有一個(gè)特有的編號(hào)。而這個(gè)編號(hào)可以暫時(shí)理解為指針,就像房屋的編號(hào)。特點(diǎn)的房間可以找到特點(diǎn)的人,例如張三要去找李四,那么就要去到李四家,才能找到李四。 總結(jié)一下,其實(shí)指針就是變量,用來(lái)存放地址的變量(存放在指針中的值都當(dāng)成地址處理)。
指針運(yùn)算符
&:取地址運(yùn)算符&是用來(lái)取操作對(duì)象的地址,它返回運(yùn)算對(duì)象的內(nèi)存地址。 *:指針運(yùn)算符&作用是通過(guò)操作對(duì)象的地址,獲取存儲(chǔ)的內(nèi)容也稱為“間接引用操作符”。
示例
#include
int main()
{
int a = 10; //定義一個(gè)普通變量a,賦值為10
int* pa;//定義指針變量pa
pa = &a;//通過(guò)取地址符&,獲取a的地址,賦值給指針變量pa
printf("a的值為:%d,pa的地址為=%p,*pa的值為=%d
",a,pa,*pa);
return 0;
}
指針類(lèi)型
變量有不同的類(lèi)型,整型,浮點(diǎn)型等等。指針同樣是有類(lèi)型的,定義如下。
char* pa = NULL;
int* pb = NULL;
short* pc = NULL;
long* pd = NULL;
float* pe = NULL;
double* pf = NULL;
指針類(lèi)型的定義方式就是type + 。其實(shí)上面代碼中char 就是為了存放char類(lèi)型變量的地址,short*就是為了存放short類(lèi)型變量的地址。其他同樣。
示例
#include
int main()
{
char a = 'a';
int b = 10;
short c = 20;
long d = 30;
float e = 40.0;
double f = 50.0;
char* pa = NULL;
int* pb = NULL;
short* pc = NULL;
long* pd = NULL;
float* pe = NULL;
double* pf = NULL;
pa = &a;
pb = &b;
pc = &c;
pd = &d;
pe = &e;
pf = &f;
printf("a的值為:%d,pa的地址為=%p,pa的下一個(gè)地址為=%p
", a, pa, pa + 1);
printf("b的值為:%d,pb的地址為=%p,pb的下一個(gè)地址為=%p
", b, pb, pb + 1);
printf("c的值為:%d,pc的地址為=%p,pc的下一個(gè)地址為=%p
", c, pc, pc + 1);
printf("d的值為:%d,pd的地址為=%p,pd的下一個(gè)地址為=%p
", d, pd, pd + 1);
printf("e的值為:%f,pe的地址為=%p,pe的下一個(gè)地址為=%p
", e, pe, pe + 1);
printf("f的值為:%lf,pf的地址為=%p,pf的下一個(gè)地址為=%p
", f, pf, pf + 1);
return 0;
}
從上述例程得知,指針加1或減1運(yùn)算,表示指針向前或向后移動(dòng)一個(gè)單元(不同類(lèi)型的指針,單元長(zhǎng)度不同),指針的類(lèi)型決定了指針向前或者向后走一步有多大距離。
指針變量的自增自減運(yùn)算。指針加 1 或減 1 運(yùn)算,表示指針向前或向后移動(dòng)一個(gè)單元(不同類(lèi)型的指針,單元長(zhǎng)度不同)。這個(gè)在數(shù)組中非常常用。 指針變量加上或減去一個(gè)整形數(shù)。和第一條類(lèi)似,具體加幾就是向前移動(dòng)幾個(gè)單元,減幾就是向后移動(dòng)幾個(gè)單元。
指針變量的初始化
指針初始化是將變量的地址分配給指針變量的過(guò)程,指針變量與其它變量一樣,在定義時(shí)可以賦值,即初始化。也可以賦值“NULL”或“0”,如果賦值“0”,此時(shí)的“0”含義并不是數(shù)字“0”,而是 NULL 的字符碼值。 指針變量在定義時(shí)如果未初始化,那么該指針就是野指針,野指針就是指針指向的位置是不可知的(隨機(jī)的、不正確的、沒(méi)有明確限制的),其值是隨機(jī)的,指針變量的值是別的變量的地址,意味著指針指向了一個(gè)地址是不確定的變量,此時(shí)去解引用就是去訪問(wèn)了一個(gè)不確定的地址,所以結(jié)果是不可知的。
關(guān)系運(yùn)算
假設(shè)有指針pa,pb,那么其關(guān)系運(yùn)算主要有下列三種。
- pa > pb,表示 pa 指向的存儲(chǔ)地址大于 pb 指向的地址。
- pa == pb,表示 pa 和 pb 指向同一個(gè)存儲(chǔ)單元。
- pa == 0 ,表示 pa 是否為空指針。
示例
#include
int main()
{
int a = 10;
int b = 20;
int* pa = NULL;
int* paa = NULL;
int* pb = NULL;
int* pc = NULL;
pa = &a;
paa = &a;
pb = &b;
printf("pa的地址是%p,pb的地址是%p,",pa,pb);
if (pa > pb)
printf("pa指向的存儲(chǔ)地址大于pb指向的地址
");
else
printf("pa指向的存儲(chǔ)地址小于pb指向的地址
");
printf("pa的地址是%p,paa的地址是%p,", pa, paa);
if (pa == paa)
printf("pa和paa是否指向同一個(gè)存儲(chǔ)單元
");
printf("pc的地址是%p,", pc);
if (pc == 0)
printf("pc是空指針");
return 0;
}
數(shù)組
一維數(shù)組
不管什么變量都有地址,數(shù)組包含若干個(gè)元素,但是每個(gè)數(shù)組元素也在內(nèi)存中占用存儲(chǔ)單元,所以也有相對(duì)應(yīng)的地址。指針變量既然可以指向變量,同樣也可以指向數(shù)組元素。 在數(shù)組中,數(shù)組名即為該數(shù)組的首地址,對(duì)該指針進(jìn)行加減,就可以實(shí)現(xiàn)指針訪問(wèn)數(shù)組元素。
示例
#include
int main()
{
int Num[5] = {11,22,33,44,55};
int* p;
int* pp;
p = &Num[0];//指向數(shù)組第一個(gè)元素,即數(shù)組首地址
pp = &Num;//直接指向數(shù)組,數(shù)組名即為數(shù)組的首地址
printf("數(shù)組的首地址Num=%p
", Num);
printf("pp所指向的地址%p
", pp);
printf("p所指向的地址是%p,數(shù)據(jù)是%d
",p,*p);
printf("Num所指向的下一個(gè)地址是%p,數(shù)據(jù)是%d
", Num + 1, *(Num + 1));//數(shù)組名即為該數(shù)組的首地址,對(duì)該指針進(jìn)行加減,就可以實(shí)現(xiàn)指針訪問(wèn)數(shù)組元素。
printf("p所指向的下一個(gè)地址是%p,數(shù)據(jù)是%d
", p+1, *(p+1));
return 0;
}
由上述的結(jié)果可以得知:
-
p 指向數(shù)組Num的第一個(gè)元素,則此操作將 Num第一個(gè)元素11,即Num[0] = 11。
-
數(shù)組名是地址,可以稱作數(shù)組地址,也可以看成第一個(gè)元素的地址,通過(guò)+整數(shù)可以移動(dòng)到想要操作的元素。
-
p+1操作為指針加整數(shù)操作,即向前移動(dòng)一個(gè)單元。此時(shí) p + 1 指向Num[0]的下一個(gè)元素,即Num[1]。通過(guò)p + 整數(shù)的操作可以移動(dòng)到想要操作的元素。
-
在 p+整數(shù)的操作要考慮邊界的問(wèn)題,如一個(gè)數(shù)組長(zhǎng)度為5,p+6的意義對(duì)于數(shù)組操作來(lái)說(shuō)沒(méi)有意義。## 二維數(shù)組
二維數(shù)組其實(shí)可以看成是一個(gè)矩陣,zai C語(yǔ)言中,定義一個(gè)數(shù)組num[3][4],可以看成是一個(gè)3行4列的矩陣,在內(nèi)存中每一個(gè)位置存儲(chǔ)一個(gè)數(shù)據(jù),用a[i][j]表示。 二維數(shù)組實(shí)際上就是元素為一維數(shù)組的數(shù)組,二維數(shù)組名可以看做指向其第一個(gè)元素(一維數(shù)組)的指針。
### 示例
#include
int main()
{
int Num[2][3] = {
{11,22,33},
{111,222,333}
};
int* p;
p = &Num[0];//指向數(shù)組第一個(gè)元素,即數(shù)組首地址
//二維數(shù)組名可以看做指向其第一個(gè)元素(一維數(shù)組)的指針,所以一級(jí)指針指向大小為一位數(shù)組大小
printf("數(shù)組的首地址是%p,一級(jí)指針的大小為%d,二級(jí)指針?biāo)赶驍?shù)據(jù)為%d
", Num, sizeof(*Num),**Num);
printf("p所指向的地址是%p,數(shù)據(jù)是%d
",p,*p);
printf("Num所指向的下一個(gè)地址是%p,數(shù)據(jù)是%d
", Num + 1, **(Num + 1));
printf("p所指向的第四個(gè)地址是%p,數(shù)據(jù)是%d
", p+3, *(p+3));
return 0;
}
字符串指針
對(duì)于字符,在計(jì)算機(jī)內(nèi)部都是用數(shù)字(字符編碼)來(lái)表示的,而字符串是“字符連續(xù)排列”的一種表現(xiàn)。字符串就是每個(gè)元素內(nèi)都存儲(chǔ)著字符的一維數(shù)組,通常稱之為字符數(shù)組。
在 C語(yǔ)言中,因?yàn)樽址麛?shù)組的元素內(nèi)存儲(chǔ)的都是 char 型的字符,所以字符數(shù)組的數(shù)據(jù)類(lèi)型是 char 型,因而字符串實(shí)際上就是一個(gè) char 型的一維數(shù)組。 在 C語(yǔ)言中,可以用兩種方法訪問(wèn)一個(gè)字符串:
- 用字符數(shù)組存放一個(gè)字符串,然后輸出該字符串
- 用字符指針指向一個(gè)字符串
字符串中包含的字符的個(gè)數(shù)就是這個(gè)字符串的長(zhǎng)度。C語(yǔ)言中用字符數(shù)組存儲(chǔ)字符串時(shí)在字符串的末端都要加一個(gè)字符“”來(lái)表示這個(gè)字符串的結(jié)束,這個(gè)“”稱為字符串結(jié)束符。因而在定義字符數(shù)組時(shí),數(shù)組大小應(yīng)為要存儲(chǔ)的字符串長(zhǎng)度的最大值加 1。
示例
#include
int main()
{
/*字符數(shù)組賦初值*/
char string1[] = { 'h','e', 'l', 'l', 'o'};
/*字符數(shù)組賦初值添加結(jié)束符*/
char string2[] = { 'h','e', 'l', 'l', 'o','' };
/*字符串賦初值*/
char string3[] = "hello";
/*用sizeof()求長(zhǎng)度*/
printf("string1的長(zhǎng)度=%d
", sizeof(string1));//輸出出現(xiàn)亂碼就是因?yàn)樽址Y(jié)尾并沒(méi)有結(jié)尾符''。
printf("string2的長(zhǎng)度=%d
", sizeof(string2));//
printf("string3的長(zhǎng)度=%d
", sizeof(string3));
/*用printf的%s打印內(nèi)容*/
printf("string1的內(nèi)容=%s
", string1);
printf("string2的內(nèi)容=%s
", string2);
printf("string3的內(nèi)容=%s
", string3);
return 0;
}
字符串指針變量本身是一個(gè)變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中并以 作為串的結(jié)束。字符數(shù)組歸根結(jié)底還是一個(gè)數(shù)組,字符串名也可以認(rèn)為是一個(gè)指針。 字符串儲(chǔ)存方式:
- 字符數(shù)組由一個(gè)或若干元素組成,每個(gè)元素存放一個(gè)字符;
- 而字符指針變量只存放字符串的首地址,不是整個(gè)字符串;
字符串存儲(chǔ)位置:
- 數(shù)組是在內(nèi)存中開(kāi)辟了一段空間用于存放字符串;
- 字符指針是在文字常量區(qū)開(kāi)辟了一段空間存放字符串,將字符串的首地址賦值給指針變量。### 示例
#include
int main()
{
char str[] = "hello world";// 棧(局部)
char* string = "hello";//文字常量區(qū)
char* string1;
string1 = "hello world";//字符指針變量另外一種賦值方法
printf("str=%s,數(shù)據(jù)大小=%d
", str, sizeof(str));//數(shù)據(jù)大小為所保存的字符大小
printf("string=%s,數(shù)據(jù)大小=%d
", string,sizeof(string));//數(shù)據(jù)大小只是保存的指針大小
printf("string1=%s,數(shù)據(jù)大小=%d
", string1,sizeof(string1));//數(shù)據(jù)大小只是保存的指針大小
return 0;
}
由上圖可以得知,數(shù)組是在內(nèi)存中開(kāi)辟了一段空間用于存放字符串,故數(shù)組越大,所占的數(shù)據(jù)大小越大;字符指針是在文字常量區(qū)開(kāi)辟了一段空間存放字符串,故字符指針是只想這個(gè)文字常量區(qū)的地址。
指針函數(shù)
指針函數(shù)就是一個(gè)返回值為指針的函數(shù),指針函數(shù)是指帶指針的函數(shù),函數(shù)返回類(lèi)型是某一類(lèi)型的指針,即本質(zhì)是一個(gè)函數(shù)。 函數(shù)定義:類(lèi)型標(biāo)識(shí)符 * 函數(shù)名(參數(shù)表) 普通的函數(shù)定義如下所示:
int fun(int x,int y);
指針函數(shù)定義如下所示:
int* fun(int x,int y);
普通的函數(shù)與指針函數(shù)只是多了一個(gè) *號(hào)的區(qū)別。上述定義的指針函數(shù)其返回值是一個(gè) int 類(lèi)型的指針,是一個(gè)地址,而上述普通函數(shù)返回的是一個(gè)int值。所以指針函數(shù)一定有函數(shù)返回值 ,同時(shí)函數(shù)返回值必須賦給同類(lèi)型的指針變量。
示例
#include
int* fun(int x, int y);//函數(shù)申明
int* fun1(int x, int y);//函數(shù)申明
int main()
{
int* p = fun(3, 4);
int* p1 = fun1(3, 4);
printf("p的地址為=%p,p所指向的數(shù)據(jù)是=%d
",p,*p);
printf("p1的地址為=%p,p1所指向的數(shù)據(jù)是=%d
", p1, *p1);
return 0;
}
/*實(shí)現(xiàn)x+y,同時(shí)返回存儲(chǔ)的地址*/
int* fun(int x, int y)
{
static int sum = 0;//靜態(tài)變量
int* p = ∑
sum = x + y;
return p;
}
/*實(shí)現(xiàn)x+y,同時(shí)返回存儲(chǔ)的地址*/
int* fun1(int x, int y)
{
int sum = 0;
int* p = ∑
sum = x + y;
return p;
}
上面示例定義了fun和fun1函數(shù),同時(shí)在函數(shù)內(nèi)用指針p指向了sum變量,但是函數(shù)執(zhí)行完之后會(huì)釋放函數(shù),雖然最后return返回了該地址的指針,但是由于空間以及釋放,故不一定會(huì)得到正確的值,需要用static去修飾變量,使得其變?yōu)殪o態(tài)變量。靜態(tài)變量一旦生成,只有在程序結(jié)束才會(huì)釋放,所以指針能一直訪問(wèn)該變量。 同樣的使用全局變量也能解決這個(gè)問(wèn)題。
函數(shù)指針
函數(shù)指針是指帶指針的函數(shù),函數(shù)指針的本質(zhì)是一個(gè)指針,該指針的地址指向了一個(gè)函數(shù),所以它是指向函數(shù)的指針。函數(shù)指針就是指向代碼段中函數(shù)入口地址的指針。
函數(shù)定義:類(lèi)型標(biāo)識(shí)符 (*函數(shù)名) (參數(shù)) 普通的函數(shù)定義如下所示:
int fun(int x,int y);
函數(shù)指針聲明格式:
int (*fun)(int x,int y);
其中,int 為返回值,(*fun)作為一個(gè)整體,代表的是指向該函數(shù)的指針,(int x,int y)為形參列表。其中fun被稱為函數(shù)指針變量 。函數(shù)指針本質(zhì)是一個(gè)指針,其指向一個(gè)函數(shù)。 函數(shù)指針與數(shù)組類(lèi)似,在數(shù)組中,數(shù)組名代表著該數(shù)組的首地址,函數(shù)也是一樣,函數(shù)名即是該數(shù)組的入口地址,因此,函數(shù)名就是該函數(shù)的函數(shù)指針。 函數(shù)指針是需要把一個(gè)函數(shù)的地址賦值給它,因此,可以采用如下的兩種方式:
p=fun;//第一種寫(xiě)法
p=&fun;//第二種寫(xiě)法
示例
#include
int (*fun)(int, int); // 聲明函數(shù)指針,指向返回值類(lèi)型為int,有兩個(gè)參數(shù)類(lèi)型都是int的函數(shù)
//int (*fun)(int a, int b); //也可以使用這種方式定義函數(shù)指針
int sum(int a, int b);
int Difference(int a, int b);
int main()
{
fun = sum; // 函數(shù)指針fun指向求和的函數(shù)sum
int c = (*fun)(1, 2);
printf("兩數(shù)之和為=%d
", c);
fun = &Difference; // 函數(shù)指針fun指向求差值的函數(shù)Difference
c = (*fun)(5, 3);
printf("兩數(shù)之差為=%d
", c);
return 0;
}
/*求最大值*/
int sum(int a, int b) {
return a+b;
}
/*求差值*/
int Difference(int a, int b) {
return a-b;
}
上面示例定義了sum求和函數(shù)和Difference求差函數(shù),可見(jiàn)函數(shù)指針fun指向函數(shù)的時(shí)候,可以添加取址符&,也可以不添加,所指向的為函數(shù)的入口。
指針函數(shù)和函數(shù)指針
定義
指針函數(shù)本質(zhì)是一個(gè)函數(shù),其返回值為指針。 函數(shù)指針本質(zhì)是一個(gè)指針,其指向一個(gè)函數(shù)。
寫(xiě)法
指針函數(shù):int* fun(int x,int y); 函數(shù)指針:int (* fun)(int x,int y);
用途
當(dāng)項(xiàng)目比較大,代碼變得復(fù)雜了以后,有許多的函數(shù)的返回值,包括函數(shù)入?yún)⒍际窍嗤模@時(shí)候如果要調(diào)用不同的排序方法,就可以使用指針函數(shù)來(lái)實(shí)現(xiàn),我們只需要修改函數(shù)指針初始化的地方,而不需要去修改每個(gè)調(diào)用的地方。
審核編輯:湯梓紅
-
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7614瀏覽量
137780 -
指針
+關(guān)注
關(guān)注
1文章
481瀏覽量
70611
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
C語(yǔ)言指針詳細(xì)解析
C語(yǔ)言指針電子教程
C語(yǔ)言指針函數(shù)和函數(shù)指針詳細(xì)介紹
c語(yǔ)言函數(shù)指針定義,指針函數(shù)和函數(shù)指針的區(qū)別
基于C語(yǔ)言中指針的基本用法解析
C語(yǔ)言教程之指針的詳細(xì)資料說(shuō)明
![<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>教程之<b class='flag-5'>指針</b>的<b class='flag-5'>詳細(xì)</b>資料說(shuō)明](https://file.elecfans.com/web1/M00/85/3B/o4YBAFxuGIyAHFXZAAEphyKrhE8021.png)
評(píng)論