
在C语言中,已经提供了一些基本的内置类型,如int、char、short等等。但有时,我们的一些数据不能只从是简单地归结于这些单一的数据类型。所以,我们就需要自定义类型。常见的自定义类型有三种:结构体、联合体、枚举。今天我们首先来介绍一下最重要的:结构体。
结构是一些值的集合,这些值被称为成员变量。结构的每个成员可以是不同类型的变量,如指针、字符、数组,甚至是又一个结构体。
结构体的声明为:
struct name
{
member;
member;
......
};其中,struct是C语言中的一个关键字,name是结构体变量的名字,里面的member是成员。
举个栗子,我想从名字、年龄、身高描述一个人,写成结构体类型就是:
struct human
{
char name[20];//名字
int age;//年龄
float length;//身高
};
//一定记得最后的分号不能丢
//一个话题外的小知识点:一个汉字相当于两个字符的大小除此之外,还有一种结构体的匿名声明,在声明结构体类型时不写出名字,这个类型的变量只能在声明后紧接着创建,结构体变量创建好后它的声明直接销毁,也就是只能用一次。在实际应用中,这种特殊的声明方式其实完全没必要使用,大家仅做了解就好~
创建好一个结构体类型后,我们就可以创建这种类型的结构体变量了,创建的方式有两种:
//方式一:在结构体类型的声明后直接创建,如a1
struct human
{
char name[20];
int age;
float length;
}a1;
//方式二:结构体声明后在下面的语句创建,如a2
struct human a2;创建后,当然也要存入数据了,结构体变量的初始化方法为:
struct human
{
char name[20];
int age;
float length;
}a1;
//默认情况下,数据是按照声明的结构体成员顺序初始化的:
a1 = {"zhangsan", 18, 180.0};
struct human a2 = {"lisi", 20, 178.0};
//也可以指定顺序初始化,要在成员名前加. :
struct human a3 = {.length=175.5, .name="wangwu", .age=30};结构体成员的直接访问是通过点操作符.完成的,如下:
struct human
{
char name[20];
int age;
float length;
}a1 = {"zhangsan", 18, 180.0};
printf("年龄是:%d\n", a1.age);
printf("身高是:%f\n", a1.length);
结构体类型也是一种类型,创建了一种结构体类型,自然也有指向这种结构体变量的指针类型了:
struct human
{
char name[20];
int age;
float length;
}a1;
struct human* p1 = &a1;有时候我们得到的不是一个结构体变量,而是一个指向结构体的指针,我们需要用这个指针找到结构体的成员,这就是结构体成员的间接访问,要用到->操作符:
struct human
{
char name[20];
int age;
float length;
}a1 = {"zhangsan", 18, 180.0};
struct human* p1 = &a1;
printf("年龄是:%d\n", p1->age);
printf("身高是:%f\n", p1->length);
结果也是对的
知道了结构体的基本使用方法,我们更深入一点,学习一下计算结构体的大小,这涉及到结构体内存对齐。
基本规则为:
我们来分析两个结构体就理解了(以下代码都在VS下运行):
例子1:
struct s1
{
char c;
int i;
double d;
};

例子2:
struct s2
{
char c1;
int i;
char c2;
}

原因了解一下就好:
换句话说,结构体的内存对齐,是用空间节省时间的做法。
所以,我们在设计结构体时,为了尽量节省空间,应该做到:让占用空间小的成员尽量集中在一起。比如:
struct s1
{
char c1;
int i;
char c2;
};
struct s2
{
char c1;
char c2;
int i;
}s2所占空间就比s1要小。
#pragma这个预处理指令,可以改变编译器的默认对齐数
用法是:#pragma pack(n),n是我们希望改成的默认对齐数;使用完这个我们修改的对齐数,写下#pragma pack(),就能取消设置的对齐数,还原为编译器默认的。
这样,在结构体内存对齐方式不合适的时候,我们可以自己设计对齐方式。

结构体类型也是可以作为函数参数传递的,但传的时候,我们有传值和传址两种选择。大多数情况下,都建议选择传递结构体的地址(指针)。 原因是:函数传参的时候,参数需要压栈,会有时间和空间上的系统开销。如果传递一个结构体时这个结构体过大,参数压栈的系统开销比较大,可能会导致性能的下降。
位段也是一种数据结构,今天做一个初步的了解就好,它的声明和使用和结构体极为相似。只有两点不同:
每个成员名后的数字代表着给这个成员变量申请的空间大小(单位是比特)。 比如:
struct s1
{
int i:10;
char c1:2;
char c2:4;
};但要知道的是:
本篇完,感谢阅读