一、结构体
1、结构体的声明
1、结构的基础知识。
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型,描述复杂对象,是我们自己创造出来的一种类型。.
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
比如描述学生,学生包含:名字+年龄+性别+学号这几项信息。比如书名+作者+出版社+定价+书号等。这里只能使用结构体来描述。
2、结构的声明
1)定义结构体类型。例如,描述一个学生,需要一些数据,名字、年龄、性别、电话
struct - 结构体关键字,
Stu - 结构体标签,
struct Stu - 结构体类型,
里面的内容是成员变量,
结尾分号不可缺少
struct Stu
{
//成员变量
charname[20];
shortage;
charsex[5];
chartele[12];
}s1,s2, s3;//s1,s2,s3是三个全局的结构体变量。创建类型之后直接创建三个变量。
2)typedef作用是类型重命名,名字重命名成Stu
typedef struct Stu
{
//成员变量
char name[20];
short age;
char sex[5];
char tele[12];
}Stu;//名字简化成Stu,Stu是类型,可以直接用Stu创建变量
3、类型是用来创建变量的。
1)创建结构体变量
struct Stu s1;//struct Stu - 结构体类型,类型是用来创建变量的。局部结构体变量
Stu s2;//类型重命名成Stu,直接用Stu创建变量
2)初始化:定义变量的同时赋初值。
Stu s = { "张三",18,"男","133666999" };//初始化:定义变量的同时赋初值。
Stu w = { "田七",17,"女","138123564" };//初始化:定义变量的同时赋初值。
4、结构成员的类型。
结构的成员可以是标量、数组、指针,甚至是其他结构体。
1)结构体变量的定义
struct S
{
int a;
char c;
char arr[20];
double d;
};
struct T
{
char ch[10];
struct S s;
char* pc;
};
2)结构体变量的初始化
结构的成员可以是标量、数组、指针,甚至是其他结构体。
char arr[] = "hello world";
struct T t = {"hi",{100,'w',"hello",3.14},arr };//结构体嵌套初始化
printf("%s\n", t.ch);//hi
printf("%s\n", t.s.arr);//hello
printf("%lf\n", t.s.d);//3.14
printf("%s\n",t.pc);//hello world
2、结构体成员的访问
1、结构体变量访问成员。结构变量的成员是通过点操作符·访问的,结构体.成员名
2、结构体指针访问指向变量的成员,操作符:->,结构体指针->成员名
例:
typedef作用是类型重命名,名字重命名成Stu
typedef struct Stu
{
//成员变量
char name[20];
short age;
char sex[5];
char tele[12];
}Stu;//名字简化成Stu,Stu是类型,可以直接用Stu创建变量
void Print1(Stu temp)
{
//结构体变量访问成员,结构变量的成员是通过点操作符(.)访问的。
printf("name: %s\n", temp.name);
printf("age: %d\n", temp.age);
printf("sex: %s\n", temp.sex);
printf("tele: %s\n", temp.tele);
}
void Print2(Stu* ps)
{
//结构体成员访问,还有操作符:->,是针对结构体指针的
printf("name: %s\n", ps->name);
printf("age: %d\n", ps->age);
printf("sex: %s\n", ps->sex);
printf("tele: %s\n", ps->tele);
}
Stu s = { "张三",18,"男","666666" };
//为了打印结构体数据,封装了两个函数,传参可以传s和取地址s(&s)
Print1(s);
Print2(&s);
3、Print1和Print2函数哪个更好?
如果采用Print1函数,实参传给形参,形参实例化之后其实相当于实参的一份临时拷贝。所以,需要拷贝一份一模一样的数据,放在其他内存位置上。会造成空间浪费,时间上效率也低。
如果采用Print2函数,传过去的参数是地址,地址大小是4个字节或者8个字节。所以,无论结构体有多大,Print2函数只需要创建4个字节或者8个字节的结构体指针变量。也可以通过结构体地址改变成员内容。
结论:结构体传参的时候,要传结构体的地址。
4、注意:
函数传参的时候,参数是需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
二、位段
1、位段的声明和结构是类似的
但有两个不同:
1)位段的成员必须是int、unsigned int或signedint。也可以是short、char
2)位段的成员名后边有一个冒号和一个数字。
位段后的数字不能大于32
2、位段的内存分配
1)位段的成员可以是int、unsigned int、signedint或者是char(属于整形家族)类型
2)位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。
3)位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
4)位段是用来节省空间的,开辟的空间由低位向高位使用
例:
#include <stdio.h>
//位段 - 二进制位
struct S
{
int a : 2;//只需要2个bit位,可以表示4种状态
int b : 5;//5个bit位
int c : 10;//10个bit位
int d : 30;//30个bit位
};
int main()
{
//47个bit位 - 大小应该6个字节
//但是位段的空间是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的,所以需要8个字节
struct S s;
printf("%d\n", sizeof(s));//8个字节
return 0;
}
注意:4个字节 = 32个bit位
三、联合(共用体)
联合 - 联合体 - 共用体
联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
1、联合的特点
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小,因为联合至少得有能力保存最大的那个成员。
在同一时刻,联合体的成员是不能同时使用的
例:
#include <stdio.h>
union Un
{
char c;
int i;
};
int main()
{
union Un u;
printf("%d\n", sizeof(u));//4个字节
//地址是相同的,共用同一块空间
printf("%p\n", &u);
printf("%p\n", &(u.c));
printf("%p\n", &(u.i));
return 0;
}
2、联合大小的计算
联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
VS中默认对齐数的值为8
例:
#include <stdio.h>
union Un
{
int a; //大小为4,VS默认对齐数为8,对齐数为4
char arr[5]; //数组的对齐数计算,数组的元素是什么类型,拿数组元素类型计算对齐数。char大小是1,默认是8,→1。
};
int main()
{
union Un u;
printf("%d\n", sizeof(u));//8个字节
return 0;
}
四、枚举
1、枚举顾名思义就是一一列举,把可能的取值一一列举。
比如我们现实生活中:
一周的星期一到星期日是有限的7天,可以一一列举。性别有:男、女、保密,也可以一一列举。月份有12个月,也可以一一列举。这里就可以使用枚举了。
2、enumSex,enum Color都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫枚举常量 。这些可能取值都是有值的,默认从0开始,一次递增1,在定义的时候也可以赋初值。
3、我们可以使用#define定义常量,为什么非要使用枚举?
枚举的优点
1)增加代码的可读性和可维护性
2)和#define定义的标识符比较枚举有类型检查,更加严谨。
3)防止了命名污染(封装)
4)便于调试
5)使用方便,一次可以定义多个常量
例:
//枚举类型
enum Sex
{
//枚举的可能取值 - 常量
//常量可以赋初值
MALE = 2,
FEMALE,
SECRET
};
enum Color
{
RED, //0
GREEN,//1
BLUE //2
};
int main()
{
//C语言的源代码-->预编译-->编译-->链接-->可执行程序
enum Sex s = MALE;
enum Color c = BLUE;
printf("%d\n", sizeof(s));//MALE是一个整数,s的大小与整型的大小相同。4个字节
printf("%d %d %d\n", RED, GREEN, BLUE);
printf("%d %d %d\n", MALE, FEMALE, SECRET);
return 0;
}