跳到主要內容

Pointer 之不是我排擠你而是我搞不定你!

學習 C 的過程中, Pointer 這個章節對我來說是個無法抹去的痛.
也許是我領悟力太差, 又或許是練習不夠, 我始終無法說服我自己 Pointer 的概念是很自然的.

在 Java 中, 不會操作到指標, 也沒有操作指標的方法.
Primitive Datatype 就是傳數值, Object Datatype 就是傳位址. 雖然骨子裡頭, 物件的操作一樣是使用指標傳遞位址, 但是看不到指標卻是如此的神清氣爽.

在 Objective-C 裡就不是這麼一回事了. Pointer 又回來了.
沒辦法搞定 Pointer 就沒辦法搞定 Objective-C, 不得不, 還是得好好的練習摸索.

於是, 用幾個範例來幫助自己記憶, 分享給所有對 Pointer 沒轍的程式人 orz...
int numbers[] = {1, 2, 3};
int *numbersPtr;
numbersPtr = numbers;
NSLog(@"%i, %i, %i, %i", *numbers, numbers[0], numbers[1], numbers[2]);
NSLog(@"%i, %i, %i, %i", *numbersPtr, numbersPtr[0], numbersPtr[1], numbersPtr[2]);
[輸出結果]
1, 1, 2, 3
1, 1, 2, 3
先複習一下, 宣告變數時, 在變數名稱前加上 "*", 即為宣告該變數為特定資料型態的指標.
使用變數時, 在變數前加上 "&" 可以取得儲存該變數的位址, 可以用來指派給指標.
使用指標變數時, 在變數前加上 "*" 可以取得該指標指向之位址所儲存的數值.
那指標是什麼? 指標是一個變數, 用來儲存某種資料型態之資料的位址.

回到範例, 在這個例子裡頭很明顯可以看到,  以中括號宣告的 int array 可以指派給 int pointer.
又可以看到, *numbers 和 numbers[0] 的數值相同, *numbersPtr 和 numbersPtr[0] 的數值相同.

所以可以推論
=> 陣列是一種指標, 而陣列變數存的其實是第一個 element 的位址.

實際上書裡也是這麼寫的,
numbersPtr = numbers <-equals-> numbersPtr = &numbers[0]
所以 "*" 加陣列名稱實際上取得的是第一個 element 的數值.

看起來, 似乎沒什麼問題了, 根本沒想像中那麼難嘛, 寫程式的人是怎麼回事, 有那麼恐怖嗎?
用到一個 "*" 的時候看起來好像真的沒那麼難, 那如果用到兩個 "*" 呢?
老實講, 我頭好暈 orz...

最簡單的就是在 Objective-C 中的 Object Datatype. 換個例子再看看.
NSString *string1 = @"String1";
NSString *string2 = @"String2";
NSString *strings[2]; //an array of NSString objects
strings[0] = string1;
strings[1] = string2;
NSString **stringsPtr; //a pointer to NSString object 
stringsPtr = strings;
NSLog(@"%@ %@ %@", *strings, strings[0], strings[1]);
NSLog(@"%@ %@ %@", *stringsPtr, stringsPtr[0], stringsPtr[1]);
[輸出結果]
String1 String1 String2
String1 String1 String2
要先說明的是, 在 Objective-C 中物件的宣告和 Java 不同, 必須用到 "*".
但問題來了, 該怎麼取得物件的內容呢?
如果依照 Primitive Datatype 的概念, 第一個想到的答案會是使用 "*" 加上物件名稱, 然而這樣的操作方式, 並不能取得該物件的內容. (那會取得什麼呢? 有興趣可以自己玩玩看 XD)
取得物件的方式和 Java 沒兩樣, 不需要加上 "*", 直接使用物件名稱就可以取得物件的內容.
那麼, 怎麼進行物件的指派呢? 這也和 Java 一樣, 不需要加上任何符號, 直接以物件名稱就可以進行指派. 說明結束, 回頭看範例!

在這個範例中, stringsPtr 這個變數有兩個 "*".
別和我一樣一看到兩個 "*" 就暈了. 冷靜想想, 兩個 "*" 並沒有那麼恐怖. 因為在 Objective-C 中物件的宣告必須使用到 "*", 所以 stringsPtr 的宣告實際上是這個意思
=> 宣告 stringsPtr 為一個指向 NSString 物件的指標.

剩下的其實就跟第一個範例一樣, 陣列就是一種指標
=>  strings 這個 NSString 物件陣列, 可以指派給 stringsPtr 這個 NSString 物件的指標.
陣列名稱存放的其實是第一個 element 的位址
=> "*" 加陣列名稱將會取得在陣列中的第一個物件.

呼... 看似簡單, 但每次用上卻依然覺得頭昏眼花.
真的希望是熟練度的問題, 希望在我多多練習後, 不會再次碰上 Pointer 指向哪, 看了程式碼卻越看越花的窘境.

留言

這個網誌中的熱門文章

引數?! 參數??!! 什麼鬼啊!!

我想這個不僅是只有我會遇到的問題, 大概也是所有 Programming 的人都有的疑惑 (應該是吧?) 什麼引數?? 什麼參數?? 天啊... 到底是誰翻譯的呀!!!! 就字面上來看... 講句實在話, 我真的不了解, 大概是學藝不精所致. 也許有些人認為 => 管它那麼多!! 寫得出來就好了!! 不過龜毛如我, 我還是想搞清楚定義是什麼!

Mac OS X 10.6 同步收取 Gmail, how?

在 Apple 官方的 Mac OS X 10.6 介紹網頁中, 雖然並沒有在內建的郵件軟體 - Mail 著墨太多. 但是實際上 Mail 也做了一些改善, 讓使用可以更方便, 而這篇文主要目的就是說明怎麼讓 Mail 與 Gmail 進行同步. 在過去使用郵件軟體收取電子郵件的使用經驗中, 往往都需要輸入很多資料, 什麼 "寄件伺服器" "收件伺服器" "通訊協定"... 等等等, 這對一般用戶來說, 只能說是災難. 畢竟沒學過那些專有名詞, 天曉得那是些什麼東西!? 而 Mac OS X 10.6 中的 Mail 不同了, 現在只需要輸入 Email 帳號及密碼, 軟體自動搞定細部設定! 有沒有這麼簡單!? 手邊有 Hotmail 的朋友可以試試看, 只要輸入帳號密碼, 10.6 的 Mail 就會幫你設定好其它需要設定的資料. 不過今天的主角是 Gmail 啦! 而要使用的是 Gmail 提供的 IMAP 的功能, 在使用前得先到 Gmail 中進行一些簡單的設定, 當然小弟也會說明這樣設定的理由 :) OK! Here we go!!!

第二章 緊急返鄉 - 推著爺爺去散步

也許是曾經身為軍人的關係, 爺爺很排斥使用輪椅... 也許是曾經身為一家之主的榮耀, 縱使小便不方便卻堅持不肯使用尿壺... 也許就是因為爺爺是爺爺, 所以很少開口要我幫忙他些什麼凡是自己來, 總是他在給我, 我卻很少能給他什麼... 只是兩次的手術, 在病床上躺久了, 他的身體狀況真的大不如前... 沒辦法想自己起來走走就走走, 想坐到沙發就坐到沙發, 想拿起遙控器看看電視就拿, 想回房休息就回房間. 這樣的光景, 以前是再熟悉不過的... 很希望爺爺真的能趕快好起來, 而回家時一切都沒變, 爺爺看到我回家開心大笑起身握握我的手... 現在的他, 只能任我們宰割... 儘管他再怎麼使勁, 那纖細的雙腿依然撐不住他的身子, 不喜歡輪椅也得坐輪椅... 儘管他再怎麼不願意, 行動不方便的他還是被我們包了尿布, 不喜歡尿布也得包尿布... 爺爺一點點的隱私, 一點點的尊嚴也不剩, 連不願意吃飯, 都被我們直接灌食, 連絕食的權力都沒有...