数据结构

数据结构

数据结构是聚合在一个名称下的数据元素的集合。这些被称为成员的数据元素可以有不同的类型和不同的长度。在 C++ 中,可以使用以下语法声明数据结构:

struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;

其中 type_name 是结构类型的名称,object_name 可以是一组该结构类型的对象的有效标识符。在花括号 {} 内,是数据成员的列表,每个成员都用一个类型和一个有效的标识符作为其名称来指定。

例如:

1
2
3
4
5
6
7
struct product {
  int weight;
  double price;
} ;

product apple;
product banana, melon;

这里声明了一个名为 product 的结构类型,并定义它有两个成员:weightprice,每个成员都有不同的基本类型。这个声明创建了一个新的类型(product),然后用它来声明该类型的三个对象(变量):applebananamelon。请注意,一旦 product 被声明,它的使用方式就和任何其他类型一样。

struct 定义的末尾,分号(;)之前,可以使用可选字段 object_names 来直接声明该结构类型的对象。例如,结构对象 applebananamelon 可以在定义数据结构类型时就进行声明:

1
2
3
4
struct product {
  int weight;
  double price;
} apple, banana, melon;

在这种情况下,如果指定了 object_names,类型名称(product)就变成了可选的:struct 语句要么需要一个 type_name,要么在 object_names 中至少有一个名称,但不一定两者都需要。

很重要的一点是,要清楚地区分结构类型名称(product)和该类型的对象(applebananamelon)。从一个结构类型(product)可以声明出许多对象(例如 applebananamelon)。

一旦声明了某个特定结构类型的三个对象(applebananamelon),就可以直接访问它们的成员。语法很简单,在对象名和成员名之间插入一个点(.)。例如,我们可以像操作它们各自类型的标准变量一样来操作这些元素:

1
2
3
4
5
6
apple.weight
apple.price
banana.weight
banana.price
melon.weight
melon.

它们每一个的数据类型都与其所引用的成员相对应:apple.weightbanana.weightmelon.weight 的类型是 int,而 apple.pricebanana.pricemelon.price 的类型是 double

这里是一个结构类型在实际应用中的真实例子:

// example about structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct movies_t {
  string title;
  int year;
} mine, yours;

void printmovie (movies_t movie);

int main ()
{
  string mystr;

  mine.title = "2001 A Space Odyssey";
  mine.year = 1968;

  cout << "Enter title: ";
  getline (cin,yours.title);
  cout << "Enter year: ";
  getline (cin,mystr);
  stringstream(mystr) >> yours.year;

  cout << "My favorite movie is:\n ";
  printmovie (mine);
  cout << "And yours is:\n ";
  printmovie (yours);
  return 0;
}

void printmovie (movies_t movie)
{
  cout << movie.title;
  cout << " (" << movie.year << ")\n";
}
Enter title: Alien
Enter year: 1979

My favorite movie is:
 2001 A Space Odyssey (1968)
And yours is:
 Alien (1979)

这个例子展示了对象的成员如何像普通变量一样工作。例如,成员 yours.year 是一个 int 类型的有效变量,而 mine.title 是一个 string 类型的有效变量。

但对象 mineyours 本身也是有类型的变量(movies_t 类型)。例如,它们都被传递给了 printmovie 函数,就像它们是简单变量一样。因此,数据结构的一个特性就是能够既可以单独引用其成员,也可以引用整个结构。在这两种情况下,都使用相同的标识符:结构体的名称。

因为结构体是类型,所以它们也可以用作数组的类型,从而构建它们的表格或数据库:

// array of structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct movies_t {
  string title;
  int year;
} films [3];

void printmovie (movies_t movie);

int main ()
{
  string mystr;
  int n;

  for (n=0; n<3; n++)
  {
    cout << "Enter title: ";
    getline (cin,films[n].title);
    cout << "Enter year: ";
    getline (cin,mystr);
    stringstream(mystr) >> films[n].year;
  }

  cout << "\nYou have entered these movies:\n";
  for (n=0; n<3; n++)
    printmovie (films[n]);
  return 0;
}

void printmovie (movies_t movie)
{
  cout << movie.title;
  cout << " (" << movie.year << ")\n";
}
Enter title: Blade Runner
Enter year: 1982
Enter title: The Matrix
Enter year: 1999
Enter title: Taxi Driver
Enter year: 1976
 
You have entered these movies:
Blade Runner (1982)
The Matrix (1999)
Taxi Driver (1976)

指向结构体的指针

和其他任何类型一样,结构体也可以被其自己类型的指针指向:

1
2
3
4
5
6
7
struct movies_t {
  string title;
  int year;
};

movies_t amovie;
movies_t * pmovie;

这里 amovie 是一个 movies_t 结构类型的对象,而 pmovie 是一个指向 movies_t 结构类型对象的指针。因此,下面的代码也是有效的:

1
pmovie = &amovie;

指针 pmovie 的值将被赋为对象 amovie 的地址。

现在,让我们看另一个混合了指针和结构体的例子,它将引出一个新的运算符:箭头运算符(->)。

// pointers to structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct movies_t {
  string title;
  int year;
};

int main ()
{
  string mystr;

  movies_t amovie;
  movies_t * pmovie;
  pmovie = &amovie;

  cout << "Enter title: ";
  getline (cin, pmovie->title);
  cout << "Enter year: ";
  getline (cin, mystr);
  (stringstream) mystr >> pmovie->year;

  cout << "\nYou have entered:\n";
  cout << pmovie->title;
  cout << " (" << pmovie->year << ")\n";

  return 0;
}
Enter title: Invasion of the body snatchers
Enter year: 1978
 
You have entered:
Invasion of the body snatchers (1978)

箭头运算符(->)是一个解引用运算符,专门用于指向含有成员的对象的指针。这个运算符用于直接从对象的地址访问其成员。例如,在上面的例子中:

1
pmovie->

在所有方面,都等同于:

1
(*pmovie).

pmovie->title(*pmovie).title 这两个表达式都是有效的,都访问了由名为 pmovie 的指针所指向的数据结构的成员 title。这与下面的表达式完全不同:

1
*pmovie.

它实际上等同于:

1
*(pmovie.title)

这将访问结构对象 pmovie 中一个假设存在的名为 title 的指针成员所指向的值(但实际情况并非如此,因为 title 不是指针类型)。下表总结了指针运算符和结构成员运算符的可能组合:

表达式求值内容等价于
a.b对象 a 的成员 b
a->ba 指向的对象的成员 b(*a).b
*a.b对象 a 的成员 b 所指向的值*(a.b)

嵌套结构体

结构体也可以嵌套,即一个结构体的元素本身是另一个结构体:

1
2
3
4
5
6
7
8
9
10
11
12
struct movies_t {
  string title;
  int year;
};

struct friends_t {
  string name;
  string email;
  movies_t favorite_movie;
} charlie, maria;

friends_t * pfriends = &charlie;

在上述声明之后,以下所有表达式都将是有效的:

1
2
3
4
charlie.name
maria.favorite_movie.title
charlie.favorite_movie.year
pfriends->favorite_movie.

(顺便说一下,最后两个表达式引用的是同一个成员)。
Index
目录