# C++ Pointer(指針) ## 一、什麼是指針 ```cpp int a; int *p; ``` 指針同樣是一種變數,和一般變數的差別是它用來保存記憶體位址,比如a的記憶體位址在0x1234,p要保存a的位址存的就是0x1234 ## 二、*和&符號介紹 ### & 如果將&接在一個變數前面,就會變成取得該變數的記憶體位址 ex: ```cpp int a = 10; &a // int * ``` 而它的型別即是原本的加上一個* 原本是int,所以int的記憶體位址型別是int * 這也就是指針變數的型別有*的原因 所以用int *型別保存int變數的記憶體位址 ```cpp int a = 10; int *p = &a; // p保存了a的記憶體位址,比如0x1234 cout << p; // 0x1234 ``` 而當&接在型別之後,int &num,作用是Reference(參考),在這裡不講述 ### * 如果*接在一個指針變數前面,就會變成取得該指針保存的地址的值 ex: ```cpp int a = 10; int *p = &a; // p = 0x1234 cout << *p; // 10 ``` 當a的記憶體位址是0x1234 p保存的就是0x1234 而*p的作用是取得0x1234這個位址的值 10 ![image](https://hackmd.io/_uploads/rJa62souC.png) ## 三、多重指針 ```cpp int a = 10; int *p = &a; int **pp = &p; ``` &變數 的型別就是變數的型別加上* int → int * int * → int ** 多層指針同樣是保存少一層指針的記憶體位址 比如int *\*用來保存int *的記憶體位址 只要是變數宣告的寫法(前面接著型別) 如int \*p,int &num (Reference) 都會被當成*或&跟型別int在一起的 (int \*)p 即使\*和p連在一起,同樣是int \* 如括號所示 ## 四、陣列 [12, 24, 36, 48] ```cpp int arr[] = {12, 24, 36, 48}; ``` 首先陣列是連續的記憶體空間保存的,int大小為4byte 如果arr[0]位於0x1234 arr[1]則是0x1234+4(int大小)=0x1238 後續的同理 也就是可以透過開頭arr[0] 0x1234+4×N找到第N個索引值的記憶體位址 ```cpp int arr[] = {12, 24, 36, 48}; int *p = arr; // 隱含轉換成&arr[0] // int *p = &arr[0]; // 雖然arr的記憶體位址&arr即是首元素的位址,不過可能因為型別問題產生錯誤 // int *p = &arr; 有可能報錯 cout << *(p+2); // 36 cout << arr[2]; // 36 cout << p[2]; // 36 如同第一個 ``` 指針的加法會加上型別大小 比如int * 加1實際上會是地址+4 int 4byte,所以0x1234\~0x1237都在存放12這個值,0x1238\~0x123B才是第二個元素28 ## 五、建立物件 一般建立物件在C++使用class/struct的名稱加上() ```cpp class Test{} ... Test t = Test(); ``` **new**關鍵詞的作用是分配一塊對應的記憶體空間並返回開頭位址 用來存放xxx型別的記憶體位址是xxx * ```cpp class Test{} ... Test *test = new Test(); ``` 上述為建立一塊Test記憶體空間,比如0x1234 或者說建立一個Test的物件並返回記憶體位址 可以用new的方式建立一個array並返回其開頭位址 ```cpp int *arr = new int[10]; arr[0] = 1; ``` 也可以new int() ```cpp int *num = new int(10); ``` ## 六、為什麼要用指針 指針保存的是一個記憶體位址 而一個記憶體位址在64位元固定是8byte 也就是一個物件無論多大,使用記憶體位址來操作都是8byte的大小