Download presentation
Presentation is loading. Please wait.
Published byἈδάμ Δασκαλοπούλου Modified 6年之前
1
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月
2
9.1 结构体类型和结构体变量 9.2 结构体数组 9.3 结构体指针变量 9.4 结构体类型数据在函数间的传递 9.5 union共用体
3
9.1 结构体类型和结构体变量 9.1.1 结构体类型定义 结构体类型是由不同类型的数据组成的,组成结构体类型的每一个数据都称为该结构体类型的成员。在程序设计中,使用结构体类型时,首先要对结构体类型的组成进行描述,结构体类型的定义方式如下所示: struct 结构体类型名称 { 数据类型 成员名1; 数据类型 成员名2; … 数据类型 成员名n; };
4
9.1 结构体类型和结构体变量 9.1.1 结构体类型定义 在上述语法结构中,“struct”是定义结构体类型的关键字,其后是所定义 “结构体类型名称”,在“结构体类型名称”下的大括号中,定义了结构体类型的成员项,每个成员是由“数据类型”和“成员名”共同组成的。 例如,描述一个学生信息,该信息包含学号(num)、姓名(name)、性别(sex)、年龄(age)、地址(address)等组成,这时可以使用下列语句定义一个名称为student的结构体类型:
5
9.1 结构体类型和结构体变量 9.1.1 结构体类型定义 在上述结构体定义中,结构体类型struct Student由5个成员组成,分别是num、name、sex、age和address。 struct Student { int num; char name[10]; char sex; int age; char address[30]; };
6
9.1 结构体类型和结构体变量 9.1.1 结构体类型定义 注意:
结构体类型定义以关键字struct开头,后面跟的是结构体类型的名称,该名称的命名规则与变量名相同。 定义好一个结构体类型后,并不意味着分配一块内存单元来存放各个数据成员,它只是告诉编译系统结构体类型是由哪些类型的成员构成,各占多个字节,按什么格式存储,并把它们当做一个整体来处理。
7
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 上个小节只是定义了结构体类型,它相当于一个模型,其中并无具体数据,系统也不会为它分配实际的内存空间。为了能在程序中使用结构体类型的数据,应该定义结构体类型的变量,并在其中存放具体的数据。下列是定义结构体变量的三种方式。 1、先定义结构体类型,再定义结构体变量 定义好结构体类型后,可以定义结构体变量,定义结构体变量的语法格式如下所示: struct 结构体类型名 结构体变量名;
8
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 例如:
上述定义了结构体类型变量stu1和stu2,这时,stu1和stu2便具有了结构体特征,它们各自都存储了一组基本类型的变量,具体如图9-1所示。 图9-1 stu1、stu2存储结构 从图9-1中可以看出,变量stu1和stu2分别占据了一块连续的内存单元。 struct student stu1,stu2;
9
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 2、在定义结构体类型的同时定义结构体变量
该方式的作用与第一种方式相同,其语法格式如下所示: struct 结构体类型名称 { 数据类型 成员名1; 数据类型 成员名2; … 数据类型 成员名n; } 结构体变量名列表;
10
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 例如:
上述代码在定义结构体类型student的同时,定义了结构体类型变量stu1和stu2。其中stu1和stu2中所包含的成员类型都是一样的。 struct student { int num; char name[10]; char sex; } stu1, stu2;
11
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 3、直接定义结构体变量
除上述两种方式外,还可以直接定义结构体变量,其语法格如下所示: struct { 数据类型 成员名1; 数据类型 成员名2; … 数据类型 成员名n; } 结构体变量名列表;
12
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 例如:
上述代码同样定义了结构体变量stu1和stu2,但采用这种方式定义的结构体是没有名称。 struct { 数据类型 成员名1; 数据类型 成员名2; … 数据类型 成员名n; } 结构体变量名列表;
13
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 注意: 结构体类型中的成员,可以是一个结构体变量,例如:
struct Date { int year; int month; int day; }; struct Student int num; char name[10]; char sex; struct Date birthday; } stu1;
14
9.1 结构体类型和结构体变量 9.1.2 结构体变量的定义 在上述代码中,首先定义了结构体类型Date,由year、month、day三个成员组成,然后定义了结构体变量stu1,其中的成员birthday是一个Date结构体类型。student的类型结构如图9-2所示。 图9-2 struct Student类型结构 另外,结构体变量占用的内存是各个成员所占字节数之和,例如,在变量stu1中,由于成员num占4个字节,name占10个字节,sex占1个字节,age占4个字节,birthday占12个字节,address占30个字节,因此,变量stu1占用的内存是各个成员所占字节数之和,即61个字节。
15
9.1 结构体类型和结构体变量 9.1.3 结构体变量的初始化
由于结构体变量中存储的是一组类型不同的数据,因此为结构体变量初始化的过程,其实就是为结构体中各个成员初始化的过程。根据结构体变量定义方式的不同,结构体变量初始化的方式可分为两种。
16
9.1 结构体类型和结构体变量 9.1.3 结构体变量的初始化 1、在定义结构体类型和结构体变量的同时,对结构体变量初始化,具体示例如下:
上述代码在定义结构体变量stu的同时,就对其中的成员进行了初始化。 struct Student { int num; char name[10]; char sex; } stu = { , "Zhang San", 'M'};
17
9.1 结构体类型和结构体变量 9.1.3 结构体变量的初始化 2、定义好结构体类型后,对结构体变量初始化,具体示例如下:
在上述代码中,首先定义了一个结构体类型Student,然后在定义结构体变量时,为其中的成员进行初始化。 struct Student { int num; char name[10]; char sex; }; struct Student stu = { , "Zhang San", 'M'};
18
9.1 结构体类型和结构体变量 9.1.4 结构体变量的引用 定义并初始化结构体变量的目的是使用结构体变量中的成员。在C语言中,引用结构体变量中一个成员的方式如下所示: 例如,下列的语句用于引用结构体变量stu1中num成员: 为了帮助大家更好地掌握结构体变量的使用,接下来通过一个案例来输出结构体变量中所有成员的值,如例9-1所示。 结构体变量名.成员名; stu1.num;
19
9.1 结构体类型和结构体变量 9.1.4 结构体变量的引用 例9-1 1 #include <stdio.h>
2 #include <stdlib.h> 3 struct Student 4 { 5 char name[50]; 6 int age; 7 }; 8 void main() 9 { 10 struct Student s = {"Zhang San", 23}; 11 printf("%s %d\n", s.name, s.age); 12 }
20
9.1 结构体类型和结构体变量 9.1.4 结构体变量的引用 运行结果如图9-3所示。
图9-3 运行结果 从图9-3中可以看出,结构体变量中成员name和age的值被输出了。
21
9.2 结构体数组 9.2.1 结构体数组的定义 假设一个班有20个学生,如果我们需要描述这20个学生的信息,可以定义一个长度为20的student类型数组,与定义结构体变量一样,可以采用三种方式定义结构体数组student。 1、先定义结构体类型,后定义结构体数组,具体示例如下: struct Student { int num; char name[10]; char sex; }; struct student stus[20];
22
9.2 结构体数组 9.2.1 结构体数组的定义 2、在定义结构体类型的同时定义结构体数组,具体示例如下:
3、直接定义结构体数组,具体示例如下: struct Student { int num; char name[10]; char sex; } stus[20]; struct { int num; char name[10]; char sex; } stus[20];
23
9.2 结构体数组 9.2.2 结构体数组的初始化 结构体数组的初始化方式与数组类似,都是通过为元素赋值的方式完成的。由于结构体数组中的每个元素都是一个结构体变量,因此,在为每个元素赋值的时候,需要将其成员的值依次放到一对大括号中。 例如,定义一个结构体数组Student,该数组有3个元素,并且每个元素有num、name、sex三个成员,可以采用下列两种方式对结构体数组student初始化。
24
9.2 结构体数组 9.2.2 结构体数组的初始化 1、先定义结构体数组类型,然后初始化结构体数组,具体示例如下:
struct Student { int num; char name[10]; char sex; }; struct Student students[3] = { { , "Zhang San", 'M'}, { , "Li Si", 'W'}, { , "Zhao Liu", 'M'}
25
9.2 结构体数组 9.2.2 结构体数组的初始化 2、在定义结构体数组的同时,对结构体数组初始化,具体示例如下:
struct Student { int num; char name[10]; char sex; } Student students[3] = { { , "Zhang San", 'M'}, { , "Li Si", 'W'}, { , "Zhao Liu", 'M'} };
26
9.2 结构体数组 9.2.2 结构体数组的初始化 当然,使用这种方式初始化结构体数组时,也可以不指定结构体数组的长度,系统在编译时,会自动根据初始化的值决定结构体数组的长度。例如,下列初始化方式也是合法的。 struct Student { int num; char name[10]; char sex; } Student students[] = { { , "Zhang San", 'M'}, { , "Li Si", 'W'}, { , "Zhao Liu", 'M'} };
27
9.2 结构体数组 9.2.3 结构体数组的引用 结构体数组的引用是指对结构体数组元素的引用,由于每个结构体数组元素都是一个结构体变量,因此,结构体数组元素的引用方式与结构体变量类似,其语法格式如下所示: 例如,要引用9.2.2小节中结构体数组student第一个元素的num成员,可以采用下列方式: 为了帮助读者更好地掌握结构体数组的使用,接下来,通过一个案例来输出结构体数组中的所有成员,如例9-2所示。 数组元素名称.成员名; student[0].num;
28
9.2 结构体数组 9.2.3 结构体数组的引用 例9-2 1 #include <stdio.h>
2 #include <stdlib.h> 3 struct Student 4 { 5 char name[50]; 6 int studentID; 7 }; 8 void main() 9 { 10 struct Student s[2] = {{"Zhang San", }, {"Li Si", }}; 11 for (int i = 0; i < 2; i++) 12 { 13 printf("%s %d\n", s[i].name, s[i].studentID); 14 } 15 }
29
9.2 结构体数组 9.2.3 结构体数组的引用 运行结果如图9-4所示。
图9-4 运行结果 在例9-2中,首先定义了一个长度为2的结构体数组s,并对数组中的元素进行了初始化。然后使用for循环,依次输出了s[0]和s[1]中的成员值。
30
9.3 结构体指针变量 9.3.1 结构体指针变量 在使用结构体指针变量之前,首先需要定义结构体指针,结构体指针的定义方式与一般指针类似,例如,下列语句定义了一个Student类型的指针。 在上述代码中,定义了一个结构体指针p,并通过“&”将结构体变量s的地址赋值给p,因此,p就是指向结构体变量s的指针。 当程序中定义了一个指向结构体变量的指针后,就可以通过“指针名->成员变量名”的方式来访问结构体变量中的成员,接下来通过一个案例来演示结构体指针的用法,如例9-3所示。 struct Student s = {"Zhang San", , 'M', 93.5}; struct Student *p = &s;
31
9.3 结构体指针变量 9.3.1 结构体指针变量 例9-3 1 #include <stdio.h>
2 #include <stdlib.h> 3 struct Student 4 { 5 char name[50]; 6 int studentID; 7 }; 8 void main() 9 { 10 struct Student s = {"Zhang San", }; 11 struct Student *p = &s; 12 printf("%s %d\n", p->name, p->studentID); 13 }
32
9.3 结构体指针变量 9.3.1 结构体指针变量 运行结果如图9-5所示。
图9-5 通过指针访问成员变量 在例9-3中,首先定义了一个结构体类型变量s,并将变量s中的成员name初始化为Zhang San,studentID 初始化为 。然后,定义了一个结构体指针p,并将p指向s的地址,最后,通过p->name访问成员name和studentID的值。从图9-5中可以看出,使用结构体指针同样可以访问结构体变量中的成员。
33
9.3 结构体指针变量 9.3.2 结构体数组指针 指针可以指向结构体数组,即将结构体数组的起始地址赋给指针变量,这种指针就是结构体数组指针,例如,下面语句定义了student结构体的一个数组和该数组的指针。 在上述代码中,p是一个student结构体数组指针,从定义上看,它和结构体指针没什么区别,只不过指向的是结构体数组。 为了帮助读者更好地掌握结构体数组指针的用法,接下来通过一个案例来演示如何使用结构体数组指针输出多个学生的信息,如例9-4所示。 struct Student stu1[10], *p=&stu1;
34
9.3 结构体指针变量 9.3.2 结构体数组指针 例9-4 1 #include <stdio.h>
2 #include <stdlib.h> 3 struct student 4 { 5 int num; 6 char name[20]; 7 char sex; 8 int age; 9 } stu[3] = { 10 { , "Wang Ming", 'M', 19}, 11 { , "Zhang Ning", 'W', 23}, 12 { , "Wang Ming", 'M', 19} 13 }; 13 void main() 14 { 15 struct student *p; 16 printf("No\t\tName\t\tsex\tage\n"); 17 for (p=stu; p<stu+3; p++) 18 { 19 printf("%ld\t%-12s\t%-2c\t%4d\n",p->num,p->name,p->sex,p->age); 20 } 21 }
35
9.3 结构体指针变量 9.3.2 结构体数组指针 运行结果如图9-6所示。
图9-6 运行结果 在例9-4中,第3~11行代码用于初始化结构体数组stu,在第15行代码中,“p=stu”用于将p指向结构体数组stu的第一个元素,“p++”用于将指针指向下一个元素。第17行代码,通过“->”用于获取某个成员的值。从图9-6中可以看出,程序输出了结构体数组stu中所有元素的成员值。
36
9.4 结构体类型数据在函数间的传递 9.4.1 结构体变量作为函数参数
结构体变量作为函数参数的用法与普通变量类似,都需要保证调用函数的实参类型和被调用函数的形参类型相同。接下来,通过一个案例来演示如何将结构体变量作为函数参数传递数据,如例9-5所示。
37
9.4 结构体类型数据在函数间的传递 9.4.1 结构体变量作为函数参数 例9-5 1 #include <stdio.h>
2 struct Student 3 { 4 char name[50]; 5 int studentID; 6 }; 7 void printInfo(struct Student stu) 8 { 9 printf("name: %s\n", stu.name); 10 printf("id: %i\n", stu.studentID); 11 } 12 void main() 13 { 14 struct Student student = {"Zhang San", 1}; 15 printInfo(student); 16 }
38
9.4 结构体类型数据在函数间的传递 9.4.1 结构体变量作为函数参数 运行结果如图9-7所示。
图9-7 运行结果 在例9-5中,定义了一个用于输出数据的printfInfo()函数,该函数需要接收一个结构体类型的参数。从代码第15行可以看出,当将结构体变量作为参数传递给函数时,其传参的方式与普通变量相同。
39
9.4 结构体类型数据在函数间的传递 9.4.2 结构体数组作为函数参数
函数间不仅可以传递一般的结构体变量,还可以传递结构体数组。接下来,通过一个案例来演示如何使用结构体数组作为函数参数传递数据,如例9-6所示。
40
9.4 结构体类型数据在函数间的传递 9.4.2 结构体数组作为函数参数 例9-6 1 #include <stdio.h>
2 struct Student 3 { 4 char name[50]; 5 int studentID; 6 }; 7 void printInfo(struct Student stu[],int length) 8 { 9 for (int i = 0; i < length; i++) 10 { 11 printf("name: %s\n", stu[i].name); 12 printf("id: %i\n\n", stu[i].studentID); 13 } 14 } 15 void main() 16 { 17 struct Student students[3] = { 18 {"Zhang San", 1}, 19 {"Li Si", 2}, 20 {"Wang Wu", 3} 21 }; 22 printInfo(students, 3); 23 }
41
9.4 结构体类型数据在函数间的传递 9.4.2 结构体数组作为函数参数 运行结果如图9-8所示。
图9-8 运行结果 在例9-6中,由于无法通过数组直接获取到其长度,因此,在定义的printfInfo()函数中,需要传递两个参数,其中一个是结构体数组,另一个是数组的长度。printfInfo()函数接收到传递来的数组名和长度后,使用for循环,将结构体数组中的所有成员输出。
42
9.4 结构体类型数据在函数间的传递 9.4.3 结构体指针作为函数参数
结构体指针变量用于存放结构体变量的首地址,所以将指针作为函数参数传递时,其实就是传递结构体变量的首地址。接下来,通过一个案例来演示如何将结构体指针作为函数参数传递数据,如例9-7所示。
43
9.4 结构体类型数据在函数间的传递 9.4.3 结构体指针作为函数参数 例9-7 1 #include <stdio.h>
2 struct Student 3 { 4 char name[50]; 5 int studentID; 6 }; 7 void printInfo(struct Student* stu) 8 { 9 printf("name: %s\n", stu->name); 10 printf("id: %i\n\n", stu->studentID); 11 } 12 void main() 13 { 14 struct Student student = { "Zhang San", 1 }; 15 printInfo(&student); 16 }
44
9.4 结构体类型数据在函数间的传递 9.4.3 结构体指针作为函数参数 运行结果如图9-9所示。
图9-9 运行结果 在例9-7中,定义了一个用于输出数据的printfInfo()函数,该函数需要接收一个结构体指针类型的参数,由于结构体指针作为函数参数时,需要传递的是结构体变量的首地址,因此,在代码第15行中,通过“&”获取结构体变量student的首地址,然后将其作为参数传递给printfInfo()函数。
45
9.5 union共用体 9.5.1 共用体类型的定义 在C语言中,共用体类型同结构体类型一样,都属于构造类型,它在定义上与结构体类型十分相似,定义共用体类型的语法格式如下所示: 在上述语法格式中,“union”是定义共用体类型的关键字,其后是所定义“共用体类型名称”,在“共用体类型名称”下的大括号中,定义了共用体类型的成员项,每个成员是由“数据类型”和“成员名”共同组成的。 union 共用体类型名称 { 数据类型 成员名1; 数据类型 成员名2; …… 数据类型 成员名n; };
46
9.5 union共用体 9.5.1 共用体类型的定义 例如下面这段代码:
上述代码定义了一个名为data的共用体类型,该类型由三个不同类型的成员组成,这些成员共享同一块存储空间。 union data { int m; float x; char c; };
47
9.5 union共用体 9.5.2 共用体变量的定义 共用体变量的定义和结构体变量的定义类似,假如要定义两个data类型的共用体变量a和b,则可以采用下列三种方式。 1、先定义共用体类型,再定义共用体变量,具体示例如下: union data { int m; float x; char c; }; union data a, b;
48
9.5 union共用体 9.5.2 共用体变量的定义 2、在定义共用体类型的同时定义共用体变量,具体示例如下:
3、直接定义共用体类型变量,具体示例如下: union data { int m; float x; char c; } a, b; union { int m; float x; char c; } a, b;
49
9.5 union共用体 9.5.2 共用体变量的定义 上述三种方式都用于定义共用体变量a和b,并且共用体变量a、b所分配的内存空间是一样的。以共用体a为例,它由三个成员组成,分别是m、x和c,编译时,系统会按照最长的成员为它分配内存,由于成员x的长度最长,它占4个字节,所以共用体变量a的内存空间也为4个字节。共用体a中成员内存的分配情况如图9-10所示。 图9-10 共用体变量a的成员内存情况
50
9.5 union共用体 9.5.2 共用体变量的定义 从图9-10中可以看出,共用体和结构体的定义形式类似,但是它们的含义却不同。结构体变量所占用的内存长度是各成员所占内存长度之和,而共用体变量所占的内存长度却是成员中占内存最长的长度,例如,共用体变量a在内存中占用的长度是4个字节,但如果a是结构体的话,占用的内存长度是7个字节。
51
9.5 union共用体 9.5.3 共用体变量的引用和初始化
在共用体变量定义的同时,只能用第一个成员的类型值进行初始化,共用体变量初始化的方式如下所示: 从上述语法格式可以看出,尽管只能给第一个成员赋值,但必须用大括号括起来。 例如,下列语句用于对data类型的共用体变量a进行初始化。 union 共用体类型名 共用体变量={第一个成员的类型值} union data a={8};
52
9.5 union共用体 9.5.3 共用体变量的引用和初始化
完成了共用体变量的初始化后,就可以引用共用体中的成员了,共用体变量的引用方式与结构体类似,例如,下列代码定义了一个共用体变量a和一个共用体指针p。 如果要引用共用体变量中的m成员,则可以使用下列方式: union data { int m; float x; char c; }; union data a, *p=&a; a.m; // 引用共用体变量a中的成员m p->m // 引用共用体指针变量p所指向的变量成员m
53
9.5 union共用体 9.5.3 共用体变量的引用和初始化
需要注意的是,虽然共用体变量的引用方式与结构体类似,但两者是有区别的,其主要区别是,在程序执行的任何特定时刻,结构体变量中的所有成员是同时驻留在该结构体变量所占用的内存空间中,而共用体变量仅有一个成员驻留在共用体变量所占用的内存空间中。接下来通过一个案例来验证,如例9-8所示。
54
9.5 union共用体 9.5.3 共用体变量的引用和初始化 例9-8 1 #include <stdio.h>
2 union Data 3 { 4 int i; 5 int j; 6 }; 7 void main() 8 { 9 union Data d; // 定义了一个union 10 d.i = 15; 11 printf("%d\n", d.i); 12 printf("%d\n", d.j); 13 d.j = 23; 14 printf("%d\n", d.i); 15 printf("%d\n", d.j); 16 printf("%p\n", &d.i); 17 printf("%p\n", &d.j); 18 }
55
9.5 union共用体 9.5.3 共用体变量的引用和初始化 运行结果如图9-11所示。
图9-11 运行结果 在例9-8中,定义了一个Data类型的共用体变量d,其中包含了两个int类型的变量i和j,当将i赋值为15时,由于i和j的长度一致,因此,对i赋值就相当于给j赋值。同理,当将j赋值为23时,j的值会将之前i的值覆盖,最终i和j的值都为23。
56
本章主要讲解了结构体和共用体两种构造类型,其中,结构体允许将若干个相关的、数据类型不同的数据作为一个整体处理,并且每个数据各自分配了不同的内存空间,而共用体中所有的成员共享同一段内存空间。
通过本章的学习,希望大家熟练掌握结构体和共用体的定义、初始化以及引用方式,为后期复杂数据的处理提供有力的支持。
Similar presentations