struct用于引出一個(gè)結(jié)構(gòu)定義,其后的標(biāo)識(shí)符被稱為結(jié)構(gòu)體標(biāo)記(structure tag)。聲明如下:
struct Node { int a; struct Node *next;};結(jié)構(gòu)體的類型是struct Node(類型名,如int等)。在結(jié)構(gòu)體定義的花括號(hào)內(nèi)聲明的變量,被稱為結(jié)構(gòu)體的成員。同一個(gè)結(jié)構(gòu)體成員必須具有不同的名字,但是兩個(gè)不同的結(jié)構(gòu)體類型中的成員可以有相同的名字而不發(fā)生沖突。每一個(gè)結(jié)構(gòu)體必須要以分號(hào)結(jié)束。 結(jié)構(gòu)體定義并不占用內(nèi)存中的其他空間,只是創(chuàng)建了一種新的可用來定義變量的數(shù)據(jù)類型(struct+tag)。定義結(jié)構(gòu)體變量如下:
struct Node node, nodes[50], *nodePtr;分別定義了一個(gè)struct Node類型的變量,一個(gè)包含了50個(gè)struct Node類型的元素的數(shù)組,和一個(gè)指向該結(jié)構(gòu)體類型的指針。也可通過如下方式定義變量:
struct Node { int a; struct Node *next;}node, nodes[50], *nodePtr;結(jié)構(gòu)體定義時(shí)可以省略標(biāo)記名,但是如果省略了標(biāo)記名,則該結(jié)構(gòu)體類型變量的聲明就只能和結(jié)構(gòu)體定義同時(shí)進(jìn)行,不能進(jìn)行單獨(dú)的聲明。如下:
struct { int a; float b;}node, nodes[50], *nodePtr;一個(gè)結(jié)構(gòu)體不能包含它自身類型的實(shí)例,但是指向自身類型的指針可以出現(xiàn)。一個(gè)結(jié)構(gòu)體定義中出現(xiàn)指向自身結(jié)構(gòu)體體類型的指針成員的結(jié)構(gòu)體,被稱為自引用結(jié)構(gòu)體。 可用于結(jié)構(gòu)體的操作:將結(jié)構(gòu)體變量賦值給其他具有相同類型的結(jié)構(gòu)體變量,用&取得結(jié)構(gòu)體變量的地址,訪問一個(gè)結(jié)構(gòu)體變量中的成員,sizeof確定結(jié)構(gòu)體的大小。
總共有三種方式可以實(shí)現(xiàn)結(jié)構(gòu)體初始化。 一、可以通過將一個(gè)結(jié)構(gòu)體變量賦值給另一個(gè)與其類型相同的結(jié)構(gòu)體變量,從而對(duì)后者初始化。 二、可以通過對(duì)結(jié)構(gòu)體變量中的每一個(gè)成員分別進(jìn)行賦值來實(shí)現(xiàn)初始化。 三、可以與數(shù)組一樣采用初始值列表來初始化結(jié)構(gòu)體,如果列表中的初始值個(gè)數(shù)少于結(jié)構(gòu)體中成員個(gè)數(shù)時(shí),則剩余沒有初始值與之對(duì)應(yīng)的成員,將被自動(dòng)的初始化為0(當(dāng)成員是指針時(shí),被初始化為NULL)。對(duì)于函數(shù)之外定義的(即外部的)結(jié)構(gòu)體變量,如果在定義時(shí)沒有被顯式的初始化,則自動(dòng)被初始化為0或NULL。
對(duì)結(jié)構(gòu)體的訪問可以通過兩種運(yùn)算符來實(shí)現(xiàn),一個(gè)是結(jié)構(gòu)體成員運(yùn)算符(structure member Operator)(.),一個(gè)是結(jié)構(gòu)體指針運(yùn)算符(structure pointer operator)(->),也成為箭頭運(yùn)算符。 一、結(jié)構(gòu)體成員運(yùn)算符(.)通過結(jié)構(gòu)體變量名來訪問結(jié)構(gòu)體成員。如:
struct Node node = {1, NULL};二、結(jié)構(gòu)體指針運(yùn)算符(一個(gè)減號(hào)和一個(gè)大于號(hào)組成,中間沒有空格)通過指向結(jié)構(gòu)體的指針來訪問結(jié)構(gòu)體成員。如:struct Node node = {1, NULL};struct Node * nodePtr = &node;printf("%d", nodePtr->a);其中表達(dá)式nodePtr->a等價(jià)于*(nodePtr).a,圓括號(hào)不能少,因?yàn)榻Y(jié)構(gòu)體成員運(yùn)算符優(yōu)先級(jí)高于解引用運(yùn)算符優(yōu)先級(jí)。 一般不要在結(jié)構(gòu)體成員運(yùn)算符和結(jié)構(gòu)體指針運(yùn)算符的量變加上空格,有助于強(qiáng)調(diào)包含這些運(yùn)算符的表達(dá)式本質(zhì)上是一個(gè)單一變量名。
將結(jié)構(gòu)體傳遞給函數(shù)有三種方式,傳遞結(jié)構(gòu)體的個(gè)別成員,傳遞整個(gè)結(jié)構(gòu)體,傳遞一個(gè)指向結(jié)構(gòu)體的指針。當(dāng)結(jié)構(gòu)體或者結(jié)構(gòu)體的個(gè)別成員被傳遞給一個(gè)函數(shù)時(shí),它們是按值傳遞的方式被傳遞的。當(dāng)結(jié)構(gòu)體的個(gè)別成員或者整個(gè)結(jié)構(gòu)體被傳遞給一個(gè)函數(shù)時(shí),它們是按值傳遞的。而以傳地址方式傳遞一個(gè)結(jié)構(gòu)體,實(shí)際上是將結(jié)構(gòu)體變量的地址傳遞給被調(diào)函數(shù)。結(jié)構(gòu)體數(shù)組和其他數(shù)組一樣,都是自動(dòng)以傳地址傳遞的。
typedef提供了一種為已經(jīng)定義好的數(shù)據(jù)類型創(chuàng)建同義詞(或別名)的機(jī)制。如下:
typedef struct card Card;就為結(jié)構(gòu)體struct card定義了一個(gè)同義詞Card作為該類型的新名字。通常使用typedef,那樣就不再需要結(jié)構(gòu)體標(biāo)記了。如下:
typedef struct { int a; int b;} Node;直接創(chuàng)建了一個(gè)結(jié)構(gòu)體類型Node而不需要另外再編寫一條單獨(dú)的typedef。然而若省略結(jié)構(gòu)體標(biāo)記而使用typedef如下的自引用結(jié)構(gòu)體,并不能編譯通過:
typedef struct { int a; Node *next; //error:unknown type name 'Node'} Node;typedef是為一個(gè)已經(jīng)存在的數(shù)據(jù)類型,創(chuàng)建一個(gè)作為其別名的新類型名。type還常常被用來為基本數(shù)據(jù)類型創(chuàng)建一個(gè)別名,以便可移植在其余系統(tǒng)上。
由于結(jié)構(gòu)體中成員并不一定是連續(xù)的存儲(chǔ)在內(nèi)存單元中的,所以不能用==或者!=來對(duì)結(jié)構(gòu)體進(jìn)行比較。一些結(jié)構(gòu)體的存儲(chǔ)區(qū)域可能出現(xiàn)一些空洞,因?yàn)橛?jì)算機(jī)是按照一定邊界來存儲(chǔ)不同數(shù)據(jù)類型的變量的(如“半字”,“字”或“雙字”)。計(jì)算機(jī)中存儲(chǔ)數(shù)據(jù)的基本單位是一個(gè)字,通常是2或4個(gè)字節(jié)。對(duì)于空洞的值沒有專門的定義,所以即使結(jié)構(gòu)體中數(shù)據(jù)完全相同,也不能保證空洞中的值完全相同。 當(dāng)結(jié)構(gòu)體中有無符號(hào)整型或者有符號(hào)整型成員時(shí),C語言允許指定這些成員所占用的存儲(chǔ)位數(shù)(bit),被稱為位域(bit field)。通過將數(shù)據(jù)存儲(chǔ)在它們所需的最小的存儲(chǔ)空間內(nèi),可以有效的提高存儲(chǔ)空間的利用率。位域的使用如下:
struct bitCard { unsigned face : 4; unsigned suit : 2; unsigned color : 1;};聲明一個(gè)位域的方法是,在無符號(hào)整數(shù)或者有符號(hào)整數(shù)后加上一個(gè)冒號(hào)(:)和一個(gè)整型常數(shù),這個(gè)整型常數(shù)表示位域的寬度,這個(gè)表示寬度的常數(shù)必須是一個(gè)整數(shù),它的取值范圍是0到系統(tǒng)中正常存儲(chǔ)一個(gè)整型數(shù)所需的二進(jìn)制位數(shù)之間,包含該范圍的邊界值。 還可以指定一個(gè)無名位域,用來填充(padding)結(jié)構(gòu)體中的存儲(chǔ)縫隙,如下:
struct example { unsigned a : 13; unsigned : 19; unsigned c : 4;};填充的目的是為了使成員b能夠存儲(chǔ)在下一個(gè)存儲(chǔ)單元中。 寬度為0的無名位域可以用來使下一個(gè)位域?qū)R在一個(gè)新的存儲(chǔ)單元的邊界上。如下:
struct example { unsigned a : 13; unsigned : 0; unsigned c : 4;};就通過一個(gè)寬度為0的無名位域,來跳過存儲(chǔ)a的那個(gè)存儲(chǔ)單元中剩余的二進(jìn)制位(有多少位就跳多少位),將b對(duì)齊在下一個(gè)存儲(chǔ)單元上。位域操作依賴機(jī)器。試圖去獲取一個(gè)位域的地址是一個(gè)語法錯(cuò)誤。盡管位域可以節(jié)約存儲(chǔ)空間,但是它們會(huì)使編譯器生成運(yùn)行速度較慢的機(jī)器代碼,是一種以空間換時(shí)間的方法。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注