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