顯示廣告
隱藏 ✕
※ 本文為 MindOcean 轉寄自 ptt.cc 更新時間: 2020-09-20 15:50:06
看板 Gossiping
作者 HuangJC (吹笛牧童)
標題 Re: [問卦] 有沒有學習 C 語言指標的好方法?
時間 Sun Sep 20 02:20:48 2020



我們從機械語言定址法說起好了

絕對定址法:
比如,從位址 0x300 取出值,放入累加器

間接定址法:
比如,從位址 0x300 取出值,這個值又當成位址,再去該位址取出其值,放入累加器


組合語言應該是不會那麼三八,給你兩層三層的間接定址的
但 C 語言可以,每多打一個星號取出其值,就是取出的值再間接定址一次
但事實上還不是湊出來的 :P
前面說了,值取出後放入累加器
那我就把累加器的值不當值,當成位址,再取一次就好啦

在機械語言裡這麼直觀的東西
在 C語言裡,說"為了你方便",有點不一樣

0x300+1 是多少? 0x301 嘛,對吧~
但如果在 C, 就會說指標指的物件是有 size 的
如果是個 word, 那麼 0x300 + 1(word) = 0x302
也就是那個 1,必需賦與單位,單位是 word

就這樣而已,差別不大 XD
但這在陣列裡算好用的
比如一個 size = 32 byte 的元素
0x300 + 1(32byte) = 0x320
在陣列就真的好用

要把 0x300 當數值用時,比如當 word, 其實就是 (word)0x300
就算它本來是指標,也會被 cast 成 word
要把 0x300 當指標用時,就算它本來是word, 只要你 cast 下去,就會變指標
(void*)0x300  像這樣,它就變指標

一般來說,我們不胡搞,以免自己受不了
可是當你在看別人程式時,你無法禁止別人胡搞
如果跨模組時,直接胡搞更是把不同模組黏起來最快的方法

就像拿全域變數寫程式一樣,又爽又危險 XD
所以就算本來宣告 int ***a; 說 a 是個三層指標好了
可是我要用時,馬上 cast (int**)a  這樣用
你受不了又怎樣呢?就是可以 XD

一個變數要被視為什麼,是要'活在當下'的
當下怎麼用它,它就是什麼
如果你不確定,就多步進執行或加 print 去看它

而因為指標的加一減一,事實上是帶單位的
所以記得 sizeof 偶爾要用用,去檢查檢查它是不是你所想的那麼一回事


回到 怎麼學能學好
你要故意學很高深當然可以,就好像學生時微積分學到很難,出社會後好像沒在用
你常用的程度自然就會熟了

我是蠻愛用指標的,因為它可以創造物件的分身
寫程式時要注意本尊只有一個,其他都用分身
這樣的好處是不用注意物件的 sync 問題

比如, a=3 , b=a,  然後 a=4
b 是拷 a 的值,但 a 改成 4 之後,b 卻沒一起改
這就是複製的缺點
用分身的話,a 的改變,b 不用通知也會跟著變,多好...

而一堆人都要用變數,到底把本尊放在哪好?
那就是程式架構的問題了
本尊一定要最早產生,最後消滅
如果沒這特性,比如上面的 a 先消滅,b 又保留 a 的值要繼續使用
那 b 不就從分身轉而為本尊的地位?
這麼複雜的擁有權轉移,很容易讓人暈頭轉向的
但也不是絕對不做;觀念清楚就可以
於是我們漸漸會確立物件是個有形有質的'東西'
要好好保管,或好好轉移擁有權
這有形有質的概念堅持下來,物件導向就很有感覺
物件導向不是 class, private, public, method 這些字眼而已
它就是把一群變數好好的當成物件去保管,以有形有質去對待它
有這概念,就算用 c 都可以寫出物件導向



我第一次寫二元數排序,照著課本做就失敗了
後來連續做兩次都失敗,但我確定校對兩次,絕對沒打錯
結論很簡單:課本印錯了,誤人子弟 XD
(第一次成功,就是拋開課本,自己寫就成功了)

若再加上硬 cast 指標以讓程式會動的這些 code
可以說糊成一團粥的機率大增


那還是會自己檢查指標比較重要
檢查下去你就知道那些指標運算在幹麻

像 COM 的巨集裡也在運算指標,我看了就很暈
但拆開來步進一下就懂


--
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 49.216.189.45 (臺灣)
※ 文章代碼(AID): #1VPam2DG (Gossiping)
※ 文章網址: https://www.ptt.cc/bbs/Gossiping/M.1600539650.A.350.html
abadjoke: 看了這一串 我還是乖乖待python 就好了1F 09/20 02:21

鄉民當然要用 python, 它怎麼翻譯的?它和我褲子裡那條意思是一樣的
另外城市獵人的那把槍,也叫 python

koreawargod: 看完這篇...我今晚可以很好睡了2F 09/20 02:24

再給個番號更好睡

YAYA6655: 猛3F 09/20 02:24

※ 編輯: HuangJC (49.216.189.45 臺灣), 09/20/2020 02:26:06
sef96121: 有看有推4F 09/20 02:28
DDxMM: 不同環境平台指標用多了會出現奇奇怪怪現象5F 09/20 02:30
pearlsally: 牛逼 第一次學樹 堆的時候真d痛苦6F 09/20 02:30
DDxMM: 到後來變成少用指標的好7F 09/20 02:30

C 的指標有陷阱啊 XD
2D 陣列有兩種做法
一種是等長的一維陣列,組成二維
一種是不等長的一維陣列,組成二維

這兩種陣列的取值都是兩個星號,但骨子裡不一樣
而這個不一樣又只有 compiler 在肚子裡知道
所以要常用 sizeof 去檢查,就會知道問題了

turorach: 以前一直對物件導向不太了解,都傻傻地用8F 09/20 02:32
※ 編輯: HuangJC (49.216.189.45 臺灣), 09/20/2020 02:34:46
DDxMM: 大端小端對齊就夠你搞,還是不要用指標比較通用9F 09/20 02:35
zero00072: 感謝分享!物件本尊分身那跟檔案系統的 inode link 好10F 09/20 02:39
zero00072: 像。
DarkIllusion: 用c做出物件導向的特性會有點累12F 09/20 02:43

我是不得已的啊,我先學會了物件導向,才碰到工具...

相反的看到人用工具,肚子裡裝的不是物件
才知道觀念不通的人永遠都不通 XD
※ 編輯: HuangJC (49.216.189.45 臺灣), 09/20/2020 02:45:10
patentstm: 推字多好睡~13F 09/20 02:49
r34796a: 看得半懂 但有收穫 推14F 09/20 02:54
Nigger5566: 淺顯易懂,讚15F 09/20 03:00
buke: 推  看來我還是乖乖寫php就好16F 09/20 03:06
pizzafan: 只要看到書裡寫連兩個星號**才認為4高手的 把牠當渣就好17F 09/20 04:46
pizzafan: 故意複雜化、玩符號艱澀耍婊藝術 高來高去的 都當渣就好
pizzafan: 老外教學 也沒有教人專練這種功 來婊人的  有叫他去吃屎
summerleaves: 優文  還有連範例都錯 這書也太爛 XD20F 09/20 08:33
froce: 身為python和golang黨表示自己很幸福,很少看到一堆*號的21F 09/20 08:36

一個星號代表查一次表,只要每一層表格都有命名
也就是把抽象概念具象化,自然不需要多層星號

一次取出一層即可,並且用表格名字去承接

只有當抽象到暈頭轉向時程式才會看不懂
但事實上你早就在用多層指標了;一定有

光是字串就是一維

char* str1 = 'hello'
char* str2 = 'world'

字串串成文章就是二維

text *text1; (在此我省略空間的產生及釋放;直接使用)
text *text2;

text1[0] = str1
text1[1] = str2

多篇文章難道在系統裡過份?那就三維了

texts[0] = text1
texts[1] = text2

當要取出第一篇文章的第一行的第一個字時

texts[0][0][0] <= 這什麼鳥?一次解三維?

或者

text = texts[0]  <= 先取出文章
str = text[0]    <= 再取出字串
a = str[0]       <= 再從字串取出字元

有難嗎?其實三層不是早就在用了?
只因為每層結構都有命名,一次取用一層,你以為沒在用而已




※ 編輯: HuangJC (49.216.189.45 臺灣), 09/20/2020 12:04:56
※ 編輯: HuangJC (49.216.189.45 臺灣), 09/20/2020 12:11:51

--
※ 看板: Gossiping 文章推薦值: 0 目前人氣: 0 累積人氣: 439 
分享網址: 複製 已複製
r)回覆 e)編輯 d)刪除 M)收藏 ^x)轉錄 同主題: =)首篇 [)上篇 ])下篇