指標詳解

故里家鄉發表於2020-10-04

指標實際就是儲存記憶體地址的一個變數,指標是有型別的,當對指標進行解引時,會根據指標的型別對所指的記憶體進行相應的解析,同變數一樣也佔用一定的記憶體(32位系統下佔4位位元組,64位佔8位位元組)
指標的定義

int a;
int* p = &a;

*代表 p為int型別的指標,&為取地址符

int* p, s1;

在這行程式碼中p為int型別的指標,s1為整形變數

指標的三種const用法

const int* p;// int const*  p;
	p = &a;
	//這兩種定義方法的指標,所指向的資料不能通過該指標進行修改
int a;
int* const p = &a;
//這種方式定義的指標,必須進行初始化,且該指標值不會改變,可以通過指標對其指向的值進行修改
int a;
const int* const p = &a;//或者int const* const p = &a;
//這種方式定義的指標,必須進行初始化,且該指標值不會改變,不可以通過指標對其指向的資料進行修改

指標與陣列的糾纏
當函式引數中出現陣列時,實際上傳遞的陣列首個元素的地址,而不是把整個陣列copy到棧空間,大量的拷貝會使得程式效率下降.因此在函式中對形參傳來的陣列進行的操作會影響實參裡的值

指標陣列的定義

int* p[100];

指標陣列傳參

//方式一: 指標陣列傳參,宣告成指標陣列,不指定陣列大小
void method_4(int *arr[], int len) { 
    for(int i=0; i<len; i++){ printf(" arr[%d] = %d\n", i, *arr[i]); 
    } 
}
//方式二: 指標陣列傳參,宣告成指標陣列,指定陣列大小
void method_5(int *arr[10])
{ 
	for(int i=0; i<10; i++){ printf(" arr[%d] = %d\n", i, *arr[i]); 
	} 
}
//方式三: 二維指標傳參
//傳過去是指標陣列的陣列名,代表首元素地址,而陣列的首元素又是一個指標, 
//就表示二級指標,用二級指標接收
void method_6(int **arr, int len) { 
	for(int i=0; i<len; i++){ printf(" arr[%d] = %d\n", i, *(*(arr+i))); 
	}
}

空指標

  1. 什麼是空指標? 空指標,就是值為 0 的指標。(任何程式資料都不會儲存在地址為 0 的記憶體塊中,它是被操作系 統預留的記憶體塊。) int *p = 0; 或者int *p = NULL; //強烈推薦
  2. 空指標的使用
    1)指標初始化為空指標 int *select = NULL; 目的就是,避免訪問非法資料。
    2)指標不再使用時,可以設定為空指標 int *select = &xiao_long_lv; //和小龍女約會 select = NULL;
    3)表示這個指標還沒有具體的指向,使用前進行合法性判斷897943840118979438401111 int *p = NULL; // 。。。。 if § { //p 等同於 p!=NULL //指標不為空,對指標進行操作 }

壞指標
int *select; //沒有初始化
情形一printf(“選擇的房間是: %d\n”, *select);
情形二select = 100; printf(“選擇的房間是: %d\n”, *select);

指標也分等級
二級指標只能存放一級指標的地址,三級指標只能存放二級指標的地址,以此類推.(不能越級)

空指標
void => 空型別 void* => 空型別指標,只儲存地址的值,丟失型別,無法訪問,要訪問其值,我們必須對這個指 針做出正確的型別轉換,然後再間接引用指標。 所有其它型別的指標都可以隱式自動轉換成 void 型別指標,反之需要強制轉換

指標運算
(1)指標與整數的運算,指標加減數字表示的意義是指標在陣列中位置的移動; 對於整數部分而言,它代表的是一個元素,對於不同的資料型別,其陣列的元素佔 用的位元組是不一樣的, 比如指標 + 1,並不是在指標地址的基礎之上加 1 個地址,而是在這個指標地址的 基礎上加 1 個元素佔用的位元組數:
 如果指標的型別是 char*,那麼這個時候 1 代表 1 個位元組地址;
 如果指標的型別是 int*,那麼這個時候 1 代表 4 個位元組地址;
 如果指標的型別是 float*,那麼這個時候 1 代表 4 個位元組地址;
 如果指標的型別是 double*,那麼這個時候 1 代表 8 個位元組地址。
(2)通用公式: 資料型別 *p;
p + n 實際指向的地址:
p 基地址 + n * sizeof(資料型別)
p - n 實際指向的地址:
p 基地址 - n * sizeof(資料型別)
比如
對於 int 型別,比如 p 指向 0x0061FF14,則: p+1 實際指向的是 0x0061FF18,與 p 指向的記憶體地址相差 4 個位元組; p+2 實際指向的是 0x0061FF1C,與 p 指向的記憶體地址相差 8 個位元組
對於 char 型別,比如 p 指向 0x0061FF28,則: p+1 實際指向的是 0x0061FF29,與 p 指向的記憶體地址相差 1 個位元組; p+1 實際指向的是 0x0061FF2A,與 p 指向的記憶體地址相差 2 個位元組

指標和指標可以做減法操作,但不適合做加法運算.
指標和指標做減法適用的場合:兩個指標都指向同一個陣列,相減結果為兩個指標之 間的元素數目,而不是兩個指標之間相差的位元組數。
如果兩個指標不是指向同一個陣列,它們相減就沒有意義。
不同型別的指標不允許相減(指標之間可以進行比較)

函式指標
//函式指標的定義 把函式宣告移過來,把函式名改成 (* 函式指標名)
int (*fp)(const void *, const void *);
/貝爾實驗室的C和UNIX的開發者採用第1種形式,而伯克利的UNIX推廣者卻採用第2 種形式ANSI C 相容了兩種方式/
fp = &compare_int;
(*fp)(&x, &y); //第1種,按普通指標解引的放式進行呼叫,(*fp) 等同於compare_int
fp(&x, &y); //第2種 直接呼叫

陣列指標
指向陣列的指標
陣列指標的定義假設指向一個int 型別的陣列,陣列成員為3個
int (* p)[3];

引用
可以理解為對一個變數起別名,實際上c++是用常指標實現的,所謂明修棧道暗度陳倉

int &a = 10;時是成立的,編譯器會在棧開闢int空間,並起一個名字

相關文章