结构体
什么是结构体?
结构体是不同类型元素的集合体。
为什么要有结构体?
因为一个对象有很多个属性这些属性是相互联系的,例如一个学生有年龄(age),地址(adder),学号(num),姓名(name)等属性,所以数组是存储不了的(数组是同一类型元素的集合体),但是如果分开存放又难以反映出它们之间的关系,因此才有了结构体。
结构体如何使用?
结构体的声明:
struct Student
{
char name[20];
short age;
char num[20];
float socer;
};//分号不能丢
此时我们声明了一个结构体,但它仅仅是一个类型,和C语言中的int char等是一样的,系统并没有为它开辟空间,只有在定义变量后,才会开辟空间。
特殊的结构体声明:
匿名结构体类型:
struct
{
int a;
float b;
double c;
}x;
struct
{
int a;
float b;
double c;
}*p;
p = &x;//非法
注: 上面的两个结构体都没有名字,这样的结构体叫做匿名结构体,匿名结构体只能在声明的时候定义结构体变量。虽然上面两个结构体都是匿名结构体而且成员列表都一样,但它们仍属于两个不同的类型,所以最后一个语句是错误的。
结构体变量的定义及初始化
struct point
{
int x;
int y;
} p1 = {2,2};//声明类型的同时定义变量p1
struct point p2 = { 1, 3 };//定义结构体变量p2并进行初始化;
-------------------------------------------------------------
struct Node
{
int data;
int arr[3];
struct point p1;
struct Node* next;
};
struct Node n1 = { 3, { 1, 2, 3 }, { 1, 2 }, NULL };
总的来说,结构体的初始化和数组是一样的。
只能整体初始化,不能整体赋值
当结构体内嵌套结构体时,采用大括号套大括号的方式进行初始化。
结构体的自引用:
如果一个结构体的成员变量中包含自身,就叫做结构体的自引用
struct Node
{
int data;
struct Node next;
};
这种自引用方式显然是错误的,因为Node中有一个next,而next中还有下一个next,下一个next中含有下一个next…(子子孙孙无穷尽焉)。
如图:
正确的自引用方式:
struct Node
{
int data;
struct Node* next;
};
这正如数据结构中链表的节点一样!
结构体成员的访问方式:
struct A
{
int b;
char c;
};
int main()
{
struct A a = { 1, 'h' };
struct A* pa = &a;
printf("%d %c\n", a.b, pa->c);
system("pause");
return 0;
}
可见结构体成员的访问总共有两种方式:
1.结构体变量名.成员名
2.结构体指针->成员名
结构体传参
函数在调用的时候要生成栈帧结构,参数要入栈,因此要开辟空间,而且结构体传参的时候不像数组会发生降级,因此如果结构体自身所占空间过大,势必在硬拷贝的情况下导致性能的下降。
结论:结构体传参的时候,传结构体指针。
枚举
enum关键字,专门用来定义枚举类型,这也是它在C语言中的唯一用途。
enum week
{
Mon = 1,
Tues,
Wed,
Thurs,
Fri,
Sat,
Sun
};
像结构体一样,此时仅仅声明了一个枚举类型,并没有定义枚举变量。枚举中的成员统称为枚举常量,和普通常量一样,枚举常量也只能作为右值,不能作为左值。
enum num
{
a,
b = 0,
c,
d = 4,
e
};
int main()
{
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", c);
printf("%d\n", d);
printf("%d\n", e);
system("pause");
return 0;
}
可以看出枚举常量的值默认从0开始,后面的数比前一个数多1.
枚举的优点(相较于宏)
1.增加代码的可读性,可维护性。
2.枚举有类型,更加严谨。
3.防止命名污染。
4.便于调试。
5.使用方便,一次可以定义多个枚举常量。
联合体(共用体)
用union关键字来声明联合体,联合也是一种自定义类型,像结构体一样也包括很多成员变量,但这些成员变量共用一块内存空间 。因此联合体也叫共用体 。
因为联合体是用用一块内存空间的,因此一个联合体的大小,至少是其内部最大成员变量的大小(最大指的是所占内存最大)。
联合体的大小
union Un
{
char arr[10];
int b;
};
int main()
{
printf("%d\n", sizeof(union Un));
system("pause");
return 0;
}
输出:12.这里应该是10,但结果是12 是因为内存对齐的缘故。
union Un
{
char i;
int b;
};
int main()
{
union Un un;
printf("%p\n", &(un.i));
printf("%p\n", &(un.b));
system("pause");
return 0;
}
输出:
在这里操作系统给联合体分配四个字节,验证得出i存储在四个字节中地址最低的字节中。利用这个特点,我们可以利用联合体来验证计算机的大小端存储模式,代码如下:
union Un
{
char i;
int b;
};
int main()
{
union Un un;
un.b = 1;
if (un.i == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
system("pause");
return 0;
}
tip:在定义声明类型的时候,我们可以用typedef对其进行类型重命名从而进行简化!