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