Re: [問題] 自己練習運用基礎的指標小問題

看板C_and_CPP作者 (坐吃山空)時間8年前 (2015/08/05 06:03), 8年前編輯推噓7(709)
留言16則, 6人參與, 最新討論串4/4 (看更多)
※ 引述《M013020058 (帥翰)》之銘言: : 非常感謝先進的分析 : 目前初學者小弟我為指標分類為下,並提出幾個疑惑的地方。 : 1, 很多書籍都透過變數位址來修改/定義變數資料,但今天不是直接修改/定義變數資料 : 就好?為什麼要繞一圈? 誠如之前所提到的,主要有兩個方向,一個是你不用指標做不到,另一個是這樣做可能 比較快。 後者牽涉到的問題比較多,而且也不是主要的用途,所以我講一下前者。 首先我們知道,在 C 裡面你要存取某個物件/變數的值的時候, 你有兩種方法,一個是你要寫出他的名字,另一個是你要知道他的位址: 方法一: 使用名字 int main() { int a = 3; a = 5; // 透過名字去修改變數內容 // 此時 a 的值是 5 return 0; } 方法二: 使用位址 int main() { int a = 3; int *b = &a; *b = 5; // 透過位址去修改變數內容 // 此時 a 的值是 5 return 0; } 上述兩種方法都可以達到修改變數 a 內容的效果,而一般的時候我們會建議使用前者, 因為後者看起來就是繞了一圈不知道在幹嘛。 那後者甚麼時候有用呢 ? 最常見的就是在函式呼叫的時候: void f(int b) { b = 5; } int main() { int a = 3; f(a); // 此時 a 是 3 還是 5 ? return 0; } 初學者如果在學習函式的時候沒有對引數傳遞和可視範圍 (scope) 有比較清楚的了解, 那這個例子可能就弄不清楚應該是 3 或是 5 在呼叫完 f(a) 之後,main 裡面的 a 應該還是 3,他不會受到 f 的影響。 這可以從很多面向來解釋,首先呼叫函式的時候,a 會被複製一份變成 f 裡面的 b, 所以 b = 5 修改的是一個複製品,無法修改到原始的變數 a。 那如果我們把 b = 5 改成 a = 5 呢 ? void f(int a) { a = 5; } 結果還是一樣沒用,而 f 裡面的 a 只是一個剛好同名同姓的複製品。 f 函式的定義是在 main 裡面的 a 的可視範圍外,所以是無法用變數名字直接去存取 main 裡面的 a。 此時我們可以使用指標來逃過可視範圍的限制,透過 "位址" 來修改變數內容: void f(int *b) { *b = 5; } int main() { int a = 3; f(&a); // 此時 a 是 5 return 0; } 為什麼這裡要特別傳遞指標呢? 就是希望 f 裡面可以透過 "位址" 去存取 main 裡面 的 a 。因為位址是個 "值",是可以複製到 f 裡面的,沒有跟名字一樣有可視範圍限 制。 還有甚麼時候我們可能會需要位址而不能用名字去存取呢 ? 我舉個簡化的例子: int main() { int a = 3; int b = 5; int c = 9; int d = 4; // 可能因為某些原因,我們當初沒有宣告陣列而是使用四個獨立的變數名字 // 如果現在我想要用迴圈去批次處理這些變數怎麼辦 ? int* t[] = {&a, &b, &c, &d}; // 我們可以使用陣列去存變數位址 for (int i = 0; i < 4; i++) { // 此時就可以使用迴圈去依序存取不同名字的變數 f(t[i]); } return 0; } : 2,同上,是否是為了讀寫檔案所建立指標功能? 不全然是,讀寫檔案只是指標的一種應用。 因為讀寫檔案的時候是使用函式傳遞、生命週期與可視範圍脫鉤、檔案大小不固定、存 取有效能考量等等,用指標去操作是比較可能的設計。 : 3,以矩陣為例,可用指標來取代矩陣。而兩種在記憶體上或其他地方哪裏不一樣? 你可能有甚麼誤會 指標跟陣列的愛恨情仇有兩個主要的問題: 一個是常見的存取問題,指標可以用來存取所指向的陣列元素。 實際上照 C 的陣列設計,所有陣列的存取都是透過指標。 其實沒有甚麼取不取代的問題。 只是當你要在函式間傳遞陣列的時候,因為 C 函式無法直接傳遞陣列型別的物件, 所以你只能透過傳遞指標去存取。 另一個問題是空間配置問題, 陣列的大小如果是編譯期已知,我們可以透過變數定義來配置: int a[10]; 但是如果在編譯期還不知道的話,我們就需要透過動態配置: int size; scanf("%d", &size); int *a = (int *) malloc(size *sizeof(int)); (C++ 或 C99 後有其他作法) (註: 有些時候因為編譯器的限制,在函式內能配置的陣列大小會受到限制, 此時也有可能改用後者來動態配置或者改為全域變數。) 所以實際上需要考量的是空間配置問題,看你是屬於哪一種就用哪一個。 : 4, 最後,指標能有一般變數沒有的「動態」功能,所以才需要指標? 不知道動態功能是甚麼意思 ? : 在指標上的學習,小弟我一直在想這幾個問題?為何需要指標?每本書籍都把指標列為程 : 式碼重要的地方,無法理解~~~~~ 因為你寫太少練習,簡單說就是如果你不需要用就可以把程式寫好,看起來程式碼又沒有 亂七八糟。那就不要用指標。 初學者與其練習怎麼用,不如先練習不要用怎麼寫 ? PS: 我常開玩笑說,如果你完全不要用函式,那你大概就快不需要用指標了。 但是你要怎麼不用函式呢 @@ 了解函式呼叫的運作與限制是使用指標一個很重要的基礎 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.122.83.198 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1438725786.A.D8F.html

08/05 09:23, , 1F
推,現在學指標真的會有點混亂
08/05 09:23, 1F
※ 編輯: Feis (140.122.83.198), 08/05/2015 11:43:38

08/05 17:01, , 2F
一樓你把變數跟指標想成姓名跟住址就好了,要寄東西
08/05 17:01, 2F

08/05 17:01, , 3F
給某某人你可以指定拿給他,或寄到他家。前者是不管
08/05 17:01, 3F

08/05 17:02, , 4F
他在哪都會讓他收到,後者是寄過去可能其實他搬走了
08/05 17:02, 4F

08/05 17:03, , 5F
但對郵差來說後者可以說幾乎一定比較快。
08/05 17:03, 5F

08/05 17:04, , 6F
然後就是物件跟物件之間要溝通,你不用指標就是存一
08/05 17:04, 6F

08/05 17:04, , 7F
堆變數呼叫一堆方法然後return 來return去,但如果在
08/05 17:04, 7F

08/05 17:05, , 8F
初始化就把指標傳過去記憶,就很方便呼叫其他物件
08/05 17:05, 8F

08/05 17:05, , 9F
不過用指標就要注意記憶體複寫的問題,如同前面說的
08/05 17:05, 9F

08/05 17:06, , 10F
郵差寄信過去其實是別人收到。可能會出錯或結果有誤
08/05 17:06, 10F

08/05 17:39, , 11F
哇...謝謝川澄大的解釋,用讓自己有畫面的方式來想會方
08/05 17:39, 11F

08/05 17:39, , 12F
便很多
08/05 17:39, 12F

08/05 19:01, , 13F
好文
08/05 19:01, 13F

08/05 22:13, , 14F
我不用函式的話大概會是滿滿的go to
08/05 22:13, 14F

08/06 03:39, , 15F
08/06 03:39, 15F

03/02 21:15, , 16F
查到這篇文 kawasum大 感謝啟發
03/02 21:15, 16F
文章代碼(AID): #1LmJQQsF (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1LmJQQsF (C_and_CPP)