C/C++ Pointer

相信很多人都還對指標這定義很不熟悉,甚至在寫程式時也很容易搞混,沒關係小弟也是從這懵懵懂懂的道路走過來的,這邊先直接給一道程式大家先試著想想看答案是什麼?!

int main() { int a = 5; int b = a; std::cout << a << std::endl; std::cout << b << std::endl; a = 10; std::cout << a << std::endl; std::cout << b << std::endl; return 0; } // output // a = 5 // b = 5 // a = 10 // b = 5

小弟本身是先從 python 學起(雖然大學修課是C/C++),如果上面程式來看自己會覺得最後 a = 10b = 5,沒錯答案的確是這樣起初剛學指標時也很容易會被這種題目混淆,會思考著 b 到底是獲得 a 的數值還是位址。

接著就是位址、指標的重點了,以下面程式來看當宣告變數時會給予一個記憶體空間去做存放,而這空間就是人家常提到的位址,那 a 這個變數便代表了 0x0011FF00 這個位址,而這位址存放的元素為 int 變數(4 個byte)。

int a = 10; int b = 20; int c = 30;

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

那麼 pointer 要做什麼用呢,當想要去更動位址裡面的數值時 pointer 就派上用場啦,可以應用到的範圍很廣這邊就先講一下他的基本要數,從下面範例來看這次 b 直接取了 a 的位址,那當 b 給予其他數值時(也就表示該位址做更動) a 的數值也會跟著做改變。

int main() { int a = 5; int *b = &a; std::cout << a << std::endl; std::cout << *b << std::endl; *b = 15; std::cout << a << std::endl; std::cout << *b << std::endl; return 0; } // output // a = 10 // b = 10 // a = 15 // b = 15

那麼先看了上面的 pointer 起手式後,來簡單講解 *& 做什麼用的,當你宣告變數時該變數名稱只是代表該型態值,也就如下面程式當宣告 a 為 10,那這個 a 變數只是一個 int 型態值有它自己的記憶體空間,所以當你宣告 b 為 a 時就只是將 a(10) 這個值也給 b,那 a 與 b 各為不同記憶體空間。

int a = 10; int b = a;

當想要牽一髮而動全身的效果時就得用到 *&,如下程式所示,int *b 為要放入 int 位址的變數,&a為將 a 的位址取出來,所以 int *b = &a 為將 a 的位址給予 b,所以 b 拿到的是 a 的位址。

  • *:為位址變數
  • &:取變數位址
int a = 10; int *b = &a; // a 位址 0x61fe14 // b 位址 0x61fe14

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

但要將 b 位址裡面的數值顯示出來該怎麼做呢? ** 就是將位址裡面的值顯示出來,有點像負負得正的概念

std::cout << a << std::endl; std::cout << *b << std::endl; // a => 10 // b => 10

Arrary

剛有提到 pointer 應用場景很廣,這裡就介紹常用到的陣列(Array),陣列與一般變數不同的是陣列可以存很多個變數,也就是說一般變數只給一個記憶體空間,而陣列則是給很幾個記憶體空間,聽起來很繞口直接看程式!

int main() { int a = 10; int b[2] = {10, 20}; int c = 30; // testFunction(&a, &b); std::cout << &a << std::endl; std::cout << b << std::endl; std::cout << &c << std::endl; return 0; } // output // a 位址==> 0x61fe1c // b 位址==> 0x61fe14 // c 位址==> 0x61fe10

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這次你有發現 b 不需要 & 就能直接顯示位址了耶,宣告陣列本身就是記憶體位址,那麼不就可以直接將陣列位址給其他人了囉!? 請看程式~

int a[3] = {3, 4, 5}; int *b = a; // a 位址==> 0x61fe14 // b 位址==> 0x61fe14

下面程式有讓你覺得好像有看過類似這樣的陣列操作嗎?
由於 b 本身就是陣列位址,所以可以藉由 b+i 的操作來換下一個記憶體位址,再配合上面有提到的負負得正的概念, *(b+i) 就能將值取出來囉~

int b[3] = {10, 20, 30}; for(int i = 0; i < 3; i++) { std::cout << *(b+i) << std::endl; }

結論

當宣告一個變數就是挪出一個記憶體空間去存放這個變數,那就有了位址與數值的關係。

  • int a = 2,a 為 int 型態數值,數值為 2
  • int *b = &a,b 為 int 指標位址,位址為 a 的位址
  • a 與 b 位址相同,所以 a 與 b 的存放數值也就相同
  • int c[3] = {10, 20, 30},b 為 3 個 int 指標位址,各存放 10、20、30 數值
  • int *d = c,d 為 int 指標位址,指向 c 的位址