——理解C++和數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)
指針不僅可以指向變量、數(shù)組、函數(shù),還可以和結(jié)構(gòu)(structure)聯(lián)系起來,這使得C語言的威力倍增,初學(xué)C語言的朋友對(duì)結(jié)構(gòu)可能不太重視,對(duì)它的理解也不夠深入,但事實(shí)上,結(jié)構(gòu)是一個(gè)非常重要的工具,有了它我們可以很輕松的構(gòu)建一些僅靠其它C語言特性做起來很復(fù)雜的程序。深入地理解結(jié)構(gòu)會(huì)對(duì)你理解C++的面向?qū)ο笥泻艽髱椭⑶視?huì)讓在你學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)時(shí)有一份愜意的心情。(本講中默認(rèn)讀者已經(jīng)對(duì)結(jié)構(gòu)有了基本的認(rèn)識(shí))
附:在本講的最后,會(huì)提供上一講復(fù)雜聲明的答案。
1.深入理解結(jié)構(gòu)
<1>.為什么需要結(jié)構(gòu)
C語言中有很多內(nèi)置類型,如int型、double型、char型等,但僅僅使用這些類型并不能很好地表達(dá)我們的意圖。假如我們想表示一輛汽車,汽車有很多自身的屬性,如:最大功率、車重、顏色、最高時(shí)速、價(jià)格等等。這些屬性都應(yīng)該和汽車緊密相連,我們每構(gòu)造一輛車時(shí),這些固有的屬性都應(yīng)該一并被定義。有了這種需求,就催生了結(jié)構(gòu)。結(jié)構(gòu)有時(shí)也被翻譯為結(jié)構(gòu)體。當(dāng)我們定義了一個(gè)結(jié)構(gòu)后,就意味著定義了一種新的類型,結(jié)構(gòu)是C語言中為數(shù)不多的能讓我們自己掌控所定義類型的語言特性,在C中使用結(jié)構(gòu)可以把不同類型的值存儲(chǔ)在一起。
<2>.使用結(jié)構(gòu)
首先看一個(gè)例子,我將用這個(gè)例子貫穿本講的內(nèi)容:
struct car
{
char name[50];
int max_power;
int weight;
char color[20];
int max_speed;
int PRice;
struct car *next;
} one_car, famous_cars[12];
關(guān)鍵字struct表示將要定義一個(gè)結(jié)構(gòu),編譯器會(huì)將從struct直到分號(hào)為止的部分識(shí)別為一個(gè)結(jié)構(gòu)。花括號(hào)中存放我們要進(jìn)行組合的內(nèi)容,car是一個(gè)可選(optional)的結(jié)構(gòu)標(biāo)簽(tag),也叫結(jié)構(gòu)名,有了這個(gè)標(biāo)簽我們就可以在將來的程序中用struct car作為struct{int max_power; int weight; char color[20]; int max_kph; float price;}的簡(jiǎn)寫形式。右花括號(hào)后的one_car是一個(gè)structcar類型的變量,而famous_cars[12]是一個(gè)數(shù)組,這個(gè)數(shù)組包含了20個(gè)structcar類型的元素。
結(jié)構(gòu)中的所有內(nèi)容都稱作成員,所有成員必須在結(jié)構(gòu)的內(nèi)部聲明,一旦結(jié)構(gòu)定義完成后,就沒有任何辦法可以增加成員了。當(dāng)定義了一個(gè)結(jié)構(gòu)后不僅定義了一個(gè)新的類型,同時(shí)也定義了一個(gè)新的作用域,在struct car中有7個(gè)成員,這些成員的作用范圍只是這個(gè)結(jié)構(gòu)中,我們?cè)诮Y(jié)構(gòu)外是看不到也用不了的,如果想用怎么辦呢。可以通過成員操作符(.)來訪問結(jié)構(gòu)中的成員。(.)的左操作數(shù)是結(jié)構(gòu)變量名,右操作數(shù)是成員名,如果我想把one_car的顏色設(shè)置成紅色,那么可以寫one_car.color= "red";現(xiàn)在我還想將12輛名車中的第一輛車的價(jià)格調(diào)整到525萬元,如:famous_cars[0].price = 525;此時(shí)的famous_cars[0]和one_car是同一類的對(duì)象,都是struct car類型的變量,只不過famous_cars[0]是隸屬于famous_cars[12]這個(gè)數(shù)組的一個(gè)元素,而one_car是個(gè)自由身罷了。
<3>.結(jié)構(gòu)的自引用
大家應(yīng)該早已注意到struct car中的最后一個(gè)成員struct car *next了,有些朋友對(duì)此不太理解。結(jié)構(gòu)可以包含任意類型的成員,包括其他類型的結(jié)構(gòu),當(dāng)然也可以包含自身類型的結(jié)構(gòu),但在定義這種結(jié)構(gòu)時(shí),只能寫成包含指向自身類型的指針,而不能寫成以下這種形式:
struct car
{
char name[50];
int max_power;
int weight;
char color[20];
int max_speed;
int price;
struct car next; //錯(cuò),此時(shí)類型不完整,不能包含自身類型的變量
};
因?yàn)閚ext是另一個(gè)完整的結(jié)構(gòu)變量,它的內(nèi)部同樣會(huì)包含一個(gè)成員struct car next,這個(gè)成員還會(huì)包括一個(gè)成員struct car next,如此下去永無休止,編譯器將無法確定這個(gè)結(jié)構(gòu)struct car的大小。為了解決這個(gè)問題,我們可以把第一個(gè)成員聲明為struct car *next;,一個(gè)struct car結(jié)構(gòu)的指針就是用來存儲(chǔ)同類型結(jié)構(gòu)變量的地址的,是有固定長度的,此時(shí)編譯器可以輕松確定struct car的大小。
2.指向結(jié)構(gòu)的指針
剛剛說過的struct car *next就是一個(gè)指向結(jié)構(gòu)的指針,它既可以在結(jié)構(gòu)內(nèi)作為一個(gè)結(jié)構(gòu)成員,也可以作為一個(gè)自由的對(duì)象出現(xiàn)在結(jié)構(gòu)定義后面的任何地方,現(xiàn)在我們?cè)賮矶x一個(gè)指向struct car類型的指針car_pointer:structcar *car_pointer = &one_car;。現(xiàn)在我們擁有了一個(gè)指向結(jié)構(gòu)的指針,如何通過這個(gè)指針來訪問結(jié)構(gòu)變量中的成員呢?同樣是通過解引用操作符,比如現(xiàn)在想將one_car的發(fā)動(dòng)機(jī)進(jìn)行調(diào)教,把最大功率增加100千瓦:(*car_pointer).max_power += 100;首先通過*操作符獲取結(jié)構(gòu)變量one_car,然后再對(duì)它的max_power成員進(jìn)行修改。特別要注意括號(hào)不能丟,因?yàn)槌蓡T操作符.的優(yōu)先級(jí)高于*操作符,如果沒有括號(hào)的話將會(huì)導(dǎo)致錯(cuò)誤。正是由于這個(gè)有些令人厭煩的訪問方式,C語言提供了更加快捷且易于理解的方式——(->)操作符。通過這個(gè)操作符,我們就無需再受丟括號(hào)的困擾了。 -> 操作符和 . 操作符具有同樣的優(yōu)先級(jí)。使用方法:car_pointer-> max_power += 100;
3.鏈?zhǔn)酱鎯?chǔ)
有了以上的基礎(chǔ),現(xiàn)在可以來討論通過結(jié)構(gòu)與指向結(jié)構(gòu)的指針構(gòu)建的一種存儲(chǔ)數(shù)據(jù)的方式——鏈?zhǔn)酱鎯?chǔ)了。假設(shè)現(xiàn)在要組織一次名車的巡礼活動(dòng),車輛的排列順序按品牌的字典序進(jìn)行。為了保證車隊(duì)的連貫性,車與車之間通過繩索連接起來。這幅圖景如果用程序來表現(xiàn)是這樣的:
#include <stdio.h>
#include <stdlib.h>
struct car
{
char name[50];
int max_power;
int weight;
char color[20];
int max_speed;
int price;
struct car *next;
};
int main()
{
int i = 0;
struct car*car_pointer = (struct car *)malloc(sizeof(struct car));
struct car *record = car_pointer;
struct car *remove = car_pointer;
struct car *current = car_pointer;
for (i; i < 2; i++)
{
car_pointer->next = (struct car *)malloc(sizeof(structcar));
printf("Please input car's name : ");
scanf("%s",car_pointer->name);
printf("%s's max_power : ",car_pointer->name);
scanf("%d",&car_pointer->max_power);
printf("%s's weight : ",car_pointer->name);
scanf("%d",&car_pointer->weight);
printf("%s's color : ",car_pointer->name);
scanf("%s",car_pointer->color);
printf("%s's max_speed : ",car_pointer->name);
scanf("%d",&car_pointer->max_speed);
printf("%s's price : ",car_pointer->name);
scanf("%d",&car_pointer->price);
printf("/n");
car_pointer = car_pointer->next;
}
car_pointer->next =NULL;
printf("巡礼車輛如下:/n");
for (record;record->next != NULL; record = record->next)
{
printf("%s/n",record->name);
printf("%s's max_power : %dKW/n", record->name, record->max_power);
printf("%s's weight : %dKG/n", record->name, record->weight);
printf("%s's color : %s/n",record->name, record->color);
printf("%s's max_speed : %dKM/H/n", record->name, record->max_speed);
printf("%s's price : %d萬元(¥)/n",record->name, record->price);
printf("/n");
}
while(current->next != NULL)
{
remove = current;
current = current->next;
free(remove);
}
return 0;
}
首先,我們定義一個(gè)結(jié)構(gòu),然后在主函數(shù)中開辟一段能容納結(jié)構(gòu)struct car的內(nèi)存,并定義一個(gè)指向此結(jié)構(gòu)類型的指針car_pointer將其指向剛才所開辟的內(nèi)存空間。接下來定義幾個(gè)同類型的指針并初始化為car_pointer留作他用。在鏈?zhǔn)酱鎯?chǔ)中,每一塊這樣的內(nèi)存空間都被稱作結(jié)點(diǎn),代表著鏈中的一個(gè)實(shí)體。接下來的for循環(huán)用來控制創(chuàng)建多少個(gè)結(jié)點(diǎn),每一次循環(huán),都創(chuàng)建一個(gè)新的結(jié)點(diǎn),并用前一個(gè)結(jié)點(diǎn)的next成員指向新創(chuàng)建的結(jié)點(diǎn),再通過相應(yīng)的輸入來初始化每個(gè)結(jié)點(diǎn)的各個(gè)成員。在循環(huán)結(jié)束后,將最后一個(gè)結(jié)點(diǎn)的next成員置為NULL。
然后,用先前創(chuàng)建的指針record來控制這個(gè)車隊(duì)的輸出,因?yàn)榇藭r(shí)car_pointer已經(jīng)走到了車隊(duì)的末尾,無法再用它從頭進(jìn)行遍歷了。
最后將動(dòng)態(tài)分配的內(nèi)存釋放掉。注意此時(shí)同樣需要另一個(gè)指向車隊(duì)頭部的指針current,用來遍歷車隊(duì)鏈表,并創(chuàng)建一個(gè)remove指針指向要?jiǎng)h除的結(jié)點(diǎn)。如果我們不設(shè)置remove指針而是直接將current所指的結(jié)點(diǎn)釋放掉,就找不到下一個(gè)結(jié)點(diǎn)了。本例使用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)所創(chuàng)建的車隊(duì)鏈表如下圖所示:

4.用typedef給結(jié)構(gòu)創(chuàng)建別名
本將的最后一個(gè)話題,我們?cè)賮碚務(wù)則ypedef。關(guān)鍵字typedef用來給一種類型起一個(gè)別名,理所當(dāng)然地可以給一個(gè)結(jié)構(gòu)類型定義一個(gè)別名,用法上沒有什么區(qū)別。如果想給struct car定義一個(gè)別名Car可以這樣處理:
typedef struct car
{
char name[50];
int max_power;
int weight;
char color[20];
int max_speed;
int price;
struct car *next;
} Car;
通過typedef引入Car這個(gè)名字作為struct car {……}的簡(jiǎn)寫形式。此后我們就可以用Car來定義變量了,如Car one_car;或Car famous_cars[12]; 當(dāng)然也可以按如下的方式來起別名,而且會(huì)更清晰易讀:
struct car
{
char name[50];
int max_power;
int weight;
char color[20];
int max_speed;
int price;
struct car *next;
};
typedef struct car Car;
typedef struct car *CarPointer;
此時(shí)的CarPointer是struct car *類型的別名,即指向struct car的指針類型。理解了這種表示法對(duì)于理解C++中的類是很有幫助的。
差一點(diǎn)兒忘了,在第四講中復(fù)雜聲明還有懸而未決的問題,現(xiàn)在給出解答,如果有不明白或者有興趣深入研究的朋友可以聯(lián)系我:郵箱:porscheyin@hotmail.com,以下是原題及答案:
1. int *( *( *a[5]) ( ) ) ( );
Answer:a是一個(gè)數(shù)組,它的5個(gè)元素都是指向函數(shù)的指針,該函數(shù)仍舊返回一個(gè)指向函數(shù)的指針。
2. void * (*b) ( char, int (*) ( ) );
Answer:b是一個(gè)函數(shù)指針,該函數(shù)接受兩個(gè)形參,分別是char型和一個(gè)函數(shù)指針,返回值類型為void *。
3. float ( *(*c[10]) (int *) ) [5];
Answer:c是一個(gè)數(shù)組,它的10個(gè)元素都是指向函數(shù)的指針,所指函數(shù)接受int *型形參并返回一個(gè)指向數(shù)組的指針,這個(gè)數(shù)組包含5個(gè)float元素。
4. int ( *(*d)[2][3] ) [4][5];
Answer:d是一個(gè)指向數(shù)組的指針,此數(shù)組的元素又是一個(gè)指向數(shù)組的指針。
5. int (*(*(*e) ( int* ))[15]) (int*);
Answer:e是一個(gè)函數(shù)指針,該函數(shù)的返回值是一個(gè)指向數(shù)組的指針,所指向數(shù)組的元素又是函數(shù)指針,指向的函數(shù)具有int *型形參,返回值類型為int。
6. int ( *(*f[4][5][6]) (int*) ) [10];
Answer:f是一個(gè)數(shù)組,這個(gè)數(shù)組的元素是函數(shù)指針,這類函數(shù)具有int *型形參并返回指向數(shù)組的指針,所指向的數(shù)組的元素是具有10個(gè)int型元素。
7. int *(*(*(*g)( ))[10]) ( );
Answer:g是個(gè)指向函數(shù)的指針,它所指向的函數(shù)返回一個(gè)指向包含10個(gè)元素的數(shù)組的指針,數(shù)組元素的類型是指向函數(shù)的指針,所指向的函數(shù)不接受參數(shù)且返回值類型為int *。
另外,對(duì)于本講中的巡礼車隊(duì)程序,如果進(jìn)行相應(yīng)輸入后,會(huì)得到類似下面的輸出。我選了一些最新的世界知名車輛,它們的品牌與第四講中指針數(shù)組例子中的車輛品牌一致,我只是在每個(gè)品牌中選了一個(gè)車系,下面是輸出結(jié)果:
巡礼車輛如下:
ASTON-MATIN--DB9
ASTON-MATIN--DB9's max_power : 335KW
ASTON-MATIN--DB9's weight : 1760 KG
ASTON-MATIN--DB9's color : GREEN
ASTON-MATIN--DB9's max_speed : 300 KM/H
ASTON-MATIN--DB9's price : 304萬元(¥)
AUDI--R8
AUDI--R8's max_power : 309 KW
AUDI--R8's weight : 1560 KG
AUDI--R8's color : SILVER
AUDI--R8's max_speed : 301 KM/H
AUDI--R8's price : 180萬元(¥)
BENZ--SLR-722
BENZ--SLR-722's max_power : 478 KW
BENZ--SLR-722's weight : 1550 KG
BENZ--SLR-722's color : BLACK
BENZ--SLR-722's max_speed : 337 KM/H
BENZ--SLR-722's price : 888萬元(¥)
BENTLEY--CONTINENTAL-GTC
BENTLEY--CONTINENTAL-GTC'smax_power : 411 KW
BENTLEY--CONTINENTAL-GTC's weight: 2495 KG
BENTLEY--CONTINENTAL-GTC's color :AZURE
BENTLEY--CONTINENTAL-GTC'smax_speed : 312 KM/H
BENTLEY--CONTINENTAL-GTC's price :358萬元(¥)
BMW--M6
BMW--M6's max_power : 373 KW
BMW--M6's weight : 1785 KG
BMW--M6's color : BLUE
BMW--M6's max_speed : 250 KM/H
BMW--M6's price : 229萬元(¥)
BUGATTI--VEYRON-16.4
BUGATTI--VEYRON-16.4's max_power :736 KW
BUGATTI--VEYRON-16.4's weight : 1888 KG
BUGATTI--VEYRON-16.4's color :RED&BLACK
BUGATTI--VEYRON-16.4's max_speed :407 KM/H
BUGATTI--VEYRON-16.4's price :2500萬元(¥)
FERRARI--599GTB
FERRARI--599GTB's max_power : 456KW
FERRARI--599GTB's weight : 1690 KG
FERRARI--599GTB's color : RED
FERRARI--599GTB's max_speed : 330 KM/H
FERRARI--599GTB's price : 376萬元(¥)
JAGUAR--XK
JAGUAR--XK's max_power : 224 KW
JAGUAR--XK's weight : 1595 KG
JAGUAR--XK's color : GREEN
JAGUAR--XK's max_speed : 250 KM/H
JAGUAR--XK's price : 142萬元(¥)
LAMBORGHINI--MURCIELAGO-LP640
LAMBORGHINI--MURCIELAGO-LP640'smax_power : 471 KW
LAMBORGHINI--MURCIELAGO-LP640'sweight : 1665 KG
LAMBORGHINI--MURCIELAGO-LP640'scolor : BLACK
LAMBORGHINI--MURCIELAGO-LP640'smax_speed : 340 KM/H
LAMBORGHINI--MURCIELAGO-LP640'sprice : 438萬元(¥)
MASERATI--GRANTURISMO
MASERATI--GRANTURISMO's max_power: 298 KW
MASERATI--GRANTURISMO's weight : 1955 KG
MASERATI--GRANTURISMO's color :RED
MASERATI--GRANTURISMO's max_speed: 285 KM/H
MASERATI--GRANTURISMO's price :219萬元(¥)
MAYBACH--62S
MAYBACH--62S's max_power : 450 KW
MAYBACH--62S's weight : 2855 KG
MAYBACH--62S's color : WHITE
MAYBACH--62S's max_speed : 250 KM/H
MAYBACH--62S's price : 900萬元(¥)
ROLLS-ROYCE--PHANTOM-101EX
ROLLS-ROYCE--PHANTOM-101EX'smax_power : 338 KW
ROLLS-ROYCE--PHANTOM-101EX'sweight : 2590 KG
ROLLS-ROYCE--PHANTOM-101EX's color: BLUE
ROLLS-ROYCE--PHANTOM-101EX'smax_speed : 250 KM/H
ROLLS-ROYCE--PHANTOM-101EX's price: 680萬元(¥)
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注