【C语言程序设计】用户自己建立数据类型
根据实际情况,我们往往需要建立
结构体类型、共用体类型、枚举类型、链表
01
结构体
C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,称为结构体
1.结构体的声明
struct 结构体名称
{
结构体成员 1;
结构体成员 2;
结构体成员 3;
···
};
2.结构体的定义
(1) 在结构体声明的最后,在;前面直接定义。
(2) struct 结构体名称 结构体变量名
3.结构体的初始化(结构体的成员类型要对号入座)
(1) 按照顺序依次初始化结构体。
结构体变量名
{
数据1,
数据2,
···
};
(2) 指定部分成员初始化。
结构体变量名
{
结构体变量名.结构体成员=数据2;
结构体变量名.结构体成员=数据3;
结构体变量名.结构体成员=数据5;
···
}
4.访问结构体变量
要访问结构体成员需要引入新的运算符号“.”。eg:book.title代表的就是访问book结构体中的title这个成员。
5.结构体的嵌套。
我们在定义结构体的时候,是可以嵌套进别的结构体的(不可以自己嵌套自己)。
不同结构体内相同命名,访问结构体内的结构体内成员。
6.结构体数组(数组)
(1)在结构体声明的最后,在;前面直接定义 结构体变量名[]。
(2)struct 结构体名称 结构体变量名[]。
7.结构体指针(指针)
Struct M_mys *p=& mystruct;
通过指针对数据进行访问。
(*p).a———访问结构体mystruct中的数据aa
p->a ———访问结构体mystruct中的数据aa
02
共用体结构
1.共用体的声明和定义
共用体是一种和结构体非常类似的语法,
其定义格式是
union 共用体名{
Int a;
Float b;
Char c;
成员列表
}aa;
2.共用体内存
占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
ps:对公用体初始化,初始化表中只能有一个常量。不能通过公用体变量名进行赋值,且不能将共用体变量作为函数参数(以前不可以,C99可以)。但可以将指向共用体变量的指针作为函数参数。
3.结构体和共用体
结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
内存对齐原则
1.找到内存最大的基本数据类型,将其内存作为对齐数(可以理解为存储单位,如2字节,4字节,8字节)
2.内存最大的基本数据类型前的存储空间使用对齐数作为基本单位进行内存对齐,后面的存储空间也进行内存对齐
3.所有的存储空间进行相加
4.如果结构体内部嵌套共用体或者其他结构体,按照其内部基本数据类型进行对齐数寻找。
实例:
union MyUnion
{
float a;
int b;
char c[6];
}aa;
printf("aa的字节是:%d", sizeof(aa));
struct MyStruct
{
union MyUnion aa;
float k[5];
double p;
}bb;
printf("bb的字节是:%d", sizeof(bb));
解析:对于MyUnion,float占4个字节,int占4个字节,char占1个字节。所以以4个字节作为存储单位。因此,a占4个字节,b占4个字节,c 占8个字节。根据共用体占用的内存等于最长的成员占用的内存,所以aa的内存占8个字节。
对于MyStruct,MyUnion占8个字节,float占4个字节,double占8个字节。所以以8个字节作为存储单位,因此,aa占8个字节,k[5]占24个字节,p占8个字节。根据结构体占用的内存等于内部成员占用的内存之和,所以bb的内存占8+24+8=40个字节。
03
枚举类型
如果一个变量只有几个可能的值,则可以定义为枚举类型。
1.枚举类型声明
enum [枚举名]{枚举元素列表}
eg:
enum Weekday{sun,mon,tue,wed,thu,fri,sat};
2.枚举类型定义
枚举类型 枚举变量
eg:enum workday,weekend;
3.初始化
枚举变量=枚举元素
eg:workday=mon;
weekend=fri;
04
链表
链表是一种常见的重要的的数据结构。它可以动态地进行存储分配的一种结构。
1.头指针(head)
2结点
a.删除链表中的某个结点
代码:
void delet(LinkList *list, int n) {
LinkList *p = list, *q;
int i = 0;
while (i < n && t != NULL) {
q = p;
p = p->next;
i++;}
if (t != NULL)
{q->next = p->next;
free(p);}
else {puts("节点不存在");}
}
b.在链表中添加某个结点
void insert(LinkList *list, int n) {
LinkList *p = list, *q;
int i = 0;
while (i < n && p != NULL) {
p= p->next;
i++;
}
if (p != NULL) {
q = (LinkList*)malloc(sizeof(LinkList));
puts("输入要插入的值");
scanf("%d", &q->score);
q->next = p->next;//填充q节点的指针域,也就是说把q的指针域指向p的下一个节点
p->next = q;//填充t节点的指针域,把t的指针域重新指向q
}
else {
puts("节点不存在");
}
}