我的解釋是,把記憶體看成能容納東西的房間。這個房間的大小是一個位元組(8位)。房間可以容納東西(內容),房間有自己的門牌號(地址)。
例如:
int a = 5;
我們申請了一個名為a的房間,這個房間一共由四個基本房間組成(32位),這個房間裡存放的內容為5,那它的門牌號呢?c語言不需要我們直接接觸地址,如果學過彙編就很清楚這個問題了,c中我們可以用 &a 取得a的地址,即這個房間的門牌號。
上面是,能類比記憶體的模樣。如果我們認為第六個房間裡放的是門牌號,那麼它指向的是一號房間。
我們定義
int *p = &a;
這時候p這個房間裡面就存放了a的門牌號,注意p自己也是房間,也有門牌號。
因為不論何種類型的指標存放的都是地址,所以其所需的房間大小都是一樣的。
定義一個指標變數,我們需要這樣做:
int *p;
前面提到所有類型的指標所需的空間都是一樣大的,為什麼指標需要分類型?
我們這樣訪問指標:
int b = *p;
訪問的時候出了需要知道目標房間的門牌號,還要知道由多少間基本房間(位元組)組成。char類型佔一個基本房間,int類型佔4個基本房間(32位),自訂的類型也許更多。所以訪問的時候僅僅知道房間的門牌號還是不夠的,還需要知道其大小。我們用*p的時候,編譯器需要知道我們要從其地址開始讀幾個位元組的資料,所以我們需要定義指標的類型。
例:
#include <stdio.h>#include <stdlib.h> struct TY{ char s[100];}; int main(){ int *pa = 0x0; char *pb = 0x0; TY *pc = 0x0; ++pa; ++pb; ++pc; printf("%d %d\n",pa,sizeof(int)); printf("%d %d\n",pb,sizeof(char)); printf("%d %d\n",pc,sizeof(TY)); return 0;}
void *類型指標加大了c指標的靈活性。我的上一篇博文《void*指標實現支援所有資料類型的容器》,就是用void*實現的,在計算位移地址的時候,我把void*強制轉換成char*,這樣每次++就會移動一個位元組。
指標很靈活,不僅能夠訪問資料,還能訪問函數。
如果有彙編基礎,就知道在記憶體裡資料和代碼是沒有區別的。所以指標能夠指向資料,也就能夠指向函數代碼入口。
用指標訪問數組,傳遞參數,訪問某個特定地址,有用的地方很多
c中的指標是允許強制轉換類型的。如
int *a;char c;a = (int*)&c;
這樣是允許的,但是有什麼風險?
結合上面說的,指標類型制定了其訪問的長度。如果按上面那樣做,再有這樣的句子:
*a = ‘c’;
它修改的就不僅是c的哪一個位元組了,而是四個位元組。雖然執行
printf(“%c\n”,c)
輸出的是c。那是因為小端機的原因,結果沒錯,但是把後面三個不屬於c的位元組給寫了,越界訪問呐。
還有指標懸空,記憶體泄露等問題。所以用指標時候需要注意。