指針,是一個表示變量或函數的地址的無符號整數。
指針的字節數,與CPU的位數有關,32位機是4位元組,64位機是8位元組。
與高級語言的long類型的大小是一致的。
所以在java的JNI庫裡,如果需要把native層的C結構體的指針保存到java層,一般是定義一個long類型的變量。
指針指向的變量,可以是普通變量、數組變量、結構體變量,以及數組元素、結構體的成員變量,還可以是指針變量。
指針還可以指向函數,叫做函數指針。
指針如果指向數組,指的是數組的首地址,即數組的0號元素的地址。
數組變量名,代表的也是數組的首地址。
如果指向數組的某一個元素,則是這個元素的地址。
int a[10];
int *p = a; //指向數組首地址
p = &a[1]; //指向1號元素的地址
如果指向結構體變量,就是這個結構體的地址。
C語言的結構體的地址,也是結構體的第一個成員變量的地址。
當然,類型是不一樣的,數值一樣。
C語言一般把管理結構的結構體變量,嵌入到它要管的數據結構裡,而且一般會放在第一個位置。
例如,我們用紅黑樹管理定時器,那麼定時器的結構體是這樣的:
struct timer {
struct rb_node node; //紅黑樹的節點
int64_t time; //定時器的觸發時間
int (*handler)(void* data); //回調函數
void* data; //回調函數的參數
};
這樣timer和rb_node的指針就可以互相轉換。
獲取紅黑樹的最小元素,然後拿到它記錄的時間,與當前的系統時間比較,就可以判斷它是否被觸發:
int ret = timer->handler(timer->data);
timer是定時器的結構體指針。
handler是結構體的回調函數指針,它是結構體的成員變量,還是一個函數指針。
data是結構體的回調函數的參數,它也是一個指針,還是結構體的成員變量。
如果指向函數,就是函數的地址,也就是函數的第一條指令的地址。
編譯完的函數,是個機器指令的序列。
如果是intel這種CISC的,指令的大小是變化的。
如果是ARM這種RISC的,指令的大小是固定的,一般是4位元組,那麼函數就是個指令的數組。
指針,也是個變量。只是它的值存的是其他變量或函數的地址。
既然是變量,那麼它也有地址,也可以有指向它的指針,即二級指針。
二級指針的典型應用,就是二叉樹。
二叉樹,要把子節點的指針,存到父節點的left或者right指針變量裡。有時候會用到left或right的地址,就是個二級指針。