C語(yǔ)言指針用法總結(jié)
1、先談?wù)剝?nèi)存與地址
引例:
計(jì)算機(jī)的內(nèi)存看成大街上的一排房屋,每個(gè)房屋都要有門牌號(hào),這個(gè)就相當(dāng)于計(jì)算機(jī)的內(nèi)存地址,而房屋里面住的人、家具等等就相當(dāng)于需要存放的各種各樣的數(shù)據(jù),所以要想訪問這些數(shù)據(jù)就得知道它的內(nèi)存地址。
**bit:計(jì)算機(jī)的內(nèi)存便是由數(shù)以億萬(wàn)計(jì)的位(bit)**組成,每個(gè)位的容納值為0或1。
- byte:字節(jié),一個(gè)字節(jié)包含8個(gè)位(bit),可以儲(chǔ)存無符號(hào)unsigned類型的值為0-255(28-1),儲(chǔ)存有符號(hào)signed類型的值為-128到127。無符號(hào)類型就是非負(fù)數(shù),而有符號(hào)類型就是負(fù)數(shù),0,正數(shù)。它也是可尋址的最小內(nèi)存塊。
- word:字,是儲(chǔ)存的基本單位,在計(jì)算機(jī)內(nèi)存中基本是以一個(gè)word來儲(chǔ)存數(shù)據(jù)的。
在16位的系統(tǒng)中(比如8086微機(jī)) 1字 (word)= 2字節(jié)(byte)= 16(bit)
在32位的系統(tǒng)中(比如win32) 1字(word)= 4字節(jié)(byte)=32(bit)
在64位的系統(tǒng)中(比如win64)1字(word)= 8字節(jié)(byte)=64(bit)
地址與字節(jié)的關(guān)系:
拿我本人的機(jī)器來舉例吧,我的操作系統(tǒng)是64位的,1word=8byte=64bit,int類型在內(nèi)存中占4個(gè)字節(jié)(64位+VS),
所以地址是4個(gè)連在一起的數(shù)字,用一般取地址符&輸出的是變量的首地址。
地址就是以字節(jié)做單位的。指針類型占4個(gè)字節(jié)。
C類型所占字節(jié)數(shù):
補(bǔ)充:數(shù)據(jù)類型所占的字節(jié)數(shù)或者位數(shù)實(shí)際上與操作系統(tǒng)的位數(shù)和編譯器(不同的編譯器支持的位數(shù)可能有所不同),反正具體某種數(shù)據(jù)類型所占的字節(jié)數(shù)是編譯器根據(jù)操作系統(tǒng)的位數(shù)決定的,用例如==sizeof()==測(cè)一下就好。
C類型 | 32位(所占字節(jié)數(shù)) | 64位(所占字節(jié)數(shù)) |
---|---|---|
char | 1個(gè)字節(jié) | 1 |
short int | 2 | 2 |
int | 4 | 4 |
wchar_t | 2(寬字符) | 2 |
char16_t | 2(unicode字符) | 2 |
char32_t | 4(unicode字符) | 4 |
float | 4(6位有效數(shù)字) | 4 |
double | 8(10位有效數(shù)字) | 8 |
int * | 4 | 4 |
int i;//int類型占兩個(gè)字節(jié),16位(64位操作系統(tǒng)占4個(gè)字節(jié)),i在內(nèi)存起始地址為6申請(qǐng)了2個(gè)字節(jié)的內(nèi)存空間,并命名為i char a;//char類型占一個(gè)字節(jié),8位,a在地址為8上申請(qǐng)了1字節(jié)的內(nèi)存空間,并命名為a
//將30存入變量i的內(nèi)存空間 i=30; //將字符't'存入變量a的內(nèi)存空間 a='t'; //通過取地址符&,輸出變量的首地址6 cout<<"i的地址為:"<<&i<<endl; //輸出變量i所儲(chǔ)存的值 cout<<"i的值為:"<<i<<endl; //通過取地址符&,輸出變量的首地址8 cout<<"a的地址為:"<<&a<<endl; //輸出變量i所儲(chǔ)存的值 cout<<"a的值為:"<<a<<endl;
2、再談指針
//假設(shè)pi占2個(gè)字節(jié)寬度,實(shí)際上32位系統(tǒng)中,指針占4個(gè)字節(jié) //指針變量pi在起始地址為8上申請(qǐng)了2個(gè)字節(jié)的內(nèi)存空間 int *pi; //將變量i的起始地址賦值給pi,所以pi的值為i的起始地址 pi=&i; //輸出指針變量p的首地址11 cout<<"pi的地址為:"<<&pi<<endl; //輸出變量i的首地址,因?yàn)閜i的值被賦予為i的首地址 cout<<"pi的值為:"<<pi<<endl; //通過解引用符*訪問到變量i所儲(chǔ)存的值 cout<<"pi所指向的值:"<<*pi<<endl; *pi=20;//將通過解引用運(yùn)算符訪問到變量i并賦值為20,pi的值和地址都沒有變化 cout<<"i的值為:"<<i<<endl;
變量pi的值就是分配給變量pi的內(nèi)存空間所儲(chǔ)存的數(shù)據(jù),在上面這個(gè)例子中就是被賦予i的首地址6!
3、區(qū)別指針的類型,指針?biāo)傅念愋停羔樀闹?/h2>
(1)、指針的類型:
從語(yǔ)法角度看,把指針聲明語(yǔ)句里面的指針變量的名字去掉,剩下的就是指針的類型。
(2)、指針?biāo)傅念愋停?/h3>
從語(yǔ)法角度看,就是把指針聲明語(yǔ)句中的指針變量的名字和名字左邊的指針聲明符*去掉,剩下的就是指針?biāo)傅念愋土恕?/p>
(3)、指針的值:
**指針的值本是指針變量自身所儲(chǔ)存的數(shù)值,但是例如int p1=&i;p1的值為i的地址,可分解為兩句int p1;p1=&i;這樣就不難理解了,p1所儲(chǔ)存的值就是i的首地址,因?yàn)?amp;i表示變量i的首地址。
在32位程序中(4個(gè)字節(jié)的程序),所有類型的指針的值都是一個(gè)32位的整數(shù)。因?yàn)?2位程序里的內(nèi)存地址都是32位長(zhǎng)(4個(gè)byte)。
簡(jiǎn)而言之,指針的值占4個(gè)字節(jié),所以說指針指向了i的內(nèi)存空間,輸出的值為i這塊內(nèi)存區(qū)域的首地址。
4、指針的算術(shù)運(yùn)算:
int i=0; int *p=&i; cout<<p<<endl;//輸出的是變量p保留的i的首地址 ++p;//p的值加了4(sizeof(int)=1) cout<<p<<endl;//輸出的值為i的首地址+4
一個(gè)指針 ptrold 加(減)一個(gè)整數(shù) n 后,結(jié)果是一個(gè)新的指針 ptrnew,ptrnew 的類型和 ptrold 的類型相同,ptrnew 所指向的類型和 ptrold所指向的類型也相同。ptrnew 的值將比 ptrold 的值增加(減少)了 n 乘sizeof(ptrold 所指向的類型)個(gè)字節(jié)。就是說,ptrnew 所指向的內(nèi)存區(qū)將比 ptrold 所指向的內(nèi)存區(qū)向高(低)地址方向移動(dòng)了 n 乘sizeof(ptrold 所指向的類型)個(gè)字節(jié)。
指針和指針進(jìn)行加減:
兩個(gè)指針不能進(jìn)行加法運(yùn)算
,這是非法操作,因?yàn)檫M(jìn)行加法后,得到的結(jié)果指向一個(gè)不知所向的地方,而且毫無意義。兩個(gè)指針可以進(jìn)行減法操作,但必須類型相同
,一般用在數(shù)組方面,不多說了。
5、運(yùn)算符&和*:
這里&是取地址運(yùn)算符
,*是間接運(yùn)算符
,也叫解引用操作符。
重點(diǎn)理解(&a)=20:*
&a表示變量a的地址,(&a)表示通過a的地址找到a,然后通過解引用符給其賦值為20。(int *p=&a; *p=20;這里的p就相當(dāng)于&a,這樣就比較好理解了。)
p 的運(yùn)算結(jié)果就五花八門了。總之p 的結(jié)果是 p 所指向的東西,這個(gè)東西有這些特點(diǎn):它的類型是 p 指向的類型,它所占用的地址是 p所指向的地址。
6、指針與數(shù)組的關(guān)系:
int a[]={1,2,3,4,5}; int i; i=a[0];//i=*a; i=a[3];//i=*(a+3)
數(shù)組名a代表數(shù)組本身,類型為int [],但是如果把a(bǔ)看作指針的話,它指向數(shù)組的第0個(gè)單元,類型為int *,所指向的類型為int。
下面總結(jié)一下數(shù)組的數(shù)組名(數(shù)組中儲(chǔ)存的也是數(shù)組)的問題:
聲明了一個(gè)數(shù)組 TYPE array[n],則數(shù)組名稱 array 就有了兩重含義:
- 第一,它代表整個(gè)數(shù)組,它的類型是 TYPE[n];
- 第二 ,它是一個(gè)常量指針,該指針的類型是 TYPE*,該指針指向的類型是 TYPE,也就是數(shù)組單元的類型,該指針指向的內(nèi)存區(qū)就是數(shù)組第 0 號(hào)單元,該指針自己占有單獨(dú)的內(nèi)存區(qū),注意它和數(shù)組第 0 號(hào)單元占據(jù)的內(nèi)存區(qū)是不同的。該指針的值是不能修改的,即類似 array++的表達(dá)式是錯(cuò)誤的。
在不同的表達(dá)式中數(shù)組名 array 可以扮演不同的角色:
在表達(dá)式 sizeof(array)中,數(shù)組名 array 代表數(shù)組本身,故這時(shí)sizeof 函數(shù)測(cè)出的是整個(gè)數(shù)組的大小。
在表達(dá)式array 中,array 扮演的是指針,因此這個(gè)表達(dá)式的結(jié)果就是數(shù)組第 0 號(hào)單元的值。sizeof(*array)測(cè)出的是數(shù)組單元的大小。
表達(dá)式 array+n(其中 n=0,1,2,…)中,array 扮演的是指針,故 array+n 的結(jié)果是一個(gè)指針,它的類型是 TYPE *,它指向的類型是 TYPE,它指向數(shù)組第 n 號(hào)單元。故sizeof(array+n)測(cè)出的是指針類型的大小。在 32 位程序中結(jié)果是 4。
sizeof(int(*)[10])=4
sizeof(int[10])=40
sizeof(ptr)=4
實(shí)際上,sizeof(對(duì)象)測(cè)出的都是對(duì)象自身的類型的大小,而不是別的什么類型的大小。
7、const int *pi與int *const pi:
const int i與int const i沒有區(qū)別,const int *pi也與int const *pi沒有區(qū)別,int與const那個(gè)放前放后都是一樣的。
重點(diǎn)是*在const的左邊還是右邊:
- 1) 如果 const 修飾在* pi的左邊,則不能改的是* pi(即不能類似這樣:* pi=50;賦值)而不是指 pi。
只有通過給指針?biāo)虻淖兞抠x值,才能是*pi改變:
pi=&i;i=20;cout<<*pi<<endl; - 2) 如果 const 是直接寫在 pi 前,則 pi 不能改(即不能類似這樣:pi=&i;賦值),pi的地址永遠(yuǎn)只能指向初始化時(shí)的內(nèi)存地址了,可以直接修改i的值,也可以通過 * pi來修改i的值。
補(bǔ)充:
情況一:int *pi 指針指向 const int i 常量的情況
const int i1 = 40;
int * pi;
pi = &i1;
//const int 類型的 i1 的地址是不能賦值給指向 int 類型地址的指針 pi 的。否則 pi 豈不是能修改 i1 的值了嗎!
pi = (int * ) &i1;//強(qiáng)制類型轉(zhuǎn)換可是 C 所支持的。
*p1=80;//編譯能過但是i1的值還是40
情況二:const int *pi 指針指向 const int i1 的情況
const int i1=40;
const int * pi;
pi=&i1;//兩個(gè)類型相同,可以這樣賦值。很顯然,i1 的值無論是通過pi 還是 i1 都不能修改的。
情況三:用 const int *const pi 聲明的指針
int i;
const int * const pi=&i; //你能想象 pi 能夠作什么操作嗎?
pi值不能改,也不能通過 pi 修改 i 的值。因?yàn)椴还苁?pi 還是 pi 都是 const的。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++11新特性中auto 和 decltype 區(qū)別和聯(lián)系
這篇文章主要介紹了C++11新特性中auto 和 decltype 區(qū)別和聯(lián)系的相關(guān)資料,需要的朋友可以參考下2017-01-01C++實(shí)現(xiàn)LeetCode(137.單獨(dú)的數(shù)字之二)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(137.單獨(dú)的數(shù)字之二),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語(yǔ)言 函數(shù)指針(指向函數(shù)的指針)詳解
本文主要介紹 C語(yǔ)言函數(shù)指針的知識(shí),這里整理了詳細(xì)的資料及示例代碼以便大家學(xué)習(xí)參考,有需要學(xué)習(xí)此部分知識(shí)的朋友可以參考下2016-08-08C語(yǔ)言實(shí)現(xiàn)掃雷游戲詳細(xì)代碼
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷游戲的具體步驟和詳細(xì)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11C++實(shí)現(xiàn)LeetCode(21.混合插入有序鏈表)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(21.混合插入有序鏈表),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07獲取當(dāng)前系統(tǒng)本地時(shí)間,精確到毫秒的實(shí)例
下面小編就為大家?guī)硪黄@取當(dāng)前系統(tǒng)本地時(shí)間,精確到毫秒的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11Qt使用SqlLite實(shí)現(xiàn)權(quán)限管理的示例代碼
本文主要介紹了Qt使用SqlLite實(shí)現(xiàn)權(quán)限管理的示例代碼,管理員針對(duì)不同人員進(jìn)行權(quán)限設(shè)定,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09