程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++指針 具體引見及總結

C++指針 具體引見及總結

編輯:關於C++

C++指針 具體引見及總結。本站提示廣大學習愛好者:(C++指針 具體引見及總結)文章只能為提供參考,不一定能成為您想要的結果。以下是C++指針 具體引見及總結正文


指針的概念:

指針是一個特別的變量,它外面存儲的數值被說明成為內存裡的一個地址。要弄清一個指針須要弄清指針的四方面的內容:指針的類型,指針所指向的類型,指針的值或許叫指針所指向的內存區,還有指針自己所占領的內存區。讓我們分離解釋。

先聲明幾個指針放著做例子: 

例一: 

int *ptr; 
char *ptr; 
int **ptr; 
int (*ptr)[3]; 
int *(*ptr)[4]; 

指針的類型

從語法的角度看,你只需把指針聲明語句裡的指針名字去失落,剩下的部門就是這個指針的類型。這是指針自己所具有的類型。讓我們看看例一中各個指針的類型: 

int *ptr; //指針的類型是int * 
char *ptr; //指針的類型是char * 
int **ptr; //指針的類型是 int ** 
int (*ptr)[3]; //指針的類型是 int(*)[3] 
int *(*ptr)[4]; //指針的類型是 int *(*)[4] 

怎樣樣?找出指針的類型的辦法是否是很簡略? 

指針所指向的類型

當你經由過程指針來拜訪指針所指向的內存區時,指針所指向的類型決議了編譯器將把那片內存區裡的內容當作甚麼來對待。

從語法上看,你只須把指針聲明語句中的指針名字和名字右邊的指針聲明符*去失落,剩下的就是指針所指向的類型。例如: 

int *ptr; //指針所指向的類型是int 
char *ptr; //指針所指向的的類型是char 
int **ptr; //指針所指向的的類型是 int * 
int (*ptr)[3]; //指針所指向的的類型是 int()[3] 
int *(*ptr)[4]; //指針所指向的的類型是 int *()[4] 

在指針的算術運算中,指針所指向的類型有很年夜的感化。 

指針的類型(即指針自己的類型)和指針所指向的類型是兩個概念。當你對C愈來愈熟習時,你會發明,把與指針攪和在一路的“類型”這個概念分紅“指針的類型”和“指針所指向的類型”兩個概念,是精曉指針的症結點之一。我看了很多書,發明有些寫得差的書中,就把指針的這兩個概念攪在一路了,所以看起書來前後抵觸,越看越懵懂。

 指針的值

指針的值是指針自己存儲的數值,這個值將被編譯器看成一個地址,而不是一個普通的數值。在32位法式裡,一切類型的指針的值都是一個32位整數,由於32位法式裡內存地址全都是32位長。

指針所指向的內存區就是從指針的值所代表的誰人內存地址開端,長度為sizeof(指針所指向的類型)的一片內存區。今後,我們說一個指針的值是XX,就相當於說該指針指向了以XX為首地址的一片內存區域;我們說一個指針指向了某塊內存區域,就相當於說該指針的值是這塊內存區域的首地址。

指針所指向的內存區和指針所指向的類型是兩個完整分歧的概念。在例一中,指針所指向的類型曾經有了,但因為指針還未初始化,所以它所指向的內存區是不存在的,或許說是有意義的。

今後,每碰到一個指針,都應當問問:這個指針的類型是甚麼?指針指向的類型是甚麼?該指針指向了哪裡? 

指針自己所占領的內存區

指針自己占了多年夜的內存?你只需用函數sizeof(指針的類型)測一下就曉得了。在32位平台裡,指針自己占領了4個字節的長度。

指針自己占領的內存這個概念在斷定一個指針表達式能否是左值時很有效。  

指針的算術運算

指針可以加上或減去一個整數。指針的這類運算的意義和平日的數值的加減運算的意義是紛歧樣的。例如: 
例二: 

 char a[20]; 
 int *ptr=a; 
... 
... 
 ptr++; 

在上例中,指針ptr的類型是int*,它指向的類型是int,它被初始化為指向整形變量a。接上去的第3句中,指針ptr被加了1,編譯器是如許處置的:它把指針ptr的值加上了sizeof(int),在32位法式中,是被加上了4。因為地址是用字節做單元的,故ptr所指向的地址由本來的變量a的地址向窪地址偏向增長了4個字節。
因為char類型的長度是一個字節,所以,本來ptr是指向數組a的第0號單位開端的四個字節,此時指向了數組a中從第4號單位開端的四個字節。
我們可以用一個指針和一個輪回來遍歷一個數組,看例子: 

例三: 

int array[20]; 
int *ptr=array; 
... 
//此處略去為整型數組賦值的代碼。 
... 
for(i=0;i<20;i++) 
{ 
 (*ptr)++; 
 ptr++; 
} 

這個例子將整型數組中各個單位的值加1。因為每次輪回都將指針ptr加1,所以每次輪回都能拜訪數組的下一個單位。再看例子: 

例四: 

char a[20]; 
int *ptr = a; 
... 
... 
ptr += 5; 

在這個例子中,ptr被加上了5,編譯器是如許處置的:將指針ptr的值加上5乘sizeof(int),在32位法式中就是加上了5乘4=20。因為地址的單元是字節,故如今的ptr所指向的地址比起加5後的ptr所指向的地址來講,向窪地址偏向挪動了20個字節。在這個例子中,沒加5前的ptr指向數組a的第0號單位開端的四個字節,加5後,ptr曾經指向了數組a的正當規模以外了。固然這類情形在運用上會出成績,但在語法上倒是可以的。這也表現出了指針的靈巧性。

假如上例中,ptr是被減去5,那末處置進程年夜同小異,只不外ptr的值是被減去5乘sizeof(int),新的ptr指向的地址將比本來的ptr所指向的地址向低地址偏向挪動了20個字節。

總結一下,一個指針ptrold加上一個整數n後,成果是一個新的指針ptrnew,ptrnew的類型和ptrold的類型雷同,ptrnew所指向的類型和ptrold所指向的類型也雷同。ptrnew的值將比ptrold的值增長了n乘sizeof(ptrold所指向的類型)個字節。就是說,ptrnew所指向的內存區將比ptrold所指向的內存區向窪地址偏向挪動了n乘sizeof(ptrold所指向的類型)個字節。一個指針ptrold減去一個整數n後,成果是一個新的指針ptrnew,ptrnew的類型和ptrold的類型雷同,ptrnew所指向的類型和ptrold所指向的類型也雷同。ptrnew的值將比ptrold的值削減了n乘sizeof(ptrold所指向的類型)個字節,就是說,ptrnew所指向的內存區將比ptrold所指向的內存區向低地址偏向挪動了n乘sizeof(ptrold所指向的類型)個字節。

運算符&和*

這裡&是取地址運算符,*是...書上叫做“直接運算符”。&a的運算成果是一個指針,指針的類型是a的類型加個*,指針所指向的類型是a的類型,指針所指向的地址嘛,那就是a的地址。*p的運算成果就八門五花了。總之*p的成果是p所指向的器械,這個器械有這些特色:它的類型是p指向的類型,它所占用的地址是p所指向的地址。

例五: 

int a=12; 
int b; 
int *p; 
int **ptr; 
p=&a;//&a的成果是一個指針,類型是int*,指向的類型是int,指向的地址是a的地址。 
*p=24;//*p的成果,在這裡它的類型是int,它所占用的地址是p所指向的地址,明顯,*p就是變量a。
ptr=&p;//&p的成果是個指針,該指針的類型是p的類型加個*,在這裡是int**。該指針所指向的類型是p的類型,這裡是int*。該指針所指向的地址就是指針p本身的地址。 
*ptr=&b;//*ptr是個指針,&b的成果也是個指針,且這兩個指針的類型和所指向的類型是一樣的,所以?amp;b來給*ptr賦值就是毫無成績的了。
**ptr=34;//*ptr的成果是ptr所指向的器械,在這裡是一個指針,對這個指針再做一次*運算,成果就是一個int類型的變量。

指針表達式

一個表達式的最初成果假如是一個指針,那末這個表達式就叫指針表達式。上面是一些指針表達式的例子: 

例六: 

int a,b; 
int array[10]; 
int *pa; 
pa=&a;//&a是一個指針表達式。 
int **ptr=&pa;//&pa也是一個指針表達式。 
*ptr=&b;//*ptr和&b都是指針表達式。 
pa=array; 
pa++;//這也是指針表達式。

例七: 

char *arr[20]; 
char **parr=arr;//假如把arr看做指針的話,arr也是指針表達式 
char *str; 
str=*parr;//*parr是指針表達式 
str=*(parr+1);//*(parr+1)是指針表達式 
str=*(parr+2);//*(parr+2)是指針表達式 

因為指針表達式的成果是一個指針,所以指針表達式也具有指針所具有的四個要素:指針的類型,指針所指向的類型,指針指向的內存區,指針本身占領的內存。

好了,當一個指針表達式的成果指針曾經明白地具有了指針本身占領的內存的話,這個指針表達式就是一個左值,不然就不是一個左值。 在例七中,&a不是一個左值,由於它還沒有占領明白的內存。*ptr是一個左值,由於*ptr這個指針曾經占領了內存,其實*ptr就是指針pa,既然pa曾經在內存中有了本身的地位,那末*ptr固然也有了本身的地位。

數組和指針的關系

假如對聲明數組的語句不太明確的話,請參閱我前段時光貼出的文章<<若何懂得c和c++的龐雜類型聲明>>。 數組的數組名其實可以看做一個指針。看下例: 

例八: 

int array[10]={0,1,2,3,4,5,6,7,8,9},value; 
... 
... 
value=array[0];//也可寫成:value=*array; 
value=array[3];//也可寫成:value=*(array+3); 
value=array[4];//也可寫成:value=*(array+4); 

上例中,普通而言數組名array代表數組自己,類型是int [10],但假如把array看作指針的話,它指向數組的第0個單位,類型是int *,所指向的類型是數組單位的類型即int。是以*array等於0就一點也不奇異了。同理,array+3是一個指向數組第3個單位的指針,所以*(array+3)等於3。其它依此類推。

例九: 

char *str[3]={ 
"Hello,this is a sample!", 
"Hi,good morning.", 
"Hello world" 
}; 
char s[80]; 
strcpy(s,str[0]);//也可寫成strcpy(s,*str); 
strcpy(s,str[1]);//也可寫成strcpy(s,*(str+1)); 
strcpy(s,str[2]);//也可寫成strcpy(s,*(str+2)); 

上例中,str是一個三單位的數組,該數組的每一個單位都是一個指針,這些指針各指向一個字符串。把指針數組名str看成一個指針的話,它指向數組的第0號單位,它的類型是char**,它指向的類型是char *。

*str也是一個指針,它的類型是char*,它所指向的類型是char,它指向的地址是字符串"Hello,this is a sample!"的第一個字符的地址,即'H'的地址。 str+1也是一個指針,它指向數組的第1號單位,它的類型是char**,它指向的類型是char *。

*(str+1)也是一個指針,它的類型是char*,它所指向的類型是char,它指向"Hi,good morning."的第一個字符'H',等等。 

上面總結一下數組的數組名的成績。聲清楚明了一個數組TYPE array[n],則數組稱號array就有了兩重寄義:第一,它代表全部數組,它的類型是TYPE [n];第二,它是一個指針,該指針的類型是TYPE*,該指針指向的類型是TYPE,也就是數組單位的類型,該指針指向的內存區就是數組第0號單位,該指針本身占領零丁的內存區,留意它和數組第0號單位占領的內存區是分歧的。該指針的值是不克不及修正的,即相似array++的表達式是毛病的。

在分歧的表達式中數組名array可以飾演分歧的腳色。 

在表達式sizeof(array)中,數組名array代表數組自己,故這時候sizeof函數測出的是全部數組的年夜小。 

在表達式*array中,array飾演的是指針,是以這個表達式的成果就是數組第0號單位的值。sizeof(*array)測出的是數組單位的年夜小。 

表達式array+n(個中n=0,1,2,....。)中,array飾演的是指針,故array+n的成果是一個指針,它的類型是TYPE*,它指向的類型是TYPE,它指向數組第n號單位。故sizeof(array+n)測出的是指針類型的年夜小。

例十: 

int array[10]; 
int (*ptr)[10]; 
ptr=&array; 

上例中ptr是一個指針,它的類型是int (*)[10],他指向的類型是int [10],我們用全部數組的首地址來初始化它。在語句ptr=&array中,array代表數組自己。

本節中提到了函數sizeof(),那末我來問一問,sizeof(指針稱號)測出的畢竟是指針本身類型的年夜小呢照樣指針所指向的類型的年夜小?謎底是前者。例如:

int (*ptr)[10]; 

則在32位法式中,有: 

sizeof(int(*)[10])==4 
sizeof(int [10])==40 
sizeof(ptr)==4 

現實上,sizeof(對象)測出的都是對象本身的類型的年夜小,而不是其余甚麼類型的年夜小。  

指針和構造類型的關系

可以聲明一個指向構造類型對象的指針。 

例十一: 

struct MyStruct 
{ 
int a; 
int b; 
int c; 
} 

MyStruct ss={20,30,40};//聲清楚明了構造對象ss,並把ss的三個成員初始化為20,30和40。
MyStruct *ptr=&ss;//聲清楚明了一個指向構造對象ss的指針。它的類型是
MyStruct*,它指向的類型是MyStruct。
int *pstr=(int*)&ss;//聲清楚明了一個指向構造對象ss的指針。然則它的類型和它指向的類型和ptr是分歧的。

請問如何經由過程指針ptr來拜訪ss的三個成員變量? 

謎底: 

ptr->a; 
ptr->b; 
ptr->c; 

又請問如何經由過程指針pstr來拜訪ss的三個成員變量? 

謎底:  

*pstr;//拜訪了ss的成員a。 
*(pstr+1);//拜訪了ss的成員b。 
*(pstr+2)//拜訪了ss的成員c。 

呵呵,固然我在我的MSVC++6.0上調式過上述代碼,然則要曉得,如許應用pstr來拜訪構造成員是不正軌的,為了解釋為何不正軌,讓我們看看如何經由過程指針來拜訪數組的各個單位:

例十二: 

int array[3]={35,56,37}; 
int *pa=array; 

經由過程指針pa拜訪數組array的三個單位的辦法是: 

*pa;//拜訪了第0號單位 
*(pa+1);//拜訪了第1號單位 
*(pa+2);//拜訪了第2號單位 

從格局上看卻是與經由過程指針拜訪構造成員的不正軌辦法的格局一樣。

一切的C/C++編譯器在分列數組的單位時,老是把各個數組單位寄存在持續的存儲區裡,單位和單位之間沒有閒暇。但在寄存構造對象的各個成員時,在某種編譯情況下,能夠會須要字對齊或雙字對齊或許是其余甚麼對齊,須要在相鄰兩個成員之間加若干個“填充字節”,這就招致各個成員之間能夠會有若干個字節的閒暇。

所以,在例十二中,即便*pstr拜訪到了卻構對象ss的第一個成員變量a,也不克不及包管*(pstr+1)就必定能拜訪到構造成員b。由於成員a和成員b之間能夠會有若干填充字節,說不定*(pstr+1)就正好拜訪到了這些填充字節呢。這也證實了指針的靈巧性。如果你的目標就是想看看各個構造成員之間究竟有無填充字節,嘿,這卻是個不錯的辦法。

經由過程指針拜訪構造成員的准確辦法應當是象例十二中應用指針ptr的辦法。

指針和函數的關系

可以把一個指針聲明成為一個指向函數的指針。 

int fun1(char*,int); 
int (*pfun1)(char*,int); 
pfun1=fun1; 
.... 
.... 
int a=(*pfun1)("abcdefg",7);//經由過程函數指針挪用函數。 

可以把指針作為函數的形參。在函數挪用語句中,可以用指針表達式來作為實參。 

以上就是對C++ 指針的材料整頓,後續持續彌補相干材料感謝年夜家對本站的支撐!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved