结构体
结构体的声明
基础知识
结构是一些值的集合, 这些值成为成员变量。结构得每个成员可以是不同类型的变量。
结构的声明
struct tag//结构体标签
{
member-list; //成员列表
}variable-list;//变量
例如描述一个学生:
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];// 性别
char id[20];// 学号
};//分号不能丢
特殊的声明:
在声明结构体的时候,可以不完全的声明。
比如:
// 匿名结构体类型
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
上面的两个结构在声明的时候省略掉了结构体标签。
那么
//在上面代码的基础上,下面的代码合法吗?
p = &x;
警告
编译器会把上面的两个声明当成完全不同的类型。所以是非法的。
结构的成员
结构体成员的访问
- 结构体变量访问成员是通过点操作符(.)访问的
例如:
如何访问s的成员?
struct S s;
strcpy(s.name, "zhangsan");//使用.访问name成员
s.age = 20;//
- 结构体访问指向变量的成员 有时候我们得到的不是一个结构体变量,而是一个指向结构体的指针。那么该如何访问成员,如下:
struct S
{
char name[20];
int age;
}s;
void print(struct S* ps)
{
printf("name = %s age = %d\n", (*ps).name, (*ps).age);
printf("name = %s age = %d\n", ps->name, ps->age);
}
结构体变量的定义和初始化
如何定义变量?
struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1;
struct Point p2;//先声明结构体类型,再定义结构体变量p2;
//初始化:定义变量同时赋初值。
struct Point p3 = {x, y};
struct Stu
{
char name[15];
int age;
};
struct Stu s = {"zhangsan", 20};//初始化
struct Node
{
int data;
struct Point p;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};// 嵌套初始化
结构体内存对齐
结构体传参
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); // 传结构体
print2(&s); // 传地址
return 0;
}
首选print2函数
原因:
函数传参的时候,参数是需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。
结论
结构体传参的时候要传结构体地址。
位段
位段的声明和结构体是类似的,有两个不同:
1.位段的成员必须是 int 、unsigned int 或 signed int
2.位段的成员名后面有一个冒号和数字:
例如:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};//A就是一个位段类型
位段的内存分配
- 位段的成员可以是 int unsigned int signed int 或者是 char类型。
- 位段的空间上是按照需要以四个字节(int)或一个字节(char)的方式来开辟的。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
位段的跨平台问题
枚举
枚举类型的定义
enum Day// 星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
enum Color//颜色
{
RED,
GREEN,
BLUE
};
以上都是枚举类型
{}中的内容是枚举类型的可能取值,也叫枚举常量。这些常量都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。
例如:
enum Color
{
RED=1,
GREEN=2,
BLUE=4
};
枚举的优点
- 增加代码的可读性和可维护性。
- 和#define定义的标识符相比枚举有类型检查,更加严谨。
- 防止了命名污染。
- 便于调试。
- 使用方便,一次可以定义多个常量。
联合
定义:
这种类型定义的变量也包含一系列成员,特征是这些成员共用同一块空间。
比如:
//联合类型的声明
union Un
{
char c;
int i;
};
//联合变量的定义
union Un un;
联合大小的计算
- 联合的大小至少是最大成员的大小。
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍处。