抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

结构体类型

结构体类型与数组

结构体类型与函数

单链表

共同体声明

枚举类型

typedef声明

结构体类型

​ 在程序设计中,有时需要将不同类型的数据组合成一个有机的整体,以便于引用。例如,学生的信息包括学号、姓名、性别、年龄和成绩。如果用独立的变量:学号(sno)、姓名(name)、性别(sex)、年龄(age)和成绩(score)来表示。如图所示,变量之间是孤立的,很难体现数据之间的内在联系。

用单个变量表示学生信息

使用结构体类型,可以把多个数据项合成一个整体。学生信息可用结构体类型来描述。

用结构体类型描述学生信息

结构体类型声明

为描述学生信息,可声明一个结构体类型:

1
2
3
4
5
6
7
8
struct student
{
char sno[8]; //学号
char name[20]; //姓名
char sex; //性别
int age; //年龄
double score[3]; //三门课程的成绩
}

结构体类型 struct student ,包括 sno 、name 、 sex 、 age 和 score 共五个成员。struct student 是一个类型说明符,它和 int 、char 、 float 、 double 等一样,都可以用来指定变量的类型,只不过结构体类型 struct student 需要由程序员自行声明一样。


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

1
2
3
4
struct [标记名称]
{
成员列表
};

标记名称是一个标识符,也可以省略标记名称,表示匿名结构体类型。

结构体类型声明既可以放在函数之外,被其作用范围内的所有函数使用;也可以放在某个函数的函数体内,只能在该函数的函数体内使用。
如果 sizeof 运算符的运算对象是结构体类型,运算结果是所有成员占内存大小(按字节计算)再加上内部和尾部填充所占内存大小(按字节计算)的总和。

结构体类型的变量声明

  1. 先声明结构体类型再声明变量
1
2
3
4
5
struct 标记名称
{
成员列表
};
struct 标记名称 变量名1 [, 变量名2, 变量名3, …];

例如:

1
2
3
4
5
6
7
8
9
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score[3];
};
struct student s;
点击查看更多

struct student 才是类型说明符,以下两种声明变量的方法都是错误的。

struct s; //错误

student s; //错误

  1. 在声明结构体类型的同时声明变量
1
2
3
4
struct 标记名称
{
成员列表
} 变量名1 [, 变量名2, 变量名3, …];

例如:

1
2
3
4
5
6
7
8
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score[3];
} s1, s2;
  1. 使用匿名结构体类型声明变量
1
2
3
4
struct
{
成员列表
} 变量名1 [, 变量名2, 变量名3, …];

例如:

1
2
3
4
5
6
7
8
struct
{
char sno[8];
char name[20];
char sex;
int age;
double score[3];
} s1, s2;

结构体类型的成员,其类型也可以是结构体类型。例如,结构体类型 struct student 中的成员 age(年龄),由于年龄总是随着时间变化,比较好的方法是用生日代替年龄,生日是一个日期(由年、月、日组成),可以声明一个结构体类型来描述日期:

1
2
3
4
5
6
struct date
{
int year;
int month;
int day;
};

于是,描述学生信息的结构体类型声明可改为:

1
2
3
4
5
6
7
8
struct student
{
char sno[8];
char name[20];
char sex;
struct date birthday; //birthday的类型是struct date
double score[3];
};

初始化结构体类型的变量

在结构体类型的变量声明时给变量赋值,称为初始化。例如:

1
2
3
4
5
6
7
8
9
10
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score[3];
};

struct student s = {"2015001", "LiMing", 'M', 18, {85.0, 92.5, 95.5}};

在初始化结构体类型的变量时,大括号内的数据顺序必须与结构体类型中成员的声明顺序一致;否则,就会产生混乱。

如果某个成员的类型是结构体类型,其初始化方式如下:

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

struct student
{
char sno[8];
char name[20];
char sex;
struct date birthday; //birthday的类型是struct date
double score[3];
};

struct student t = {"2015001", "LiMing", 'M', {1997, 11, 18}, {85.0, 92.5, 95.5}};

引用结构体类型的变量

  1. 不能将结构体类型的变量作为一个整体进行输入或输出
1
2
3
4
5
6
7
8
9
10
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score[3];
};
struct student s = {"2015001", "LiMing", 'M', 18, {85.0, 92.5, 95.5}};
printf("%s, %s, %c, %d, %f, %f, %f", s); // 错误

引用结构体类型的变量中的成员要使用成员选择运算符 “ . ”,其一般形式:

1
结构体类型的变量名.成员名

例如:

1
2
3
s.age = 20;		//将20赋值给变量s中的成员age
s.age++; //使变量s中的成员age加1
sum = s.score[0] + s.score[1] + s.score[2];
  1. 如果成员本身又是一个结构体类型的变量,则要用若干成员运算符,一级一级地找到最低一级的成员
1
2
t.sno		
t.birthday.year
  1. 除了初始化,在其他位置只能用同类型的变量为结构体类型的变量赋值,或者为其成员赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score[3];
} s1, s2;
// 对s1的各个成员逐一赋值
strcpy(s1.sno, "2015001");
strcpy(s1.name, " LiMing");
s1.sex = 'M';
s1.age = 18;
s1.score[0] = 85.0;
s1.score[1] = 92.5;
s1.score[2] = 95.5;
s2 = s1; // 用同类型的变量 s1 为 s2 赋值

例题1

初始化结构体类型的变量,然后输出该变量。

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
#include <stdio.h>
int main(void)
{
struct student
{
char sno[9];
char name[20];
char sex;
int age;
double score[3];
};
struct student s = {"2018001", "QinHao", 'M', 21, {100, 95, 98}};
int i;
printf("sno: %s\n", s.sno);
printf("name: %s\n", s.name);
printf("sno: %c\n", s.sex);
printf("sno: %d\n", s.age);
printf("score: ");
for(i = 0;i < 3;i ++)
{
printf("%5.lf", s.score[i]);
}
printf("\n");
return 0;
}

运行结果:

1
2
3
4
5
sno: 2018001
name: QinHao
sno: M
sno: 21
score: 100 95 98

结构体类型 struct student 的声明放在 main 函数的函数体内,只能在 main 函数的函数体内使用 struct student 。

例题2

输入结构体类型的变量中各成员的值,为结构体类型的变量赋值。

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
#include <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score[3];
};
int main(void)
{
struct student s1, s2;
int i;
printf("Input the student's information: ");
scanf("%c%s%s%d", &s1.sex,s1.sno, s1.name, &s1.age);
for(i = 0;i < 3;i ++)
{
scanf("%lf", &s1.score[i]);
}
s2 = s1;
printf("sno: %s\n", s2.sno);
printf("name: %s\n", s2.name);
printf("sex: %c\n", s2.sex);
printf("age: %d\n", s2.age);
printf("score: ");
for(i = 0;i < 3;i ++)
{
printf("%6.1lf", s2.score[i]);
}
printf("\n");
return 0;
}

运行结果:

1
2
3
4
5
6
Input the student's information: M 2018001 QinHao 21 85.0 92.5 95.5
sno: 2018001
name: QinHao
sex: M
age: 21
score: 85.0 92.5 95.5

结构体函数 struct student 的声明放在 main 函数之前,struct student 可以被其作用范围内的所有函数使用。通常,将结构体、共同体或枚举类型的声明放在 main 函数之前。

指向结构体类型的指针变量

使用成员间接选择运算符“->”,可以直观、方便地通过指向结构体类型的指针变量访问该结构体类型变量的成员,其一般形式:

1
指向结构体类型的指针变量名->成员名

例题3

使用指向结构体类型的指针变量访问该结构体类型变量的成员。

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 <stdio.h>
#include <string.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
int main(void)
{
struct student s;
struct student *p; // 声明指向结构体类型的指针变量
strcpy(s.sno, "2018001");
strcpy(s.name, "QinHao");
s.sex = 'M';
s.age = 21;
s.score = 92.5;
puts("s.sno\t\ts.name\t\ts.sex\t\ts.age\t\ts.score");
printf("%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n\n", s.sno, s.name, s.sex, s.age, s.score);
p = &s; // 使指针变量 p 指向变量s
puts("(*p).sno\t(*p).name\t(*p).sex\t(*p).age\t(*p).score");
printf("%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n\n", (*p).sno, (*p).name, (*p).sex, (*p).age, (*p).score);
puts("p->sno\t\tp->name\t\tp->sex\t\tp->age\t\tp->score");
printf("%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n", p->sno, p->name, p->sex, p->age, p->score);
return 0;
}

运行结果:

1
2
3
4
5
6
7
8
s.sno           s.name          s.sex           s.age           s.score
2018001 QinHao M 21 92.5

(*p).sno (*p).name (*p).sex (*p).age (*p).score
2018001 QinHao M 21 92.5

p->sno p->name p->sex p->age p->score
2018001 QinHao M 21 92.5

编程练习1

声明结构体类型 struct book,描述图书信息:书名(title)、作者(author)、出版社(press)、价格(price)、数量(amount)。输入一本图书的信息,采用例题3的三种方式输出图书的信息。

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 <stdio.h>
#include <string.h>
struct book
{
char title[30];
char author[20];
char press[30];
double price;
int amount;
};
int main(void)
{
struct book b;
struct book *p;
strcpy(b.title, "疯狂Java讲义");
strcpy(b.author, "李刚");
strcpy(b.press, "电子工业出版社");
b.price = 79.0;
b.amount = 100;
puts("b.title\t\t\tb.author\t\tb.press\t\t\tb.price\t\t\tb.amount");
printf("%s\t\t%s\t\t\t%s\t\t%.1lf%\t\t\t%d\n\n", b.title, b.author, b.press, b.price, b.amount);
p = &b;
puts("(*p).title\t\t(*p).author\t\t(*p).press\t\t(*p).price\t\t(*p).amount");
printf("%s\t\t%s\t\t\t%s\t\t%.1lf\t\t\t%d\n\n", (*p).title, (*p).author, (*p).press, (*p).price, (*p).amount);
puts("(*p->title\t\t(*p->author\t\t(*p->press\t\t(*p->price\t\t(*p->amount");
printf("%s\t\t%s\t\t\t%s\t\t%.1lf\t\t\t%d\n", p->title, p->author, p->press, p->price, p->amount);
return 0;
}

运行结果:

20210315192454

编程练习2

声明结构体类型 struct date ,描述日期信息:年(year)、月(month)、日(day)。输入一个日期,计算并输出是这一年的第几天,注意判断是不是闰年。

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
#include <stdio.h>
struct date
{
int year;
int month;
int day;
};
int main(void)
{
struct date d;
int sum = 0, i;
int leapyear[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int commonyear[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
printf("请输入年:");
scanf("%d", &d.year);
printf("请输入月:");
scanf("%d", &d.month);
printf("请输入日:");
scanf("%d", &d.day);
if(d.year % 400 == 0 || (d.year % 4 == 0 && d.year % 100 != 0))
{
for(i = 0;i < d.month;i ++)
{
sum += leapyear[i];
}
sum += d.day;
}
else
{
for(i = 0;i < d.month;i ++)
{
sum += commonyear[i];
}
sum += d.day;
}
printf("%d年%d月%d日是%d年的第%d天\n", d.year, d.month, d.day, d.year, sum);
return 0;
}

运行结果:

1
2
3
4
请输入年:2020
请输入月:12
请输入日:31
2020年12月31日是2020年的第366天
1
2
3
4
请输入年:2021
请输入月:12
请输入日:31
2021年12月31日是2021年的第365天

结构体类型与数组

数组声明

  1. 先声明结构体类型再声明数组
1
2
3
4
5
6
7
8
9
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
struct student s[10];
  1. 在声明结构体类型的同时声明数组
1
2
3
4
5
6
7
8
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
} s[10];
  1. 使用匿名结构体类型声明数组
1
2
3
4
5
6
7
8
struct
{
char sno[8];
char name[20];
char sex;
int age;
double score;
} s[10];

引用数组元素的成员

数组元素的类型是结构体类型,可使用成员选择运算符引用数组元素的成员。

初始化数组

例题1

初始化数组,输出数组中的每一个数组元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
int main(void)
{
struct student s[3] = {
{"2018001", "Zhangsan", 'M', 18, 92.5},
{"2018002", "Lisi", 'F', 18, 95.5},
{"2018003", "Wangwu", 'M', 19, 85.0}
};
int i;
puts(" sno name sex age score");
for(i = 0;i < 3;i ++)
{
printf("%s%20s%5c%8d%12.1lf\n", s[i].sno, s[i].name, s[i].sex, s[i].age, s[i].score);
}
return 0;
}

运行结果:

20210315205559

例题2

输入三个学生的信息,输出成绩(score)高于平均成绩的学生信息。

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 <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
int main(void)
{
struct student s[3];
int i;
double sum = 0, avg = 0.0;
puts("Input three students' information (sex, sno, name, age, score):");
for(i = 0;i < 3;i ++)
{
// 先输入字符数据
scanf("%c%s%s%d%lf", &s[i].sex, &s[i].sno, &s[i].name, &s[i].age, &s[i].score);
getchar();
sum += s[i].score;
}
avg = sum / 3.0;
printf("The average score is %4.1lf\n", avg);
puts(" sno name sex age score");
for(i = 0;i < 3;i ++)
{
if(s[i].score > avg)
{
printf("%s%20s%5c%5d%8.1lf\n", s[i].sno, s[i].name, s[i].sex, s[i].age, s[i].score);
}
}
return 0;
}

运行结果:

20210315212109

编程练习

声明结构体类型 struct book,描述图书信息:书名(title)、作者(author)、出版社(press)、价格(price)、数量(amount)。输入五本图书的信息,按价格升序的方式对五本图书排序,输出排序后的图书信息。

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
#include <stdio.h>
struct book
{
char title[40];
char author[20];
char press[40];
double price;
int amount;
};
int main(void)
{
int i, j;
struct book b[5], temp;
printf("请输入5本书的资料(书名,作者,出版社,价格,数量):\n");
for(i = 0;i < 5;i ++)
{
scanf("%s%s%s%lf%d", &b[i].title, &b[i].author, &b[i].press, &b[i].price, &b[i].amount);
}
for(i = 0;i < 5;i ++)
{
for(j = 0;j < 4 - i;j ++)
{
if(b[j].price > b[j + 1].price)
{
temp = b[j];
b[j] = b[j + 1];
b[j + 1] = temp;
}
}
}
for(i = 0;i < 5;i ++)
{
printf("%s\t\t%s\t\t%s\t\t%.1lf\t\t%d\n", b[i].title, b[i].author, b[i].press, b[i].price, b[i].amount);
}
return 0;
}

运行结果:

20210316091354

结构体类型与函数

形参是结构体类型的变量

例题1

输入两个学生中成绩(score)较高的学生信息。

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 <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
struct student max(struct student t1, struct student t2);
int main(void)
{
struct student s1 = {"2018001", "Liming", 'M', 18, 92.5};
struct student s2 = {"2018002", "Wangfang", 'F', 18, 95.5};
struct student s;
s = max(s1, s2);
printf("sno: %s\n", s.sno);
printf("name: %s\n", s.name);
printf("sex: %c\n", s.sex);
printf("age: %d\n", s.age);
printf("score: %.1lf\n", s.score);
return 0;
}
struct student max(struct student t1, struct student t2)
{
if(t1.score > t2.score)
{
return t1;
}
else
{
return t2;
}
}

运行结果:

1
2
3
4
5
sno: 2018002
name: Wangfang
sex: F
age: 18
score: 95.5

例题2

修改学生的年龄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
void change(struct student t);
int main(void)
{
struct student s = {"2015001", "Liming", 'M', 18, 92.5};
puts("\t\t\tsno\t\tname\t\tsex\t\tage\t\tscore");
printf("Before modifying\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n", s.sno, s.name, s.sex, s.age, s.score);
change(s);
printf("After modifying\t\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n", s.sno, s.name, s.sex, s.age, s.score);
return 0;
}
void change(struct student t)
{
t.age ++;
}

运行结果

20210316093022

实参向形参的传递是单向的,在被调函数 change 中改变形参 t 的值并不影响实参 s 的值。因此,调用函数 change 后,学生的年龄依旧是 18 岁。

形参是指向结构体类型的指针变量

例题1

输出两个学生中成绩(score)较高的学生信息。

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 <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
struct student *max(struct student *p1, struct student *p2);
int main(void)
{
struct student s1 = {"2015001", "LiMing", 'M', 18, 92.5};
struct student s2 = {"2015002", "WangFang", 'F', 18, 95.5};
struct student *q;
q = max(&s1, &s2); //实参是结构体类型变量的地址
printf("sno: %s\n", q->sno);
printf("name: %s\n", q->name);
printf("sex: %c\n", q->sex);
printf("age: %d\n", q->age);
printf("score: %.1lf\n", q->score);
return 0;
}
// 形参是指向结构体类型的指针变量
struct student *max(struct student *p1, struct student *p2)
{
if(p1->score > p2->score)
{
return p1;
}
else
{
return p2;
}
}

运行结果:

1
2
3
4
5
sno: 2015002
name: WangFang
sex: F
age: 18
score: 95.5

例题2

修改学生的年龄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
void change(struct student *p);
int main(void)
{
struct student s = {"2015001", "LiMing", 'M', 18, 92.5};
struct student *q = &s;
puts("\t\t\tsno\t\tname\t\tsex\t\tage\t\tscore");
printf("Before modifying\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n", s.sno, s.name, s.sex, s.age, s.score);
change(q);
printf("After modifying\t\t%s\t\t%s\t\t%c\t\t%d\t\t%.1lf\n", s.sno, s.name, s.sex, s.age, s.score);
return 0;
}
void change(struct student *p)
{
p->age ++;
}

运行结果:

20210316094850

形参是数组元素为结构体类型的数组

例题1

输入三个学生的信息并输出。

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
#include <stdio.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
void input(int n, struct student t[ ]);
void output(int n, struct student *t);
int main(void)
{
struct student s[3];
input(3, s);
output(3, s);
return 0;
}
void input(int n, struct student t[ ])
{
int i;
printf("请输入%d位同学的信息(性别,学号,姓名,年龄,成绩)\n", n);
for(i = 0;i < n;i ++)
{
scanf("%c%s%s%d%lf", &t[i].sex, t[i].sno, t[i].name, &t[i].age, &t[i].score);
getchar();
}
}
void output(int n, struct student *t)
{
int i;
puts(" sno name sex age score");
for(i = 0;i < n;i ++)
{
printf("%s%20s%5c%5d%8.1lf\n", t[i].sno, t[i].name, t[i].sex, t[i].age, t[i].score);
}
}

运行结果:

20210316100449

编程练习1

声明结构体类型 struct book,描述图书信息:书名(title)、作者(author)、出版社(press)、价格(price)、数量(amount)。已知函数头及功能如下:

1
2
3
void input(int n, struct book t[ ]);		// 输入n本图书的信息到一维数组t中
void sort(int n, struct book t[ ]); // 对长度为n的一维数组t中的数组元素按价格升序排序
void output(int n, struct book t[[ ]); // 输出长度为n的一维数组t中的数组元素
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 <stdio.h>
struct book
{
char title[30];
char author[20];
char press[30];
double price;
int amount;
};
void input(int n, struct book t[ ]);
void sort(int n, struct book t[ ]);
void output(int n, struct book t[ ]);
int main(void)
{
struct book b[5];
input(5, b);
sort(5, b);
output(5, b);
}
void input(int n, struct book t[ ])
{
int i;
printf("请输入%d本图书的资料(书名,作者,出版社,价格,数量)\n", n);
for(i = 0;i < n;i ++)
{
scanf("%s%s%s%lf%d", t[i].title, t[i].author, t[i].press, &t[i].price, &t[i].amount);
getchar();
}
}
void sort(int n, struct book t[ ])
{
// 按照价格升序顺序排列
int i,j;
struct book temp;
for(i = 0;i < n;i ++)
{
for(j = 0;j < (n - 1) - i;j ++)
{
if(t[j].price > t[j + 1].price)
{
temp = t[j];
t[j] = t[j + 1];
t[j + 1] = temp;
}
}
}
}
void output(int n, struct book t[ ])
{
int i;
puts("title\t\tauthor\t\tpress\t\tprice\t\tamount");
for(i = 0;i < n;i ++)
{
printf("%s\t\t%s\t\t%s\t\t%.1lf\t\t%d\n", t[i].title, t[i].author, t[i].press, t[i].price, t[i].amount);
}
}

运行结果:

20210316102737

编程练习2

struct mycomplex 是表示复数的结构体类型,成员 real 表示实部,成员 image 表示虚部。已知函数头及功能如下:

1
2
3
4
5
6
7
8
9
struct mycomplex
{
double real;
double image;
};
struct mycomplex input(void); // 输入并返回一个复数
struct mycomplex add(struct mycomplex c1, struct mycomplex c2); // 计算并返回两个复数的和
struct mycomplex mul(struct mycomplex c1, struct mycomplex c2); // 计算并返回两个复数的乘积
void output(struct mycomplex c); // 输出一个复数
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
#include <stdio.h>
struct mycomplex
{
double real;
double image;
};
struct mycomplex input(void); // 输入并返回一个复数
struct mycomplex add(struct mycomplex c1, struct mycomplex c2); // 计算并返回两个复数的和
struct mycomplex mul(struct mycomplex c1, struct mycomplex c2); // 计算并返回两个复数的乘积
void output(struct mycomplex c); // 输出一个复数
int main(void)
{
struct mycomplex c1, c2, c3, c4;
c1 = input();
c2 = input();
c3 = add(c1, c2);
c4 = mul(c1, c2);
output(c3);
output(c4);
}
struct mycomplex input(void)
{
struct mycomplex c;
printf("请输入复数的实部和虚部:");
scanf("%lf%lf", &c.real, &c.image);
return c;
}
struct mycomplex add(struct mycomplex c1, struct mycomplex c2)
{
int i, j;
struct mycomplex c;
i = c1.real + c2.real;
j = c1.image + c2.image;
c.real = i;
c.image = j;
return c;
}
struct mycomplex mul(struct mycomplex c1, struct mycomplex c2)
{
struct mycomplex c;
int i, j;
i = c1.real * c2.real - c1.image * c2.image;
j = c1.image * c2.real + c1.real * c2.image;
c.real = i;
c.image = j;
return c;
}
void output(struct mycomplex c)
{
printf("%.lf + %.lfi\n", c.real, c.image);
}

运行结果:

1
2
3
4
请输入复数的实部和虚部:1 2
请输入复数的实部和虚部:3 4
4 + 6i
-5 + 10i

单链表

单链表的元素称为结点,每个结点包括两个域:存储实际数据的域称为数据域;存储下一个结点地址的域称为指针域。

为了在编程时方便处理,往往在单链表的第一个结点之前附设一个结点,称为头结点

头结点的数据域不存储任何信息,头结点的指针域存储第一个结点的地址

动态存储库函数

  1. 库函数 malloc

所需包含的头文件:stdlib.h

函数原型:

1
void *malloc(unsigned int size);

功能:分配长度为size个字节的存储单元,当执行成功时,返回一个指向所分配存储单元起始地址的指针;否则,返回NULL

  1. 库函数 free

所需包含的头文件:stdlib.h

函数原型:

1
void free(void *ptr);

功能:释放指针变量 ptr 指向的存储单元

例题1

调用库函数 malloc 和 free ,分配 、释放存储单元。

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
#include <stdio.h>
#include <stdlib.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
};
int main(void)
{
struct student *p;
puts("Input the students' information(sex, sno, name, age, score)");
p = (struct student *)malloc(sizeof(struct student));
scanf("%c%s%s%d%lf", &p->sex, p->sno, p->name, &p->age, &p->score);
printf("sno: %s\n", p->sno);
printf("name: %s\n", p->name);
printf("sex: %c\n", p->sex);
printf("age: %d\n", p->age);
printf("score: %.1lf\n", p->score);
free(p);
p = NULL;
return 0;
}

运行结果:

1
2
3
4
5
6
7
Input the students' information(sex, sno, name, age, score)
M 2015001 LiMing 18 92.5
sno: 2015001
name: LiMing
sex: M
age: 18
score: 92.5

单链表的基本操作

通常用结构体类型的变量来表示单链表中的结点,一个结构体类型的变量包含若干成员,用指针类型的成员存储下一个结点的地址

1
2
3
4
5
6
7
8
9
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
struct student *next;
}

其中,成员 snonamesexagescore 一起作为数据域,存储实际数据;成员next 是指向结构体类型 struct student 的指针变量,将成员next 作为指针域,存储下一个节点的地址。


实例1

建立一个学生信息的单链表,输出单链表中的学生信息,然后销毁单链表。

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <stdio.h>
#include <stdlib.h>
struct student
{
char sno[8];
char name[20];
char sex;
int age;
double score;
struct student *next;
};
// 将p 指向的节点作为第一个节点插入到以head为头指针的单链表中
void insert_node(struct student *head, struct student *p);
// 输出以 head 为头指针的单链表中所有学生的信息
void traverse(struct student *head);
// 删除以head为头指针的单链表的第一个节点
void delete_node(struct student *head);
int main(void)
{
struct student *h, *q;
int i, n;
printf("Input the number of students:");
scanf("%d", &n);
getchar(); // 读入并丢弃“回车符”
// 创建头节点,并设置头结点的指针域为空
h = (struct student *)malloc(sizeof(struct student));
h -> next = NULL;
printf("Input %d students' information(sex, sno, name, age, score):\n", n);
for(i = 0;i < n;i ++)
{
// 创建新节点
q = (struct student *)malloc(sizeof(struct student));
// 读入学生信息
scanf("%c%s%s%d%lf", &q->sex, q->sno, q->name, &q->age, &q->score);
getchar(); // 读入并丢弃“回车符”
// 将新节点作为第一个节点插入到单链表中
insert_node(h, q);
}
traverse(h);
while(h->next)
{
delete_node(h);
}
free(h);
h = NULL;
return 0;
}
void insert_node(struct student *head, struct student *p)
{
p -> next = head -> next;
head -> next = p;
}
void traverse(struct student *head)
{
struct student *p;
puts(" sno name sex age score");
p = head -> next; // 将p指向单链表的第一个结点
// 当p等于NULL时,整个链表输出完成,while语句结束
while(p)
{
// 输出p所指结点的数据域,即学生信息
printf("%s%20s%5c%5d%8.1lf\n", p->sno, p->name, p->sex, p->age, p->score);
p = p -> next; // 使p指向下一个结点
}
}
void delete_node(struct student *head)
{
struct student *p;
p = head -> next;
head -> next = p -> next;
printf("Deleting the student %s ...\n", p->sno);
free(p);
p = NULL;
}

运行结果:

20210316141108

共同体声明

共同体类型声明

共同体声明的一般形式:

1
2
3
4
union [标记名称]
{
成员列表
};

共同体类型的变量声明

  1. 先声明共同体类型再声明变量
1
2
3
4
5
union 标记名称
{
成员列表
};
union 标记名称 变量名1 [, 变量名2, 变量名3, ...];

例如:

1
2
3
4
5
6
7
union data
{
char ch;
int i;
double d;
};
union data x;
  1. 在声明共同体类型的同时声明变量
1
2
3
4
union 标记名称
{
成员列表
} 变量名1 [, 变量名2, 变量名3, ...];

例如:

1
2
3
4
5
6
union data
{
char ch;
int i;
double d;
} x1, x2;
  1. 使用匿名共同体类型声明变量
1
2
3
4
union
{
成员变量
} 变量名1 [, 变量名2, 变量名3, ...];

例如:

1
2
3
4
5
6
union
{
char ch;
int i;
double d;
} x1, x2;

初始化共同体类型的变量

在共同体类型的变量声明时给变量赋值,称为初始化。只能对共同体类型变量的第一个成员赋值,不能像结构体类型的变量那样对所有的成员赋值。例如:

1
2
3
4
5
6
7
8
9
union data
{
char ch;
int i;
double d;
};
union data x1, x2;
union data x1 = {'s'}; //正确,为第一个成员ch赋值's'
union data x2 = {'s', 100, 95.5}; //错误

引用共同体类型的变量

引用共同体类型的变量应遵守以下规则:

  1. 不能将共同体类型的变量作为一个整体进行输入和输出。
  2. 除了初始化,在其他位置只能用同类型的变量为共同体类型的变量赋值,或者为其他成员赋值。
  3. 共同体类型的变量中起作用的成员是最后一次赋值的成员,在给一个成员赋值后原有的成员就会失去作用。

例题

建立如表所示的成绩单,输入各科成绩,然后再输出。

课程名 评分方式 分数 等级
C Language Programming 百分制 90
College Chinese 五级分制 excellent
Advanced Mathematics 百分制 88
Introduction to Computers 五级分制 good
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
#include <stdio.h>
#include <string.h>
union method
{
int hundred; // 百分制成绩
char five[10]; // 五级分制成绩
};
struct course
{
char name[30]; // 课程名称
char mode; // 评分方式(h:百分制,f:五级制)
union method grade; // 共同体类型的成员表示不同类型的成绩
};
int main(void)
{
struct course report[4];
int i;
// 将课程名称存入结构体类型
strcpy(report[0].name, "C Language Programming");
strcpy(report[1].name, "College Chinese");
strcpy(report[2].name, "Advanced Mathematics");
strcpy(report[3].name, "Introduction to Computers");
// 输入各门课程的评分方式、考试成绩
for(i = 0;i < 4;i ++)
{
printf("Input the mode(h/f) of course \"%s\": ", report[i].name);
scanf("%c", &report[i].mode);
printf("Examination Result: ");
// 根据评分方式输入不同类型的考试成绩
if('h' == report[i].mode)
{
scanf("%d", &report[i].grade.hundred);
}
else
{
scanf("%s", report[i].grade.five);
}
getchar(); // 读入并丢弃回车符
}
puts("\nname mode grade");
for(i = 0;i < 4;i ++)
{
printf("%-30s%-16c", report[i].name, report[i].mode);
// 根据评分方式输出不同类型的考试成绩
if('h' == report[i].mode)
{
printf("%d\n", report[i].grade.hundred);
}
else
{
printf("%s\n", report[i].grade.five);
}
}
return 0;
}

运行结果:

20210316164129

枚举类型

所谓”枚举”,就是将变量的可取值一一列举出来,变量只能存、取其中的某个值,存、取其他值是错误的

枚举类型声明

枚举类型声明的一般形式:

1
enum [标记名称] {枚举常量1[, 枚举常量2, 枚举常量3, ...]};

标记名称是一个标识符,也可以省略标记名称,表示匿名枚举类型

枚举常量是类型为 int 的标识符

枚举类型声明既可以放在函数之外,被其作用范围内的所有函数使用;也可以放在某个函数的函数体内,只能在该函数的函数体内使用

枚举常量的值

*在枚举类型声明中,枚举常量的值从 0 开始,依次加 1 *

1
enum weekday {sun, mon, tue, wed, thu, fri, sat};
枚举常量 sun mon tue wed thu fri sat
枚举常量的值 0 1 2 3 4 5 6

例题

输出枚举常量的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
enum weekday {sun, mon, tue, wed, thu = 10, fri, sat};
int main(void)
{
printf("sun: %d\n", sun);
printf("mon: %d\n", mon);
printf("tue: %d\n", tue);
printf("wed: %d\n", wed);
printf("thu: %d\n", thu);
printf("fri: %d\n", fri);
printf("sat: %d\n", sat);
return 0;
}

运行结果:

1
2
3
4
5
6
7
sun: 0
mon: 1
tue: 2
wed: 3
thu: 10
fri: 11
sat: 12

枚举类型的变量声明

  1. 先声明枚举类型再声明变量
1
2
enum 标记名称 {枚举常量1[, 枚举常量2, 枚举常量3, ...]};
enum 标记名称 变量名1 [, 变量名2, 变量名3, ...];
  1. 在声明枚举类型的同时声明变量
1
enum 标记名称 {枚举常量1[, 枚举常量2, ...]} 变量名1 [, 变量名2, ...];
  1. 使用匿名枚举类型声明变量
1
enum {枚举变量1[, 枚举变量2, ...]} 变量名1 [, 变量名2, ...];

例题1

枚举类型的变量。

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
enum weekday {sun, mon, tue, wed, thu, fri, sat};
int main(void)
{
enum weekday today, tomorrow;
today = mon;
tomorrow = (enum weekday)(today + 1);
printf("today: %d\n", today);
printf("tomorrow: %d\n", tomorrow);
return 0;
}

运行结果:

1
2
today: 1
tomorrow: 2

例题2

间接输入、输出枚举类型的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
enum weekday {sun, mon, tue, wed, thu, fri, sat};
int main(void)
{
enum weekday today, tomorrow;
char *s[ ] = {"sun", "mon", "tue", "wed", "thu", "fri", "sat"};
int day;
printf("What day is today:\n");
printf("0--sun,1--mon,2--tue,3--wed,4--thu,5--fri,6--sat: ");
scanf("%d", &day); // 通过输入一个整数获知今天是星期几
today = (enum weekday)day;
// 根据today计算tomorrow
if(sat == today)
{
tomorrow = sun;
}
else
{
tomorrow = (enum weekday)(today + 1);
}
printf("Tomorrow is %s.\n", s[tomorrow]);
return 0;
}

运行结果:

1
2
3
What day is today:
0--sun,1--mon,2--tue,3--wed,4--thu,5--fri,6--sat: 5
Tomorrow is sat.

编程练习

输入五个学生的信息到数组 s 中,查找并输出平均成绩最高的学生的信息。

1
2
3
4
5
6
7
8
9
struct student
{
char sno[8]; //学号
char name[20]; //姓名
enum {male, female} sex; // 性别
int age; // 年龄
double score[3]; //成绩
};
struct student s[5];

typedef 声明

typedef声明(typedef declaration)并没有引入新类型,只是为已有类型引入一个同义词

为已有类型引入一个同义词的方法:

1
2
3
4
①声明变量
②将变量名换成新类型名
③在最前面加上typedef
④使用新类型名声明变量

评论




2019-2022 覃浩的博客 鄂ICP备2021017381号-1 正在载入...

PoweredHexo
HostedGitHub & Coding
DNSDNSPod
CDN腾讯云CDN
PictureBed腾讯云CDN
ThemeVolantis