为什么要创建结构体类型?在我们处理复杂对象的时候,比如描述一个人的时候,它有名字,性别,身高,体重等一些方面的特征。用结构体打包描述的时候就比较方便。
结构体类型的关键字struct。
声明的基本模板为:
struct 标签 { 成员; }变量; 结构体的成员可以是不同的类型。
结构体类型的特殊声明: 匿名结构体类型,它只能使用一次。
cstruct
{
int a;
char b;
}x;
struct
{
int a;
char b;
}*p;
p=&x这样写是错误的,在编译器看来,它们俩是不同的类型。

看下面这两种:
cstruct
{
int a;
int b;
}x;
这里的x是一个结构体类型的全局变量
typedef struct
{
int a;
int b;
}x;
这里的x是结构体类型。
typedef struct stu
{
int a;
int b;
}*put,stu;
这里的put等价于struct stu*类型
stu等价于struct stu类型例如:
ctypedef struct node
{
int x;
struct node* p;
}node;
这个自引用就是正确的。
typedef struct node
{
int x;
node* p;
}node;
这种就是错误的,这个问题的出现就和先有鸡还是先有蛋的问题一样。
不能知道是先重命名了还是先创建的。cstruct student
{
char name[20];
int age;
}a,b;
//这种是一边声明,一边定义变量的,这里的变量a,b为全局变量
struct student c;
//这种定义的变量是全局变量
int main()
{
struct student d;
//这里的d为局部变量
return 0;
}cstruct student
{
char name[20];
int age;
}a={"zhangshan",20}, b={"wuanwu",18};
struct student c={"hh",0};
int main()
{
struct student d={"sb",88};
return 0;
}如何计算结构体的大小,就需要知道它在内存中是如何储存的。 而结构体在内存中存在结构体对齐的现象。
1.第一个成员变量放在偏移量为0的位置 2.后面的成员放在偏移量为对齐数的整数倍的位置。 3.对齐数:编译器默认的一个对齐数与成员大小的较小值 vs的默认对齐数位8 4.结构体的总大小为每个成员默认最大对齐数的整数倍。 5.如果含有结构体嵌套的情况,镶嵌的那个结构体的对齐数是里面成员的最大对齐数。
c struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));
struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));
struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));



按上面的分析:可知结构体的大小分别为:12,8,16,32 运行看一下情况:

我们用
pragma修改默认对齐数
例子:
c#pragma pack(4)
//这里面的数字表示的是默认对齐数
struct p
{
int a;
int b;
char c;
};
#pragma pack()在结构体传参的时候,最好选择传址调用,有两个好处 1.可以减少对空间的浪费 2.可以对里面的数据进行修改
简单的例子:
c#include <stdio.h>
struct student
{
char name[20];
int age;
};
void f(struct student* p)
{
}
int main()
{
struct student p;
f(&p);
return 0;
}位段的实现和结构体类似,只不过位段的成员的类型只能是
unsigned int或者int类型,char类型的也可以。 每个成员名后面要加上:和数字
举个简单的例子:
cstruct stu
{
int a : 4;
int b : 2;
};后面的数字表示bite位。位段不存在对齐。 位段不具有跨平台性: 1.位段中没有规定在内存使用的过程中,是从左使用还是从右使用。 2.不能满足下一个成员使用的空间是舍弃还是保留的问题没有规定。 3.
int位段中无符号还是有符号的问题没有规定
cstruct S
{
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
struct S s = { 0 };
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
枚举类型的关键字为
enum,枚举就是把所有的可能列举出来。 里面的叫做枚举常量。它们也是有值的,如果没有给他们初始化。默认第一个是0,后面的依次增加。
例子:
cenum colour
{
//注意后面是逗号,
red,//值是0
yellow,//值是1
green//值是2
};cenum colour
{
red=2,//这种不是赋值,而是给这个常量一个初始值。
yellow=5,
green//它的值为6
};关键字
union。 里面的成员都是占用同一块空间。
例子:
cunion people
{
char a;
int b;
};联合体可能是最大类型所占空间的大小。 当结构体的大小不是最大对齐数的整数倍时,需要对齐。
例子:
cunion Un1
{
char c[5];
//开辟了5个字节的空间
int i;
//i占4个大小的空间,开辟的空间够用
//共5个字节的空间,但是不是4的整数倍,存在内存对齐,
//最终为8个字节的大小
};
union Un2
{
short c[7];
int i;
//开辟的14个字节的空间也不是4的整数倍,需要对齐。
//最终的大小为16个字节
};
int main()
{
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}看结果:
