## 3.5 數據結構 (Data Structures)
一個數據結構是組合到同一定義下的一組不同類型的數據,各個數據類型的長度可能不同。它的形式是:
struct model_name {
type1 element1;
type2 element2;
type3 element3;
.
.
} object_name;
這里model_name 是一個這個結構類型的模塊名稱。object_name 為可選參數,是一個或多個具體結構對象的標識。在花括號{ }內是組成這一結構的各個元素的類型和子標識。
如果結構的定義包括參數model_name (可選),該參數即成為一個與該結構等價的有效的類型名稱。例如:
struct products {
char name [30];
float price;
};
products apple;
products orange, melon;
我們首先定義了結構模塊products,它包含兩個域:name 和 price,每一個域是不同的數據類型。然后我們用這個結構類型的名稱 (products) 來聲明了 3個該類型的對象:apple, orange 和melon。
一旦被定義,products就成為一個新的有效數據類型名稱,可以像其他基本數據類型,如int, char或 short 一樣,被用來聲明該數據類型的對象(object)變量。
在結構定義的結尾可以加可選項object_name ,它的作用是直接聲明該結構類型的對象。例如,我們也可以這樣聲明結構對象apple, orange和melon:
struct products {
char name [30];
float price;
}apple, orange, melon;
并且,像上面的例子中如果我們在定義結構的同時聲明結構的對象,參數model_name (這個例子中的products)將變為可選項。但是如果沒有model_name,我們將不能在后面的程序中用它來聲明更多此類結構的對象。
清楚地區分結構模型model和它的對象的概念是很重要的。參考我們對變量所使用的術語,模型model 是一個類型type,而對象object 是變量variable。我們可以從同一個模型model (type)實例化出很多對象objects (variables)。
在我們聲明了確定結構模型的3個對象(apple, orange 和 melon)之后,我們就可以對它們的各個域(field)進行操作,這通過在對象名和域名之間插入符號點(.)來實現。例如,我們可以像使用一般的標準變量一樣對下面的元素進行操作:
apple.name
apple.price
orange.name
orange.price
melon.name
melon.price
它們每一個都有對應的數據類型:apple.name, orange.name 和melon.name 是字符數組類型char[30],而apple.price, orange.price 和 melon.price 是浮點型float。
下面我們看另一個關于電影的例子:
~~~
| // example about structures
#include ?iostream.h?
#include ?string.h?
#include ?stdlib.h?
struct movies_t {
char title [50];
int year;
}mine, yours;
void printmovie (movies_t movie);
int main () {
char buffer [50];
strcpy (mine.title, "2001 A Space Odyssey");
mine.year = 1968;
cout << "Enter title: ";
cin.getline (yours.title,50);
cout << "Enter year: ";
cin.getline (buffer,50);
yours.year = atoi (buffer);
cout << "My favourite movie is:\n ";
printmovie (mine);
cout << "And yours:\n";
printmovie (yours);
return 0;
}
void printmovie (movies_t movie) {
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
| Enter title: Alien
Enter year: 1979
My favourite movie is:
2001 A Space Odyssey (1968)
And yours:
Alien (1979)
|
~~~
這個例子中我們可以看到如何像使用普通變量一樣使用一個結構的元素及其本身。例如,yours.year 是一個整型數據int,而 mine.title 是一個長度為50的字符數組。
注意這里 mine 和 yours 也是變量,他們是movies_t 類型的變量,被傳遞給函數printmovie()。因此,結構的重要優點之一就是我們既可以單獨引用它的元素,也可以引用整個結構數據塊。
結構經常被用來建立數據庫,特別是當我們考慮結構數組的時候。
~~~
| // array of structures
#include ?iostream.h?
#include ?stdlib.h?
#define N_MOVIES 5
struct movies_t {
char title [50];
int year;
} films [N_MOVIES];
void printmovie (movies_t movie);
int main () {
char buffer [50];
int n;
for (n=0; n<N_MOVIES; n++) {
cout << "Enter title: ";
cin.getline (films[n].title,50);
cout << "Enter year: ";
cin.getline (buffer,50);
films[n].year = atoi (buffer);
}
cout << "\nYou have entered these movies:\n";
for (n=0; n
printmovie (films[n]);
return 0;
}
void printmovie (movies_t movie) {
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
| Enter title: Alien
Enter year: 1979
Enter title: Blade Runner
Enter year: 1982
Enter title: Matrix
Enter year: 1999
Enter title: Rear Window
Enter year: 1954
Enter title: Taxi Driver
Enter year: 1975
You have entered these movies:
Alien (1979)
Blade Runner (1982)
Matrix (1999)
Rear Window (1954)
Taxi Driver (1975)
|
~~~
### 結構指針(Pointers to structures)
就像其它數據類型一樣,結構也可以有指針。其規則同其它基本數據類型一樣:指針必須被聲明為一個指向結構的指針:
struct movies_t {
char title [50];
int year;
};
movies_t amovie;
movies_t * pmovie;
這里 amovie 是一個結構類型movies_t 的對象,而pmovie 是一個指向結構類型movies_t 的對象的指針。所以,同基本數據類型一樣,以下表達式正確的:
`pmovie = &amovie;`
下面讓我們看另一個例子,它將引入一種新的操作符:
~~~
| // pointers to structures
#include ?iostream.h?
#include ?stdlib.h?
struct movies_t {
char title [50];
int year;
};
int main () {
char buffer[50];
movies_t amovie;
movies_t * pmovie;
pmovie = & amovie;
cout << "Enter title: ";
cin.getline (pmovie->title,50);
cout << "Enter year: ";
cin.getline (buffer,50);
pmovie->year = atoi (buffer);
cout << "\nYou have entered:\n";
cout title;
cout year << ")\n";
return 0;
}
| Enter title: Matrix
Enter year: 1999
You have entered:
Matrix (1999)
|
~~~
上面的代碼中引入了一個重要的操作符:->。這是一個引用操作符,常與結構或類的指針一起使用,以便引用其中的成員元素,這樣就避免使用很多括號。例如,我們用:
`pmovie->title`
來代替:
`(*pmovie).title`
以上兩種表達式pmovie->title 和 (*pmovie).title 都是合法的,都表示取指針pmovie 所指向的結構其元素title 的值。我們要清楚將它和以下表達區分開:
`*pmovie.title`
它相當于
`*(pmovie.title)`
表示取結構pmovie 的元素title 作為指針所指向的值,這個表達式在本例中沒有意義,因為title本身不是指針類型。
下表中總結了指針和結構組成的各種可能的組合:
| 表達式 | 描述 | 等價于 |
| pmovie.title | 結構pmovie 的元素title |
|
| pmovie->title | 指針pmovie 所指向的結構其元素title 的值 | (*pmovie).title |
| *pmovie.title | 結構pmovie 的元素title 作為指針所指向的值 | *(pmovie.title) |
### 結構嵌套(Nesting structures)
結構可以嵌套使用,即一個結構的元素本身又可以是另一個結構類型。例如:
struct movies_t {
char title [50];
int year;
}
struct friends_t {
char name [50];
char email [50];
movies_t favourite_movie;
} charlie, maria;
friends_t * pfriends = &charlie;
因此,在有以上聲明之后,我們可以使用下面的表達式:
charlie.name
maria.favourite_movie.title
charlie.favourite_movie.year
pfriends->favourite_movie.year
(以上最后兩個表達式等價)
本節中所討論的結構的概念與C語言中結構概念是一樣的。然而,在C++中,結構的概念已經被擴展到與類(class)相同的程度,只是它所有的元素都是公開的(public)。在后面的章節[4.1“類”](http://www.prglab.com/cms/pages/c-tutorial/oo-programming/classes.php)中, 我們將進一步深入討論這個問題。