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

作者: Feis (永遠睡不著 @@)   2015-08-05 06:03:03
※ 引述《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:
我常開玩笑說,如果你完全不要用函式,那你大概就快不需要用指標了。
但是你要怎麼不用函式呢 @@
了解函式呼叫的運作與限制是使用指標一個很重要的基礎
作者: xjpjeass (人人)   2015-08-05 09:23:00
推,現在學指標真的會有點混亂
作者: KawasumiMai (さあ、死ぬがいい)   2015-08-05 17:01:00
一樓你把變數跟指標想成姓名跟住址就好了,要寄東西給某某人你可以指定拿給他,或寄到他家。前者是不管他在哪都會讓他收到,後者是寄過去可能其實他搬走了但對郵差來說後者可以說幾乎一定比較快。然後就是物件跟物件之間要溝通,你不用指標就是存一堆變數呼叫一堆方法然後return 來return去,但如果在初始化就把指標傳過去記憶,就很方便呼叫其他物件不過用指標就要注意記憶體複寫的問題,如同前面說的郵差寄信過去其實是別人收到。可能會出錯或結果有誤
作者: xjpjeass (人人)   2015-08-05 17:39:00
哇...謝謝川澄大的解釋,用讓自己有畫面的方式來想會方便很多
作者: coal511464 (我一個人)   2015-08-05 19:01:00
好文
作者: chuegou (chuegou)   2015-08-05 22:13:00
我不用函式的話大概會是滿滿的go to
作者: MIKEmike07 (加油!)   2015-08-06 03:39:00

Links booklink

Contact Us: admin [ a t ] ucptt.com