我們跳過虛擬內存的部分,假設程序全部加載到內存;
只需要暫時理解虛擬內存就是爲了讓20G大小的dota可以在8G內存片的電腦上運行的機制。
虛擬內存可以參考:https://blog.csdn.net/HeXiQuan123/article/details/95093877
首先:地址的單位是byte,一個字節,等同於8位二進制。所以說即使只是一個bool型變量,也至少佔據8bit=1byte的空間。
其次:1.指針的用法: int *p=&a; p是p,p是&a,但是*p就是a ; 星號稱爲解引用符號,&稱之爲取地址符號
2.指針的大小: 指針的值就是儲存好的地址,既然是地址,那自然可以根據地址值找到對應的地址,如何尋址呢?所以就要看一個地址有幾位,對於32位機器,任何一個字節的地址長度爲32位,所以指針就是32位,存儲32位的地址,即指向任何類型的指針都需要且只需要佔用4byte的內存,(64位機則是8byte的內存,方便期間只說32位機器)。這裏4byte指的是指針自己的大小,而不是被指着的對象的大小,被指着的對象可以是個char=1byte,int=4byte,或者說自己定義的結構體的大小:
指針 | 指針大小 byte | 被指着的類型大小 |
int *p=&i; | 4=sizeof(p) | 4byte=sizeof(i) |
char *p=&c | 4=sizeof(p) | 1 byte=sizeof(c) |
S* p=&s; | 4=sizeof(p) | 8byte=sizeof(s) |
其中struct S{int a;int b;};結構體的大小是有準則要求的,比較複雜可以參考《C與指針》
3.內存中指針和對象存在哪裏存的是什麼:
當我們把1byte看做一格,4G內存條的地址就從
00000000000000000000000000000000-11111111111111111111111111111111(別數了就是32位)總共約4000000000格。第幾個格子地址就是幾
我們程序加載到內存中後,假設佔據的是,第1000格到第2000格
我們的程序加載到內存後,比如這裏有一個int a=0;會在內存中找4個格子把他放進去比如第1050-1053個格子,地址就是1050(編譯期間的事情暫時不用在意細節);
如果代碼中還有一個int *p1=&a;,還有個int**p2=&p1;
指針前面說了,需要在內存中佔據一席之地即4byte;假設p1是1025-1028;p2是1015-1018;
則p2這4byte=32bit的32位中存儲的值是1025;是指針,指向int型指針的指針
p1這4byte=32位的32位中存儲的值是1050;是指針,int型的指針
a這4byte=32位的32位中存儲的值是0;是int型
int a=0 | a=0 | 1050到1053地址上寫的是0 |
int*p1=&a | p1=1050 | 1025到1028地址上寫的是1050 |
int**p2=&p1 | p2=1025 | 1015-1018地址是寫的是1025 |
4.考慮數組和指針的關係:首先,數組大小是一個常量,常量和變量區別很大,int常量可以用const來聲明,如果覺得難以理解可以先跳過
int n=5;
int a[n]={1,2,3,4,5};一定會報錯
const int n=5;
int a[n]={1,2,3,4,5};正確
上下的區別就是n是變量和n是常量,數字5就是常量,int n=5就是變量,延伸後其實有左值右值之分,比較複雜這裏不討論;
因爲數組大小是個常量,所以這時取值a[100]就是個越界值,會報錯
數組在內存中是連續存儲,所以上述a[n]佔據了20byte,分別爲5個連續的4byte,比如從地址1000-1019;
我們看出來,數組的頭4byte即a[0]是一個int值,那麼,int *p=&a[0],可以讓p指向這個數組,並且由於指針沒有界限,所以*(p+100)就越界了,但是這樣寫代碼,編譯器並不會報錯而會繼續運行下去。所以指針用不好非常危險
同時甚至,指針p可以用中括號來進行尋址運算p[1]=*(p+4);
同時甚至,可以int*p=a;這裏a不用取地址,因爲a本身的值就是地址,a就是一個類似於指針的東西,只不過多了傳參,大小等限制。
5.進階:
由上,指針可以用來改善數組傳參進入函數的問題,
指針很nb,沒有距離大小限制,
p+4和*(p+4)和*p+4都不一樣
int a[5]={1,2,3,4,5}; int*p =a;
p+4=某地址;
*(p+4)=↑上面這個地址上的int值即5即a[4];
*p+4=a[0]+4=5;
總結,指針很重要,以後學動態數組,數據結構中鏈表,樹,堆等都需要指針。