1、概念:
可以将不同种类的数据组装起来,形成一个完整的类型;
比如:
一个学生,典型地应该拥有学号(整型)、姓名(字符串)、分数(浮点型)、性别(枚举)等不同层面的属性,这些所有的属性都不应该被拆分开来,而是应该组成一个整体,代表一个完整的学生。
- 结构体的定义:
struct 结构体标签
{
成员1;
成员2;
成员3;
...
};
- 语法:
- ①、结构体标签,用来区分各个不同的结构体。
- ②、成员,是包含在结构体内部的数据,可以是任意的数据类型。
示例:
struct student
{
int a;
char b;
double c;
};
int main(void)
{
struct student n; //定义结构体变量
}
2、结构体的初始化:
- 由于结构体内部拥有多个不同类型的成员,因此初始化采用与数组类似的列表方式;
- 结构体的初始化有两种方式:1普通初始化; 2指定成员初始化;3赋值初始化。
- 为了能适应结构体类型的升级迭代,一般建议采用指定成员初始化。
示例:
1、普通初始化
struct student n={1,'a',3.14};
2、指定成员初始化
struct student n={
.a=1,
.b='b',
.c=3.14};
3、成员的引用赋值
struct student n;
n.a=1;
n.b='a';
n.c=3.14;
printf("%d %c %f\n",n.a,n.b,n.c);
3、结构体指针与数组:
- 跟普通指针无二意,可以定义指向结构体的指针,也可以定义结构体数组;
struct node n = {100, 'x', 3.14};
struct node *p = &n;
// 以下语句都是等价的
printf("%d\n", n.a);
printf("%d\n", (*p).a);
printf("%d\n", p->a); // 箭头 -> 是结构体指针的成员引用符
- 结构体数组:
struct node n[5];
n[0].a = 300;
n[0].b = 'z';
n[0].c = 3.14;
4、结构体别名:
//结构体别名
typedef struct student
{
char *name;
unsigned long number;
char sex;
int age;
}student, *pstu; //student是struct student的别名。 pstu是struct student *的别名
5、CPU字长与地址对齐:
字长的概念指的是处理器在一条指令中的数据处理能力,当然这个能力还需要搭配操作系统的设定,比如常见的32位系统、64位系统,指的是在此系统环境下,处理器一次存储处理的数据可以达32位或64位。
32位4字节
64位8字节
CPU字长确定之后,相当于明确了系统每次存取内存数据时的边界,以32位系统为例,32位意味着CPU每次存取都以4字节为边界,因此每4字节可以认为是CPU存取内存数据的一个单元。
如果存取的数据刚好落在所需单元数之内,那么我们就说这个数据的地址是对齐的,如果存取的数据跨越了边界,使用了超过所需单元的字节,那么我们就说这个数据的地址是未对齐的。
未对起的情况:
对起的情况:
6、求结构体的m值:
普通变量的m值:
char c; // 由于c占1个字节,因此c不管放哪里地址都是对齐的,因此m=1
short s; // 由于s占2个字节,因此s地址只要是偶数就是对齐的,因此m=2
int i; // 由于i占4个字节,因此只要i地址满足4的倍数就是对齐的,因此m=4
double f; // 由于f占8个字节,因此只要f地址满足4的倍数就是对齐的,因此m=4
结构体的M值:
取 决于结构体中占最大内存的成员为
struct node
{
short a; // 尺寸=2,m值=2
double b; // 尺寸=8,m值=4
char c; // 尺寸=1,m值=1
};
struct node n; // M值 = max{2, 4, 1} = 4;
7、结构体的内存大小:
struct student
{
char name[20];
int age;
char sex;
};
该结构体的内存为28
首先在64位系统中,一个地址以8个字节为一个地址,这个结构体中的m值为20,8个为一行,name与age正好占完3行24个,剩下一个char型独自占新的一行地址,所以该结构体整个内存为28
在32为系统中是28
32位系统中地址为4字节为一个地址