结构与联合
一、结构体
(一)结构体类型的定义
结构体数据类型定义的一般形式为:
struct 结构体名
{
类型名 结构体成员名1;
类型名 结构体成员名2;
……
类型名 结构体成员名n ;
};
说明:
(1)struct 是结构体定义的标志,其后必须定义一个结构体名,结构体名是一个合法的C 语言标识符,struct 与结构变量名两者合起来共同组成结构体类型名;
(2)所有的成员清单必须用一对大括号括起来。
优点:信息整体性强,具有较高的可读性和清晰性,有利于数据的
处理。
(二)结构体变量
1、结构体变量的定义:
结构体变量说明有如下3种方法:
(1)定义结构体类型的同时,说明结构体变量。 例:struct student
{ int num ; charname[20]; char sex ; int age ; float score ; char addr[30];
}student1,student2
(2)在定义结构体类型之后,说明结构体变量。 例:struct student
{ int num ; charname[20]; char sex ; float score ;
};…
student1, student2
注意:将一个变量定义为标准类型(基本数据类型)与定义为结构
体类型不同之处在于后者不仅要求指定变量为结构体类型,而且要
求指定为某一特定的结构体类型,因为可以定义出许许多多种具体
的结构体类型。
(3)用无名结构体类型,直接说明结构体变量。
例:struct Array{ int num;
char name[20];
char sex;
float score;
}student1,student2;
注意:
(1)类型与变量是不同的概念,不要混同。只能对变量赋值、存取
或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型
是不分配空间的,只对变量分配空间。
(2)对结构体中的成员(即“域”),可以单独使用,它的作用与地
位相当于普通变量。
(3)成员也可以是一个结构体变量。
(4)成员名可以与程序中的变量名相同,二者不代表同一对象。
2、结构体类型的嵌套定义
方式:struct date
{
short month;
short day;
short year;
float math;
}wang,zhao,zhang;
3、对结构体变量初始化
#include
void main()
{struct student
{long int num;
char name[20];
char sex;
char addr[20];
}a={10101,″LiLin″,′M′,″123 Beijing Road″}; /* 对结构体变量a赋初值*/
printf(″No.:%ld\nname:%s\nsex:%c\naddress:%s\n″,
a.num,https://www.doczj.com/doc/096499169.html,,a.sex,a.addr); }
注:若某一项暂时不赋值,其中的分隔符“,”也不能省略。
4、使用的一般形式:结构变量名.成员名
结构体变量的使用应遵守以下规则
(1)不能将一个结构体变量最为一个整体惊醒输入和输出。只能对其中的各个成员分别进行输入和输出;
(2)同类结构体变量之间可以整体赋值;
(3)可以对一个结构体施加取地址操作,结果是结构体第一个成员的地址;
(4)成员(分量)运算符“.”的作用是引用结构体变量中的特定成员,一般形式是:结构体变量名.成员名
(5)成员运算符的优先级较一般的运算符要高(和数组下标运算符相同),为左结合性;
(6)如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级的找到最低一级的成员;
(7)对结构体变量的成员可以像普通变量一样进行相应类型所允许的各种运算。
(三)结构数组
结构体数组与以前介绍过的数值型数组不同之处在于每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员(分量)项。
1、结构数组的定义
首先必须定义结构类型,然后才可以定义结构数组。
方式:(1)可以在定义结构类型的同时,定义结构数组;
(2)可以在定义结构类型之后,再定义结构数组。
例:struct student
{ int num;
…或
}stu[3]; struct student
{ int num;
…
};
……
stu[3];
2、初始化:(与结构变量初始化相同,必须注意数量)
注意:(1)初始化数据的类型与结构体类型的一致性;
(2)如果对数组的全部元素初始化,可以省略元素个数;
(3)如果在初始化的过程中,某个元素的某个成员不赋值,分隔符逗号也不能省略。
3、使用:结构数组中某一元素中的某个成员的功能与普通变量相同,可以参加普通变量可以参加的仁和动作,但其表示形式与普通变量不同。其使用的一般形式为:
结构数组名[下标].成员项名
例:class[2].name 标识下标为2的学生的姓名。
(四)结构与指针
1、指向结构体变量的指针的定义(与指向变量的指针的定义相同)。
2、使用:
其形式为:结构变量名.成员项名
通过结构指针访问结构中的成员可使用以下2中形式:
(1)通过指针运算符“*”;
例:(*p) . num = 200700011;/*通过指针运算符访问结构中的成员num*/(2)通过指向运算符“->”。
例:p->num = 200700011;/*通过指向运算符访问结构中的成员num*/注:(1)由于指向运算符“->”非常形象直观,因此更常用;
(2)由于指针运算符“*”的优先级低于成员运算符“.”,因
此(*p).num中的*p必须带括号。
访问结构中的成员可以用以下3种方法:
(1)结构变量名.成员项名
(2)(*结构指针名).成员项名
(3)结构指针名->成员项名
3、指向结构数组的指针(与数组的指针的用法相同)
注:结构指针加1,其移动的字节书为整个结构类型所占的字节数,即结构中各个成员所占的字节数之和。
(五)结构体与函数
1、结构体变量作为函数参数
用结构体变量作为函数参数实参和形参时,形参与实参必须保持数据类型的一致性(值传递),两者一一对应赋值,且占有各自的存储空间。
2、指向结构体变量的指针作为函数参数
用结构体指针作为函数的实参和形参时,形参和实参必须具有相同的结构类型的指针(地址传递),即形参的结构指针指向实参结构
变量,通过共享的方式实现数据的传递,具体可以利用指向结构体的指针或结构数组实现。
返回就够的函数是指函数的返回值是结构类型的数据,如结构变量或结构指针。
(六)动态内存与链表
1、动态内存函数
当程序需要使用动态内存的分配和释放函数时,应包含头文件:
#include
或 #include
(1)malloc函数【原型为:void *malloc(unsigned int size)】
申请成功返回起始地址
申请不成功返回空地址NULL
说明:(1)函数的形参是无符号整型。
(2)函数的返回值是指针(指向void类型的指针),如果需
要利用此段空间存储其他类型的数据,必须将其强制转换为其他类型的指针。
例:(float *)malloc(4) /*申请4个字节的存储空间,并将其转换为浮点类型的指针*/ (2)calloc函数【void *calloc(unsigned int n,unsigned int size)】功能:向系统申请n个长度为size个字节的存储空间。
申请成功返回起始地址
申请不成功返回空地址NULL
说明:(1)calloc函数的的形参有2个;
(2)函数的返回值是指针(指向void类型的指针),如果需
要利用此段空间存储其他类型的数据,必须将其强制转换
为其他类型的指针。
(3)free函数【原型为:void free(void *p)】
功能:将指针变量p指向的存储空间归还系统,函数无返回值。
说明:(1)指针变量p指向的存储空间归还系统后,系统可将此空间分配给其他的变量;
(2)指针变量p指向的存储空间不能是任意的地址,只能是在程序的执行过程中利用malloc函数或calloc函数获得的返回地址。
2、链表
(1)概念:利用动态内存的分配和回收策略实现的最常用的一种动态数据结构,由若干个结点所组成,每个结点可以分布在内存的任意位置。
(2)链表的组成:
头指针:存放一个地址,该地址指向一个元素
结点:用户需要的实际数据和链接节点的指针
对于第一个结点的地址的存储有2种方式:
1)只有头指针、无头结点的链表。
2)有头结点的链表。
3、链表的基本操作
链表的优点:有利于结点的插入和删除,且具有组织灵活、对内存压力小、内存的利用率高。
缺点:不能随机的存取数据。
(1)遍历链表(为了输出链表中的每一个结点的数据)步骤如下:
○1首先从链表的头结点的后继结点开始(p=head->next)。
○2如果此结点存在(p!=NULL),则打印此结点的信息,接着结点指针后移(p->next),以指向下一个结点,转入步骤2.
○3如果此结点不存在(p=NULL),则结束循环,进而结束子函数。(2)查找链表(在链表中查找数据信息)步骤如下:
○1输入待查找的数据信息。
○2从链表的头结点的后继结点开始(p=head->next)。
○3如果此点的数据信息与待查找的数据信息不同,且此点存在后继结点,则结点指针后移(p=p->next)。
○4循环结束后,仍没有找到,则输出“not found”。
(3)插入链表(在有序链表中插入信息,并仍保持有序)步骤如下:○1输入待插入的数据信息。
○2从链表的头结点开始(p=head)。
○3如果此结点存在后继结点,且此结点的后继结点的数据信息小于待插入的数据信息,则结点指针后移(p=p->next),以指向下一结点继续查找。
○4循环结束后,结点p的数据信息小玉待插入的数据信息,而结点p->next的数据信息大雨待插入的数据信息,因此应将新结点q插在结点p和p->next之间。
○5生成新结点q,将结点p的原后继结点链在新结点q之后,而结点p的后继结点为新结点q。
(4)删除链表:其查找位置的操作过程与插入算法基本相同,如果需要删除结点p->next,只需将结点p的后继指针改为其后继的后继,删除后必须及时地释放被删除结点的空间。
(5)生成链表(首先生成空链,接着不断生成新的结点插入链中,直至链表生成)链表生成算法分为头插法和尾插法。
尾插法:
○1首先生成头结点,头结点的指针为空,即空链。
○2不断生成结点,并将其插在刚生成(即上一次循环生成的结点)的后继,直至输入结束标志为止。
○3循环结束后,将最后一个结点的指针域置为空(NULL)。
二、联合体(共同体)
概念:不同类型的数据联合存放在一段起始地址相同的、连续的存储空间中。
(一)联合体类型的定义
先定义联合体类型,再定义联合体变量,接着可以使用联合体变量中的某个成员(与结构体的定义和使用方法基本相同)。
一般形式: union 联合体类型名
{
联合体成员列表;
};
例: union data
{
char ch;
int n;
float x;
};
(二)联合体变量
1、定义(联合体变量的定义有3种形式)
(1)在定义联合体的同时定义联合体变量。
例:union data
{
char ch;
int n;
float x;
}a,b,c;
(2)在定义联合体类型之后,定义联合体变量。
例:union data
{
char ch;
int n;
float x;
};
union data a,b,c;
(3)利用无名联合体类型直接定义联合体变量。
例: union
{
char ch;
int n;
float x;
}a,b,c;
注:字符型数据占用从起始单元开始的1个字节;
整型数据占用从起始单元开始的2个字节;
浮点型数据占用从起始单元开始的4个字节。
它们相互之间有覆盖的情况,在某一时刻只保留最新的数据。
2、使用(与结构体基本相同)
一般形式为:联合体变量名.成员项名
或联合体指针->成员项名
注:(1)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对它初始化。
(2)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针
(3)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
三、枚举类型
1、枚举类型的定义(与结构体类型的数据的用法基本相同)
必须先定义枚举类型,在定义枚举类型的变量,接着可使用枚举类型的数据。
2、一般形式: enum 枚举类型名{枚举常量列表};
注:系统自动为他么赋值为:0,1,2,3,……,也可根据系统需要,改变系统默认值,其后的值则顺延。
例:enum day1{mon,tue,wed,thu,fri,sat,sun};
3、枚举变量的定义
(1)在定义枚举类型的同时,定义枚举变量。
例:enum color{red,yel,gre}x,y;
(2)在定义枚举类型之后,定义枚举变量。
例:enum color{red,yel,gre};
enum color x,y;
(3)直接定义枚举变量。
例:enum {red,yel,gre}x,y;
4、枚举变量的使用
注意:(1)枚举变量的值只能取举个枚举常量之一;
(2)枚举变量不能直接取一个整数值,如果需要将枚举常量对应的整数值赋给枚举变量,必须使用强制类型转换,将整数值转换为枚举类型;
例:x=(enum color)1;
(3)枚举数据可以比较,且是按照它们对应的整数值进行的;
(4)枚举变量可以进行++或- -的运算,常用作循环控制变量;
(5)枚举数据可以通过printf(“%d”,x);这种形式输出其对应的整数值,但不能通过printf(“%s”,red);。如果输出其字符串,可利用printf(“red”)。
四、用户定义类型(typedef)
经常用在以下场合:
(1)用typedef说明一个等价的数据类型。
例:typedef int integer;
integer x,y,z;
含义:将int数据类型定义为integer,因此integer的作用与int 相同,在程序中可以使用integer定义整型变量。
(2)定义一个信德类型名代替一个数据结构类型(联合和枚举也可以使用同样的方法)。
例:typedef struct
{
int month;
int day;
int year;
}DATE;
DATE birthday,*p;
含义:将结构体定义为新的类型名DATE,在程序中可以使用DATE 定义结构变量或结构指针。
(3)定义数组类型。
例:typedef char STRING[40];
STRING str1,str2;
含义:定义一个含有40个字符的字符数组名STRING,并用STRING 定义两个字符数组str1和str2。