结构体类型

2015/05/20 C和C++基础
引出结构体

有时需要将不同类型的数据组合成一个有机的整体,以供用户方便地使用。这些组合在一个整体中的数据是互相联系的。例如,一个学生的学号、姓名、性别、年龄、成绩、家庭地址等项,都是这个学生的属性。

则可以通过下面的声明来建立所示的数据类型:

struct Student{       //声明一个结构体类型Student
	int num;          //包括一个整型变量num
	char name[20];    //包括一个字符数组name,可以容纳20个字符
	char sex;         //包括一个字符变量sex
    int age;          //包括一个整型变量age
	float score;      //包括一个单精度型变量
    char addr[30];    //包括一个字符数组addr,可以容纳30个字符
};                    //最后有一个分号

声明一个结构体类型的一般形式为:

struct 结构体类型名

{成员表列};

注意:在C语言中,结构体的成员只能是数据(如上面例子中所表示的那样)。C++对此加以扩充,结构体的成员既可以包括数据(即数据成员),又可以包括函数(即函数成员),以适应面向对象的程序设计。

定义结构体类型变量的方法

1.先声明结构体类型再定义变量。

比如:Student student1,student2;

在定义了结构体变量后,系统会为之分配内存单元。例如student1和student2在内存中各占63个字节(4+20+1+4+4+30=63)。

2.在声明类型的同时定义变量:

这种形式的定义的一般形式为:

struct 结构体名
{
    成员表列
}变量名表列;
struct Student{      //声明结构体类型Student
	int num;
	char name[20];
	char sex;
	int age;
	float score;
	char addr[30];
}student1,student2;  //定义两个结构体类型Student的变量student1,student2

3.直接定义结构体类型变量

其一般形式为:

struct{     //注意没有结构体类型名
	成员表列
}变量名表列;

结构体的成员也可以是一个结构体变量,如:

struct Date{         //声明一个结构体类型Date
	int month;
	int day;
	int year;
};

struct Student{      //声明一个结构体类型Student
	int num;
	char name[20];
	char sex;
	int	age;
	Date birthday;   //Date是结构体类型,birthday是Date类型的成员
	char addr[30];
}student1,student2;  //定义student1和student2为结构体类型Student的变量
结构体变量的初始化

和其他类型变量一样,对结构体变量可以在定义时指定初始值:

struct Student{
	int num;
	char name[20];
	char sex;
	int age;
	float score;
    char addr[30];
}student1={10001,"ZhangXin",'M',19,90.5,"Shanghai"};

也可以采取声明类型与定义变量分开的形式,在定义变量时进行初始化:

Student student1={10001,"ZhangXin",'M',19,90.5,"Shanghai"};
结构体变量的引用

(1).可以将一个结构体变量的值赋给另一个具有相同结构的结构体变量:

student1= student2;

(2).可以引用一个结构体变量中的一个成员的值。例如,student1.num表示结构体变量student1中的成员的值。

引用结构体变量中成员的一般方式为:

结构体变量名.成员名

(3).如果成员本身也是一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员。例如,对上面定义的结构体变量student1,可以这样访问各成员:

student1.birthday.month;

(4).不能将一个结构体变量作为一个整体进行输入和输出,比如:

cout<<student1;

(5).对结构体变量的成员可以像普通变量一样进行各种运算:

student2.scorestudent1.score;
sumstudent1.scorestudent2.score;
student1.age++;
++student1.age;

由于“.”运算符的优先级最高,因此student1.age++相当于(student1.age)++。++是student1.age进行自加运算,而不是先对age进行自加运算。

(6).可以引用结构体变量成员的地址,也可以引用结构体变量的地址:

cout<<&student1;       //输出student1的首地址
cout<<&student1.age;   //输出student1.age的地址

结构体变量的地址主要用作函数参数,将结构体变量的地址传递给形参。

结构体数组

一个结构体变量中可以存放一组数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组的不同之处在于:每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员项。

定义结构体数组

和定义结构体变量的方法相仿,定义结构体数组时只需声明其为数组即可。

struct Student{    //声明结构体类型Student
	int num;
	char name[20];
	char sex;
	int	age;
	float score;
	char addr[30];
};
Student stu[3];    //定义Student类型的数组stu
struct Student{
	int num;
	char name[20];
	char sex;
	int age;
	float score;
	char addr[30];
}stu[3];
struct{
	int num;
	char name[20];
	char sex;
	int age;
	float score;
    char addr[30];
}stu[3];

数组各元素在内存中连续存放:

结构体数组的初始化
struct Student{
	int num;
	char name[20];
	char sex;
	int age;
	float score;
	char addr[30];
}sty[3]={\{10101,"Li Lin",'M',18,87.5,"103 Beijing Road"},
         {10102,"Zhang Fun",'M'19,99,"130 Shanghai Road"},
         {10104,"Wang Min",'F',20,78.5,"1010,ZhongshanRoad"}\};

定义数组stu时,也可以不指定元素个数,即写成以下形式:

stu[]={\{},{},{}\};

编译时,系统会根据给出初值的结构体常量的个数来确定数组元素的个数。一个结构体常量应包括结 构体中全部成员的值。当然,数组的初始化也可以用以下形式:

Student stu[]={\{},{},{}\}; //已事先声明了结构体类型Student
指向结构体变量的指针

一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素。

1.通过指向结构体变量的指针引用结构体变量中的成员:

struct Student{    //声明结构体类型student
	int num;
	string name;
	char sex;
	float score;
};

Student stu;       //定义Student类型的变量stu
Student *p=&stu;   //定义p为指向Student类型数据的指针变量并指向stu
cout<<(*p).num<<" "<<p->num<<endl;

为了使用方便和使之直观,C++提供了指向结构体变量的运算符->,例如p->num表示指针p当前指向的结构体变量中的成员num。p->num和(*p).num是等价。

也就是说,以下3种形式等价:

1.结构体变量.成员名。如stu.num;

2.(*p).成员名。如(*p).num;

3.p->成员名。如p->num。“->”称为指向运算符。

p->n: 得到p指向的结构体变量中的成员n的值。

p->n++: 得到p指向的结构体变量中的成员n的值,用完该值后使它加1。

++p->n: 得到p指向的结构体变量中的成员n的值,并使之加1,然后再使用它。

用结构体变量和指向结构体变量的指针构成链表

链表是一种常见的重要的数据结构。如图表示最简单的一种链表(单向链表)的结构:

链表有一个“头指针”变量,图中以head表示,它存放一个地址。该地址指向一个元素。链表中的每一个元素称为“结点”,每个结点都应包括两个部分:一是用户需要用的实际数据,二是下一个结点的地址。 可以看到链表中各元素在内存中的存储单元可以是不连续的。要找某一元素,可以先找到上一个元素,根据它提供的下一元素地址找到下一个元素。

声明一个结构体类型,包含两种成员,一种是用户需要用的实际数据,另一种是用来存放下一结点地址的指针变量。例如:

struct Student{
	int num;
	float score;
	Student *next;    //next指向Student结构体变量
};
结构体类型数据作为函数参数

1.用结构体变量作函数参数:

#include <iostream>
#include <string>
using namespace std;
struct Student{       //声明结构体类型Student
	int num;
	char name[20];
	float score[3];
};

void print(Student stu){
	cout<<stu.num<<" "<<stu.name<<" "<<stu.score[0]<<" "<<
    stu.score[1]<<" "<<stu.score[2]<<endl;
}

int main( ){ 
	Studentstu;          //定义结构体变量
	stu.num=12345;       //以下5行对结构体变量各成员赋值
	stu.name="LiFung";
	stu.score[0]=67.5;
	stu.score[1]=89;
	stu.score[2]=78.5;
	print(stu);          //调用print函数,输出stu各成员的值
}

用结构体变量作实参和形参,程序直观易懂,效率是不高的。因为在实参传递给形参的时候需要从实参中每一个元素拷贝给形参。

2.用指向结构体变量的指针作实参:

#include <iostream>
#include <string>

using namespace std;

struct Student{
	int num;
	string name;                    //用string类型定义字符串变量
	float score[3];
}stu={12345,"LiFung",67.5,89,78.5}; //定义结构体student变量stu并赋初值

void print(Student *p){
	cout<<stu->num<<" "<<stu->name<<" "<<stu->score[0]<<" "<<
    stu->score[1]<<" "<<stu->score[2]<<endl;
}

int main(){
	Student*pt=&stu;   //定义基类型为Student的指针变量pt,并指向stu
	print(pt);         //实参为指向Student类数据的指针变量
}

采用指针变量作为实参和形参,空间和时间的开销都很小,效率较高。但程序(2)不如程序(1)那样直观。

3.用结构体变量的引用作函数参数:

#include <iostream>
#include <string>

using namespace std;

struct Student{
	int num;
	string name;                    //用string类型定义字符串变量
	float score[3];
}stu={12345,"LiFung",67.5,89,78.5}; //定义结构体student变量stu并赋初值


void print(Student &stu){
	cout<<stu.num<<" "<<stu.name<<" "<<stu.score[0]<<" "<<
    stu.score[1]<<" "<<stu.score[2]<<endl;
}

int main(){
	print(stu);    //实参为结构体Student变量
}

程序(3)的实参是结构体Student类型变量,而形参用Student类型的引用,虚实结合时传递的是stu的 地址,因而效率较高。它兼有(1)和(2)的优点。引用变量主要用作函数参数,它可以提高效率,而且保持程序良好的可读性。

Search

    Post Directory