写给过去的自己-No.2-数据结构篇-初尝柔性数组
??? 過去你的自己,你好。
??? 照顧寶寶,寫完第一篇就沒什么時(shí)間,既然上次講的就是數(shù)據(jù)結(jié)構(gòu),這次也講點(diǎn)相關(guān)的。
??? 其實(shí)接觸柔性數(shù)組也是個(gè)比較奇妙的過程,你以后會(huì)遇到個(gè)學(xué)長,畢業(yè)后從事軟件行業(yè),在中興鍛煉過,將會(huì)給你很多軟件方面的啟發(fā)。一次討論結(jié)構(gòu)體內(nèi)數(shù)據(jù)結(jié)構(gòu) 類型強(qiáng)制轉(zhuǎn)換的問題時(shí)(劇透一下,是你用的編譯器中的一個(gè)bug導(dǎo)致了ARM操作非對(duì)齊的地址所以進(jìn)入hardfault,這個(gè)問題和今天講的沒關(guān)系,以 后再開題),聽到了“柔性數(shù)組”這個(gè)關(guān)鍵字,當(dāng)時(shí)沒聽明白也就沒有去深究。然后某日在論壇看到篇好帖講C語言的一些高級(jí)用法,看到了一個(gè)疑似“柔性數(shù)組” 的說明,細(xì)究之后恍然大悟原來柔性數(shù)組是這么回事。不過另一個(gè)問題來了,感覺沒有什么場合會(huì)用到,也就沒有深入下去。結(jié)果就在最近,在做模塊化編程時(shí),發(fā) 現(xiàn)了用柔性數(shù)組極佳的環(huán)境。我就是這樣開始正視柔性數(shù)組。開篇講了這么多廢話的目的是要告訴你:1、多向前輩學(xué)習(xí);2、注意前輩不經(jīng)意吐露的“關(guān)鍵 字”;3、有機(jī)會(huì)一定要深究“關(guān)鍵字”,會(huì)有很大收獲;4、對(duì)新的知識(shí)再深究下應(yīng)用環(huán)境。
??? 數(shù)組一般都是靜態(tài)的,所謂靜態(tài)就是在編譯之時(shí)就已經(jīng)確定的。如果是全局?jǐn)?shù)組,則數(shù)組的大小及存放在內(nèi)存中的位置就確定了(靜態(tài)儲(chǔ)存區(qū));若是局部數(shù)組且編 譯器不支持VLA(可變長度數(shù)組),那該數(shù)組在內(nèi)存的位置就在運(yùn)行時(shí)分配(棧區(qū)域),但是數(shù)組的大小還是在編譯之時(shí)就會(huì)確定下來(若編譯器支持C99的 VLA,則僅限局部數(shù)組可使用可變長度)。從上面兩種情況可以看出,不管數(shù)組最終存放在哪里,數(shù)組的大小是需要在編譯時(shí)確定的(C語言中規(guī)定申請(qǐng)數(shù)組時(shí)中 括號(hào)內(nèi)的數(shù)據(jù)必須是常量),那問題就來了,如果你想開發(fā)一個(gè)軟件模塊且日后不想根據(jù)不同的應(yīng)用修改代碼,那用我們上述方法的數(shù)組肯定是不行的,因?yàn)椴恢?模塊在被使用時(shí)數(shù)組的大小(其實(shí)可以簡單的方法解決--宏定義數(shù)組大小,有機(jī)會(huì)再解釋)。
??? 上述就是問題的提出,下面介紹幾個(gè)豆知識(shí):
???? 1、int a = 0;那a就是變量名,其實(shí)就是內(nèi)存的一個(gè)別名。若a的地址為0x200000FE,則a就是內(nèi)存0x200000FE的別名
???? 2、struct t
????????? {
?????????????? unsigned char wLen;
???????????????unsigned char awData[7];
?????????? };
??? 再回到靜態(tài)/動(dòng)態(tài)數(shù)組上來,目測靜態(tài)數(shù)組不能滿足模塊化編程的需要,那就看看有沒有動(dòng)態(tài)數(shù)組。既然是動(dòng)態(tài),那就是在設(shè)備運(yùn)行時(shí)進(jìn)行操作,而數(shù)組又是一種數(shù) 據(jù)結(jié)構(gòu),也需要分配內(nèi)存,這樣很容易就想到“動(dòng)態(tài)分配malloc”來解決數(shù)組大小既定的問題。看一下下面的結(jié)構(gòu)體。
1 typedef struct _tTest_ 2 { 3 unsigned char wLen; /* Length of data */ 4 unsigned char awData[0]; /* Data field */ 5 }T_TEST; 6 7 T_TEST t = {0}; /* Create a "t" */?
??? 依舊是類似的結(jié)構(gòu)體t,不同的是成員數(shù)組awData的大小為0,通過sizeof (T_TEST)可以發(fā)現(xiàn)結(jié)構(gòu)體t的大小為1 byte,說明數(shù)組awData不占內(nèi)存,那這個(gè)數(shù)組還有什么意義呢?看一下豆知識(shí)1,變量名實(shí)際上就是內(nèi)存地址的別名,那么這個(gè)長度為0的數(shù)組實(shí)際上就 是某個(gè)內(nèi)存地址的一個(gè)別名。那t.awData[0]是哪個(gè)內(nèi)存地址的別名呢?從豆知識(shí)2可知它代表的是結(jié)構(gòu)體t后面的一個(gè)byte內(nèi)存,依次類 推,awData[9]就是這個(gè)結(jié)構(gòu)體t后面第10個(gè)byte的內(nèi)存。如果結(jié)構(gòu)體t后面的N個(gè)byte內(nèi)存都不被其他變量使用,那t后面的N個(gè)byte內(nèi) 存就可視為數(shù)組awData的可用范圍,即awData數(shù)組的長度為N個(gè)字節(jié)。也就是說,如果你能控制N的大小,你就能自由地控制數(shù)組awData的大 小,那如何在運(yùn)行過程中動(dòng)態(tài)地控制這個(gè)N呢?使用malloc。
1 T_TEST *ptTest = NULL; 2 int wLen = 10; /* Get 10-byte length */ 3 4 ptTest = (T_TEST*)malloc(sizeof(T_TEST) + wLen); /* Create the space for array */ 5 6 if(ptTest != NULL) 7 { 8 ptTest->awData[9] = 10; /* Operate the last byte of array */ 9 } ??? 上例中就是通過malloc在內(nèi)存的堆區(qū)域中申請(qǐng)了一塊內(nèi)存區(qū)域,這個(gè)區(qū)域由兩部分組成,一個(gè)是T_TEST結(jié)構(gòu)體的大小(1 byte),另一個(gè)就是數(shù)組的長度wLen。通過這個(gè)方法可以確保結(jié)構(gòu)體后面的wLen個(gè)內(nèi)存是不會(huì)被其他變量占用的,這樣數(shù)組就可以安全地使用。當(dāng)數(shù)組 用完以后,可以free釋放該塊內(nèi)存,再根據(jù)具體要求修改wLen重新申請(qǐng),這樣這個(gè)數(shù)組的長度就變得可變了,這就是柔性數(shù)組,既不用擔(dān)心數(shù)組定義過大而 浪費(fèi)空間,又不會(huì)因?yàn)閿?shù)組定義過小而發(fā)生越界操作。
??? 再談?wù)剬?shí)際的應(yīng)用場景,我開發(fā)的某個(gè)軟件模塊中有兩個(gè)邏輯運(yùn)算功能,于是我將可以對(duì)這個(gè)模塊的數(shù)據(jù)結(jié)構(gòu)做如下定義
結(jié)構(gòu)體T_LOGIC定義了邏輯運(yùn)算的基本單元,包含了邏輯運(yùn)算的操作(與或非等)和邏輯輸入,而結(jié)構(gòu)體T_MODULE_FUNC則是軟件模塊所定義的 數(shù)據(jù)結(jié)構(gòu),可以看出軟件模塊定義了兩個(gè)邏輯運(yùn)算基本單元tLogic1和tLogic2,tLogic1的運(yùn)算結(jié)果將作為tLogic2的輸入繼續(xù)執(zhí)行下 一級(jí)邏輯運(yùn)算。如果說產(chǎn)品的需求就是兩級(jí)的邏輯運(yùn)算,那這個(gè)軟件模塊是可以滿足要求,但如果說產(chǎn)品需求是三級(jí)邏輯運(yùn)算,那原有的數(shù)據(jù)結(jié)構(gòu)就不適用,代碼也 要改,則模塊的復(fù)用性就差,所以不能定義個(gè)tLogic3來解決該問題。為了解決這個(gè)問題,我們可以把原來的結(jié)構(gòu)修改成這樣:
這樣軟件模塊通過宏定義NUM_OF_LOGIC的數(shù)值就可以我需要多少級(jí)的邏輯運(yùn)算,這種方法實(shí)現(xiàn)比較簡單,也易于理解,但有時(shí)候在整體代碼框架下這個(gè) 宏定義的位置需要考慮清楚,同時(shí)要關(guān)心頭文件的包含順序。為了讓模塊與其它模塊更少耦合,讓模塊更好用,可以在這里使用柔性數(shù)組:
這樣就可以不用事先定義這個(gè)NUM_OF_LOGIC宏定義,而在運(yùn)行過程中動(dòng)態(tài)的申請(qǐng)和使用,是不是很方便呢(其實(shí)很多情況下還是宏定義方便,呵呵)。
終于還是寫完了,這篇寫了好長時(shí)間,有了寶寶之后屬于自己的時(shí)間少且零散,勸你還是在萌萌降臨之前多多學(xué)習(xí),我也盡可能的多總結(jié)點(diǎn)東西給你,希望你能收的到。
寫在最后:借個(gè)地方向你感嘆一下生活,你以后某天會(huì)放棄一個(gè)多年的向往,很多時(shí)候你會(huì)面臨抉擇,哪一個(gè)選項(xiàng)都伴隨著犧牲,你自己要考慮清楚什么更重要。當(dāng) 你遇到這樣的糾結(jié)時(shí),安慰自己,根本就沒有那個(gè)選擇,你在做的是你認(rèn)為最重要的。我不想干預(yù)你太多想法,但記住一點(diǎn),你有家庭的責(zé)任,請(qǐng)以整個(gè)家庭的角度 考慮問題。
轉(zhuǎn)載于:https://www.cnblogs.com/ianhom/p/4517704.html
總結(jié)
以上是生活随笔為你收集整理的写给过去的自己-No.2-数据结构篇-初尝柔性数组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gslang——原生golang/RPC
- 下一篇: Web 前沿——HTML5 Form D