VII. 結構體與共用體
在程式設計中,常需要把相關資料作為一個整體來處理,其方法是構造新的資料類型。
一、結構體(Structure):彙總資料類型,提供一種把相關資料群組合到一起的手段。
1、通常,結構中的成員都是邏輯的。
2、在商業軟體中,成員變數名一般習慣以底線(_)開頭。結構變數在被定義後,編譯器在編譯時間為所有成員分配記憶體。
3、結構體賦值:可以把一個結構變數的全部內容賦值給另一個同類的結構變數,而不必逐個成員的賦值。 注意與數組的區別:數組是不能彼此賦值的,是因為數組名是一個常量指標。數組是一個資料類型的聚集,它本質上不是資料類型。 [例]struct { void main() { int _name; char a[10], b[10]; int _age; a=b; /* ERROR!*/ }perso1, perso2; }
perso1._age=10; perso2=perso1; /* OK */
4、向函數傳遞結構時,實際上是傳遞結構成員的值,即都是值傳遞方式,包括用結構體變數作函數參數及函數返回一結構體變數兩種情況。 [注意]與數組的區別:結構體變數名僅代表值,而非地址。
除簡單結構外,向函數傳遞全部結構的方法存在重大缺陷:當執行函數調用時,資料壓棧需要開銷。這對於多成員結構或成員中有數組的結構,運行效能嚴重惡化。解決方案是:向結構傳遞指標。
向函數傳遞結構指標時,壓棧的僅僅是指標本身,這使得函數調用非常快。在某些情況下的另一個優點是,函數可以修改作為變數的結構的內容。
5、成員結構:結構體中的結構。C89 規定,結構體至少應允許嵌套 15 層,C99 增加至 63 層。
6、結構體的應用:結構體經常被應用於動態資料結構。在 C 語言中由結構體類型和動態儲存裝置分配函數來實現動態資料結構。
由於數組這樣的待用資料結構在被定義後,系統將在記憶體中為其分配連續的記憶體空間,且在程式運行期間保持不變(或整體被撤消),因此雖然它有可以隨機訪問每一個數組元素的優點,但是它有更嚴重的缺陷:在對元素進行插入和刪除運算時,需要移動大量元素而可能降低效率。並且,由於數組大小固定,儲存在連續的記憶體空間中,在資料量變化較大的情況下,必須按最大需要進行分配,有可能浪費很多記憶體。另外,在程式運行期間無法根據需要對數組進行擴充,也不可能釋放其中的某一部分記憶體。
在實際工作中,有很多問題需要用到動態方式的資料結構,它們佔用的空間可以動態變化(可以根據需要隨機地分配和釋放記憶體)。在邏輯上連續的元素,在記憶體中卻不一定連續。
具體執行個體:單向鏈表,二*樹等。(不再詳細贅述)
7、在把 C++ 代碼移植到 C 時,需要注意: struct str { int _x; int _y; };
struct str objet; /* 在 C 語言中必須有 struct,否則編譯器報錯。C++ 也可使用 */ str objet; /* C++ 的格式 */
在 C++ 中,結構體名是完整的類型名,可以被自身使用以定義變數。
二、共用體(Union):允許多個不同的變數(可以是相同類型或不同類型)共用同一塊記憶體空間,提供了以多種方式解釋同一位元模式的方法。
1、聲明共用體時,編譯器為其分配一塊記憶體,大小為其成員變數中最大的變數所佔用的位元組數。
2、共用體常用於需要頻繁進行類型轉換的場合,因為程式可以使用共用體中的資料。
三、位段(bit-field):訪問位元組中的位的內設機制,可以訪問單個位。這是 C 語言中訪問二進位位的兩種方式中的一種(另一種方式是位元運算)。
1、特點: - 記憶體緊張時,可把若干 BOOL 變數存入一個位元組。 - 某些裝置把編碼資訊傳送到各個位。 - 某些密碼編譯演算法需要訪問位元組中的位。
2、相對於位操作來說,位段能夠增加更多的代碼結構,可以提高效率。
3、C 語言的位段由結構體實現,每個位段是位段結構體中的成員,以位為單位來定義長度。
4、與普通結構體相比,位段的使用也有一定的限制和細節問題,如:不能取其地址,位段變數不能跨越數組邊界,位段只能被聲明為 int 或 unsigned int 類型等。另外,不同的機器對位段的成員的儲存順序是不一樣的,這意味著使用位段變數就引入了對機器的依賴。
四、枚舉(enum):被命名的整型常量的列表。
1、每一個符號代表一個整數值。
2、第一個符號的值是零。
3、每一個符號的值都是其前置者的值加一。
4、枚舉表中的名字不是字串。 [錯例]enum color { black, white, blue, red=4, magenta, brown, gray=20, yellow }; enum color c1; /* 定義變數 c1 為 color 類型*/ c1=gray; printf("%s/n", c1); /* ERROR!*/ /* gray 只是一個整型數值的名字,而非字串。*/
要把枚舉型翻譯成字串只能靠編程實現,如使用一個串數組,用枚舉值作數組下標,或者使用 switch() 控制結構。因此,枚舉常用於不產生這種轉換的程式中(如定義編譯器的符號表)。