目录
结构体声明
结构体是用来存放复杂对象的,使用结构体要对其声明。
//声明一个结构体类型
struct Book
{
char name[20];
char author[20];
int price;
};
struct Book
{
char name[20];
char author[20];
int price;
}b1, b2;//b1、b2全局的结构体变量
struct Book b3;//全局
int main()
{
struct Book b4;//局部变量
return 0;
}
结构体也可以进行不完全声明
struct
{
int a;
char b;
float c;
}x;
结构体自引用
结构体自引用要用到指针
struct Node
{
int data;//数据域
struct Node* next;//指针域
};
//利用typedef重定义
typedef struct Node
{
int data;
struct Node* next;
}Node;
结构体变量的定义和初始化
struct Point
{
int x;
int y;
}p3 = { 5,6 }, p4 = {7,8};
struct Point p2 = {1,2};
//结构体包含结构体和数组
struct S
{
double d;
struct Point p;
char name[20];
int data[20];
};
int main()
{
struct Point p1 = {3,4}; //定义结构体变量,并且初始化
struct S s = { 3.14, {1,5} , "zhangsan", {1,2,3} };
printf("%lf\n", s.d);
printf("%d %d\n", s.p.x, s.p.y);
printf("%s\n", s.name);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", s.data[i]);
}
return 0;
}
结构体内存对齐
规则:
1.结构体的第一个成员永远放在结构体起始位置偏移量为0的位置
2.结构体成员从第二个成员开始,总是放在偏移量为一个对齐数的整数倍出。
对齐数=编译器默认的对齐数额变量自身大小的较小值
linux-没有默认对齐数 VS的对齐数的8
3.结构体的总大小必须是各个成员的对齐数中最大那个对齐数的整数倍
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
//12
struct S1
{
char c1;//1
int a;//4
char c2;//1
};
//8
struct S2
{
char c1;//1
char c2;//1
int a;//4
};
struct S3
{
double d;
char c;
int i;
};
struct S4
{
char c1;
struct S3 s3;
double d;
};
int main()
{
//struct S1 s = {'x', 100, 'y'};
//printf("%d\n", sizeof(struct S1));
//printf("%d\n", sizeof(struct S2));
printf("%d\n", sizeof(struct S4));
//printf("%d\n", sizeof(s));
return 0;
}
我们可以修改默认对齐数
//#pragma pack(1) --改变默认对齐数
struct S1
{
char c1;//1 1 1
int i; //4 1 1
char c2;//1 1 1
};
//#pragma pack()--恢复默认对齐数
笔试题:写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
#include <stddef.h>
struct S1
{
char c1;
int i;
char c2;
};
//offsetof 是一个宏--求偏移量
int main()
{
printf("%u\n", offsetof(struct S1, c1));
printf("%u\n", offsetof(struct S1, i));
printf("%u\n", offsetof(struct S1, c2));
return 0;
}
结构体传参
传参方式一种是传值,另一种是传址。
分别对应下面的print1和print2
struct S
{
int data[1000];
int num;
};
void print1(struct S tmp)
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", tmp.data[i]);
}
printf("\nnum = %d\n", tmp.num);
}
void print2(const struct S* ps)
{
//->
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", ps->data[i]);
}
printf("\nnum = %d\n", ps->num);
}
int main()
{
struct S s = { {1,2,3,4,5,6,7,8,9,10}, 100 };
//print1(s);
print2(&s);
return 0;
}
结构体实现位段
位段的声明和结构是类似的,有两个不同
1.位段的成员必须是 int、unsigned int 或signed int 。
2.位段的成员名后边有一个冒号和一个数字
struct A
{
int _a : 2;//_a 2个bit位
int _b : 5;//_b 5个bit位
int _c : 10;//
int _d : 30;//
};
//47bit -6byte
// -8byte
int main()
{
printf("%d\n", sizeof(struct A));
return 0;
}
枚举
枚举顾名思义一一列举
枚举定义
enum Color //里面放的是常量
{
RED, //赋初值就不是0了从2开始
GREEN,
BLUE
};
int main()
{
printf("%d\n", RED); //0
printf("%d\n", GREEN);//1
printf("%d\n", BLUE); //2
//RED = 6;//错误没法修改,因为是常量
/*enum Color c = GREEN;
if (c == GREEN)
{
printf("绿色\n");
}*/
return 0;
}
默认枚举里面的是从0开始,当你给它赋值的时候就不是从0开始了。
枚举的使用,这个只讲枚举的应用,具体功能不讲。
enum Option
{
EXIT,//0
ADD,//1
SUB,//2
MUL,//3
DIV//4
};
void menu()
{
printf("******************************\n");
printf("**** 1. add 2. sub ****\n");
printf("**** 3. mul 4. div ****\n");
printf("**** 0. exit ****\n");
printf("******************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
//加法
break;
case SUB:
break;
case MUL:
break;
case DIV:
break;
case EXIT:
break;
}
} while ();
return 0;
}
联合体
联合体:里面的成员共用同一块空间。
union Un
{
char c;//1
int i;//4
};
int main()
{
union Un u = {0};
//printf("%d\n", sizeof(u));//4个字节
printf("%p\n", &u);
printf("%p\n", &(u.c));
printf("%p\n", &(u.i));
return 0;
}
计算共用体的大小:
1.联合的大小至少是最大成员的大小。
2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un1
{
char c[5];//5 1
int i;//4 4
};
union Un2
{
short c[7];//14 2
int i;//4 8 4
};
int main()
{
printf("%d\n", sizeof(union Un1));//8
printf("%d\n", sizeof(union Un2));//16
return 0;
}