C/C++ 第十讲 结构

10.1 结构体类型

例:输入5个学生的信息,如何将这些信息按平均分倒序排序并输出?学生信息:学号、姓名、语文、数学、外语三门课成绩。

  • 如何描述5个学生的信息?
  1. 独立变量:30个;
  2. 通常的数组:定义多个数组,分别存放5人的姓名、学号、成绩
  3. 使用结构类型数组!
1
2
3
4
5
6
struct Student
{
char name[20];
char no[7];
int Chinese,English,math;
}s[5];

结构类型的概念

按类型和性质将可能不同但有关联的数据组合在一起构成的集合。

结构类型如何声明

1
2
3
4
5
6
7
struct 结构类型标识符  //结构类型关键字
{
结构成员1定义;
结构成员2定义;
...;
结构成员n定义;
}; //;不能省!!
  • 结构变量的成员可以像同类型普通变量一样使用;

  • 结构成员名可以与结构外的其他变量同名,二者不代表同一个对象;

结构类型可以嵌套定义,即一个结构类型的变量可以作为另一结构类型的成员。(但不能作为自身的)

例:先声明结构类型date,再声明结构类型person

1
2
3
4
5
6
7
8
9
10
11
12
13
struct date
{
int month;
int day;
int year;
};
struct person
{
char name=[];
char sex;
int age;
struct date birthday;//也可以直接date birthday
};

image-20231109105019428

结构成员 birthday 是内嵌在 struct person 类型中的另一个结构类型的变量。

结构变量如何定义

结构类型不是程序操作的对象,不占用内存空间,只有在定义结构变量后,系统才会为之分配内存单元。定义方式:

  • 先声明结构类型再定义结构变量
  • 在声明结构类型的同时定义结构变量
  • 省略结构标识符直接定义结构变量

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct person
{
char name[15];
char sex;
int age;
struct date birthday;
}p1,p2;//声明类型的同时定义变量

struct person
{
char name[15];
char sex;
int age;
struct date birthday;
};
struct person p1,p2; //先声明类型再定义变量

struct
{
char name[15];
char sex;
int age;
struct date birthday;
}p1,p2;//无类型名变量,也只能有这里定义的两个变量了

struct student
{
char name[30];
char num[10];
double score;
}s= {"FangMin", "1300010", 87};
/*结构变量的初始化:
该初始化语句为结构变量 s 的 name 成员赋初值"FangMin"、为 num 成员赋初值"1300010"、为 score 成员赋初值 87。*/

10.2 结构体变量

结构变量的访问

结构成员的访问

结构变量多数情况下需访问到成员,而不能整体访问。

  • 通过结构变量访问成员:

    结构变量名.成员名

  • 通过指向结构的指针访问成员:

    (*指向结构的指针).成员名

    注:括号不能省略,否则优先.运算

    • 指针访问成员的专门运算符:

    p->name

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct date
{
int month;
int day;
int year;
};

struct person
{
char name[15];
char sex;
int age;
date birthday;
}p1,*p=&p1;

可如下访问:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
p1.age=21;
strcpy(p->name,"Fang Min"); //p->name是字符数组,赋值要用strcpy函数
p->birthday.month=8;//p->birthday已经是date类型变量,和month的关系是.

//对p1赋值(普通):
strcpy (p1.name, "Fang Min");
p1.sex = 'F';
p1.age = 24;
p1.birthday.month = 8;
p1.birthday.day = 10;
p1.birthday.year = 1989;

//借助结构指针对p1赋值:
strcpy(p->name, "Fang Min");
p->sex = 'F';
p->age = 24;
p->birthday.month = 8;
p->birthday.day = 10;
p->birthday.year = 1988;

其中,

name 成员为字符数组,对字符数组赋值必须通过调用 strcpy 函数实现,而不能直接用赋值语句;

birthday 成员本身又是一个内嵌的结构类型变量,所以也要按结构成员访问方式访问到它的具体成员 year、 month、 day。

总结:小心字符数组char s[N]和内嵌型结构变量。

访问原则

  • 不允许整体输入输出结构变量,必须逐成员输入输出;
  • 允许整体赋值做函数参数
  • 引用成员时若成员本身又属复杂类型,则需逐级找到最低一级成员;
  • 成员需遵循同类型普通变量的使用规则及其各种运算。

初始化

  • 结构变量初始化

    各成员的初值按顺序组织在{}中。

    1
    2
    3
    4
    5
    6
    7
    8
    struct person
    {
    char name[15];
    char sex;
    int age;
    struct date birthday;
    };
    struct person p={"Tom",'F',18,{12,21,2015}}
  • 结构数组初始化

    每个数组元素都是一个结构变量,组织在内层{}中;所有数组元素组织在外层{}中。

    1
    2
    3
    4
    5
    6
    struct student
    {
    char name[15];
    char num[7];
    int score;
    }p[10]={{"Fang Min","1403235",84},{"Fang Hua","1403256",75}};//p[0]和p[1]初始化了,p[2]~p[9]的成员值默认为空串或0
    1
    2
    gets(p1.name);
    gets(name);

10.3 结构的应用

引例的实现

输入5个学生的信息,如何将这些信息按平均分倒序排序并输出?学生信息:学号、姓名、语文、数学、外语三门课成绩。

分析:

  • 数据结构的选取:应将平均分也定义在“学生”结构类型中;
  • 正确理清层次关系;
  • 明确输入、输出、赋值等操作数据的访问要求。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "iostream"
#define N 5
using namespace std;
struct student
{
char name[20];
char no[7];
double Chinese,Engilsh,math,avg;
};
int main()
{
int i,j;
student s[N],t;//s[N]:student类数组,输入如下:
for(i=0;i<N;i++)
{
cin>>s[i].name>>s[i].Chinese>>s[i].English>>s[i].math;//逐元素逐成分输入
s[i].avg=(s[i].Chinese+s[i].English+s[i].math)/3;
}
//冒泡法排序
for(i=0;i<N-1;i++)
for(j=0;j<N-1-i;j++)
if(s[j].avg>s[j+1].avg) //结构变量允许整体赋值
{
t=s[j];
s[j]=s[j+1];
s[j+1]=t;
}
for(i=0;i<N-1;i++)
{
cout<<s[i].name<<" "<<s[i].no<<" "<<s[i].Chinese<<" ";
cout<<s[i].English<<" "<<s[i].math<<" "<<s[i].avg<<endl;
}
system('pause');
return 0;
}

附:如果对学号(字符串)排序,则需要使用strcmp():

1
if(strcmp(s[i].no,s[i+1].no)>0)

结构变量在函数中的应用

例:定义包含小时、分钟、秒三个成员的时间结构类型,写一转换函数 ,将24小时制的时间转换成12小时制。

分析:

  • 函数参数:接受时间,参数为结构类型变量
  • 函数返回值:同为结构类型。
  • 为方便输出,将是否转换的判断放在主函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "iostream"
#define N 5
using namespace std;
struct time
{
int hour;
int minute;
int second;
};
struct time change(struct time t) //允许结构变量整体做参数//注意此函数的特征
{
t.hour=t.hour%12;
return t;//返回结构类型
}
int main()
{
struct time t;
cin>>t.hour>>t.minute>>t.second;
if(t.hour>12)
{
t=change(t);
cout<<t.hour<<":"<<t.minute<<":"<<t.second<<"pm";
}
else
cout<<t.hour<<":"<<t.minute<<":"<<t.second<<"am";
system('pause');
return 0;
}

总结

  • 结构数组是元素为结构类型变量的数组,对该数组操作时需遵循数组的使用原则,对每个元素操作时要符合结构变量的引用原则;
  • 结构变量在输入输出时必须引用到最低级成员;
  • 结构变量做函数参数及赋值运算时可整体引用。

指针:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct student
{
char* name;
int grade;
}p[2];
int main()
{
char s;
gets(s);
char* p=s;
//或者
p=new char[20];
s[i].name=new char[10];
}

作业

测试:各类型变量所占内存字节

sizeof(char) = 1;

sizeof(int) = 4;

sizeof(long) = 4;

sizeof(float) = 4;

sizeof(double) = 8.

指针类型的sizeof

指针用于存放地址,它等于计算机内部地址总线的宽度,所以32位计算机中,一个[指针变量]的返回值是4字节(与指针变量的类型无关)。可以预计,在64位系统中指针变量的sizeof等于8。

sizeof(p) = 4;

数组的sizeof

数组的sizeof值等于数组所占用的内存字节数,如:

char a1[] = “abc”;

int a2[3];

sizeof( a1 ); // 结果为4,字符串末尾还存在一个NULL终止符

sizeof( a2 ); // 结果为3_4=12(3_sizeof(int))

数组元素个数的求法:

sizeof(a1)/sizeof(*a1);

编程

1

有一组关于学生成绩的信息,编写函数max,该函数返回值为分数最高的学生的信息(包括学号和分数)。再编写主函数对其进行调用并输出最高分者的信息。假设结构类型定义为:

1
2
3
4
5
struct student
{
char *num;
int score;
};

提示:num定义为指针类型,注意向其复制内容之前要先为其申请空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# include <iostream>
#define N 256
using namespace std;
struct student
{
char* num;
int score;
};
struct student max(struct student s[N],int n)
{
struct student t = {0,s[0].score };
t.num = (char*)malloc(sizeof(char));
for (int i = 0; i < n; i++)
{
if (s[i].score > t.score)
{
t.score = s[i].score;

t.num = s[i].num;

}
}
return t;
}
int main()
{
struct student s[N] = {}, t = {};
int n,i;
t.num = (char*)malloc(sizeof(char));
cout << "输入学生数:" << endl;
/*char a[N];
s->num = a;*/
cin >> n;
cout << "输入各学生序号及成绩:" << endl;
for (i = 0; i < n; i++)
{
s[i].num = (char*)malloc(sizeof(char));
cin >> s[i].num >> s[i].score;
}
t=max(s,n);
cout << "最高分者序号为" << *t.num <<",分值为:" << t.score << endl;
system("pause");
return 0;
}

标答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
#define N 5
struct student
{
char *num;
int score;
};
student max(student s[],int n)
{
student t=s[0];
for(int i=1;i<n;i++)
if(s[i].score>t.score)
t=s[i];
return t;
}
int main()
{
student s[N],maxs;
int i;
for(i=0;i<N;i++)
{
s[i].num=new char[10];//假设学号不超过9位
cin>>s[i].num>>s[i].score;
}
maxs=max(s,N);
cout<<maxs.num<<' '<<maxs.score<<endl;
system("pause");
return 0;
}

2

编写程序,定义一个日期结构变量,计算某日期是本年度的第几天。提示:为简单起见,可定义一个存放12个月中每个月总天数的数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# include <iostream>
#define N 256
using namespace std;
struct time
{
int month;
int date;
};
int change(struct time t,bool run)
{
int i,num=0, a[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }, b[12] = { 31,29,31,30,31,30,31,31,30,31,30,31 };
if (run == 1)
for (i = 0; i < t.month-1; i++)
num += b[i];
else
for (i = 0; i < t.month-1; i++)
num += a[i];
num += t.date;
return num;
}
int main()
{
struct time t;
bool run;
int num;
cout << "今年是不是闰年?(是:1;否:0)" << endl;
cin >> run;
cout << "输入一日期(月/日)" << endl;
cin >> t.month >> t.date;
num = change(t, run);
cout << "这是今年的第" << num << "天" << endl;
system("pause");
return 0;
}

3

‏使用结构数组输入10本书的名称和单价,调用函数按照书名的字母顺序序进行排序,在主函数输出排序结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#define N 5
using namespace std;
struct book
{
char name[100];
int price;
};
/*int *sort(struct book b[])
{
int i, j, *m[N],a;
for(i=0;i<N-1;i++)
for (j = 0; j < N - 1 - i; j++)
{
if (b[j].name > b[j + 1].name)
{
a = b[j].num;
b[j].num = b[j + 1].num;
b[j + 1].num = a;
}
}
for (i = 0; i < N; i++)
*m[i] = b[i].num;
return *m;
}*/
struct book *sort(struct book b[])
{
int i, j;
struct book a;
for(i=0;i<N-1;i++)
for (j = 0; j < N - 1 - i; j++)
{
//for(int z=0; b[j].name[z] != '\0' && b[j + 1].name[z] != '\0';z++)
if (strcmp(b[j].name, b[j+1].name) > 0)
{
a = b[j];
b[j] = b[j + 1];
b[j + 1] = a;
}
}
struct book* p = b;
return p;
}
int main()
{
struct book b[N],*p;
int i;
for (i = 0; i < N; i++)
cin >> b[i].name >> b[i].price;
p = sort(b);
cout << "排序后结果:" << endl;
for (i = 0; i < N; i++)
cout << p[i].name << ' ' << p[i].price << endl;
system("pause");
return 0;
}