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