1. C语言为什么会有结构体?(设计结构体时一定要考虑完善)
这是为了描述复杂的个体,只用内置类型不能完整的描述。(例如:学校统计成绩,有姓名学号性别年龄成绩等只用内置类型是不能描述清楚的) // 在结构体定义好之后,它就和内置类型没有任何区分
2. 如何定义结构体?(一个结构体就相当于一个作用域)
struct + 结构体名
{
成员列表
}; //此处的 ; 一定不能忘记
#include<stdio.h>
struct Student
{
char name[20]; //名字
int age; //年龄
char sex; //性别 1男 0女
int id; //学号
int chinese_score; //语文成绩
int math_score; //数学成绩
int english_score; //英语成绩
int score; //总成绩
};
3. 如何去使用结构体?
3.1 结构体普通变量怎么去访问其成员?
C语言规定,结构体的普通成员可以用 ' . ' 来访问
结构体普通变量怎么更改内部信息(代码如下:)
#include <stdio.h>
struct Student
{
char name[20];//名字
int id;//学号
char sex;//性别 1男 0女
int age;//年龄
int score;//总成绩
};
int main()
{
Student stu1 = { "caocao", 12345, 1, 30, 88 };
printf("%s ", stu1.name);
printf("%d ", stu1.id);
printf("%d ", stu1.sex);
printf("%d ", stu1.age);
printf("%d\n", stu1.score);
stu1.id = 54321;
//stu1.name = "caopi"; //结构体成员如果是字符串,不能直接通过赋值号'='去修改
strcpy_s(stu1.name, "caopi");
printf("%s ", stu1.name);
printf("%d ", stu1.id);
printf("%d ", stu1.sex);
printf("%d ", stu1.age);
printf("%d\n", stu1.score);
return 0;
}
调试结果如下:
3.2 结构体指针变量怎么去访问其成员?
可以通过箭头的方式去访问(*p).name == p->name arr[i] == *(arr+i)
结构体指针变量怎么更改内部信息(代码如下:)
#include<stdio.h>
struct Student
{
char name[20];//名字
int id;//学号
char sex;//性别 1男 0女
int age;//年龄
int score;//总成绩
}
int main()
{
Student stu1 = {"caocao", 12345, 1, 30, 88};
struct Student *p = &stu1;
(*p).id = 76543;
strcpy_s((*p).name,"sunjian");
p->sex = 0;
printf("%s ", p->name);//printf("%s ", (*p).name);
printf("%d ", p->id);//printf("%d ", (*p).id);
printf("%d ", p->sex);//printf("%d ", (*p).sex);
printf("%d ", p->age);//printf("%d ", (*p).age);
printf("%d\n", p->score);//printf("%d\n", (*p).score);
}
调试结果如下:
4. 结构体对齐(糅合第五点,默认的对齐大小)
(1)结构体变量的首地址 一定是这个结构体变量中最大的基础类型的大小的整数倍
(2)结构体变量中每一个成员 相当于结构体首地址的偏移 一定是该成员的基础数据类型大小的整数倍
(3)结构体变量的大小 一定是这个结构体变量中 最大的基础类型的大小的整数倍
运行出来的结果是12,现在我们来分析以下这个结果:
这里就要使用上面的规则一:char类型的变量占的格子是1,所以首地址占的格子是1,
规则二:再看第二个是int类型,所以应该占四个格子,但是这里是需要偏移的,第二条规格说了结构体变量中每一个成员应该是该成员的基础数据类型大小的整数倍,所以现在应该要补充3个格子让前边的数字是int的整数倍,也就是在int b完了之后现在已经占了八个格子了
规则三:现在还有int c没算,那么现在的结构体变量的大小为12,而第三条说了结构体变量的大小 一定是这个结构体变量中 最大的基础类型的大小的整数倍,而此时的最大的基础类型的大小为4,12是可以整除4的所以成立。此结构体的大小为12。
#include<stdio.h>
struct A
{
char a;//1
int b;//4
int c;//4
}Student;
int main()
{
struct A a;
printf("%d\n", sizeof(a));
return 0;
}
调试结果如下:
如果允许修改默认对齐大小,则规则变更:
1.结构体变量的首地址一定 是这个结构体变量中 Min(最大的基础(内置)类型的大小, 默认的对齐规则大小)的整数倍
2.结构体变量中每一个成员 相对于结构体首地址的偏移 一定是该成员的min(基础数据类型大小, 默认的对齐规则大小)的整数倍
3.结构体变量的总大小 一定是这个结构体变量中 Min(最大的基础类型的大小, 默认的对齐规则大小)的整数倍
默认的内存对齐大小 :vs默认8字节 gcc默认4字节
#pragma pack(4) //修改默认大小为4
#pragma pack()//恢复默认大小
那么下面这串代码的大小应该是多少呢?还是12吗
下面是修改默认大小的一串代码:
运行出来的结果是10,现在我们来分析以下这个结果:
这里就要使用上面的规则一:char类型的变量占的格子是1,所以首地址占的格子是1,
规则二:再看第二个是int类型,所以应该占四个格子,但是这里是需要偏移的,修改默认对齐后的第二条规格说了结构体变量中每一个成员应该是该成员的基础数据类型大小的整数倍,所以现在应该要补充1个格子让前边的数字是修改默认对齐大小2的整数倍,也就是在int b完了之后现在已经占了六个格子了
规则三:现在还有int c没算,那么现在的结构体变量的大小为10,而第三条说了结构体变量的大小 一定是这个结构体变量中 最大的基础类型的大小的整数倍,而此时的最大的基础类型的大小被修改为2,10是可以整除2的所以成立。此结构体的大小为10。
#pragma pack(2)
struct A
{
char a;//1
int b;//4
int c;//4
}Student;
int main()
{
struct A a;
printf("%d\n", sizeof(a));
return 0;
}
调试结果如下:
7. typedef的使用?
给一个类型起一个别名(小名)
typedef 类型 外号;(可以给外号再起外号)
例:typedef int AAA; //把整型int叫小名 AAA
typedef AAA BBB; //再给小名AAA再起个小名BBB,BBB表示的还是整型的int
下面这两串代码表达的意思都是用Student的小名来替代struct Student这个大名,只是两者写法不同而已,在平时的写代码过程中,我们习惯第二种写法
#include<stdio.h>
struct Student
{
char name[20];//名字
int id;//学号
char sex;//性别 1男 0女
int age;//年龄
int score;//总成绩
};
typedef struct Student Student;
#include<stdio.h>
typedef struct Student
{
char name[20];//名字
int id;//学号
char sex;//性别 1男 0女
int age;//年龄
int score;//总成绩
}Student;
使用:(写大名和写小名都是一样的都代表同一个东西)
int main()
{
struct Student stu1 = {"caocao", 12345, 1, 30, 88};
struct Student stu2 = {"liubei", 23456, 1, 35, 85};
Student stu1 = {"caocao", 12345, 1, 30, 88};
Student stu2 = {"liubei", 23456, 1, 35, 85};
return 0;
}
注:typedef和宏定义有什么区别?
typedef unsigned long long int uint64 ;
#define PINT int * //宏后面没有分号
//我们如何设计一个结构体,让他大小合适(既要满足对齐规则,又要尽可能的小)?
// 尽可能将小的结构体成员向前放
//如果不定义结构体变量,怎么计算结构体各个成员的相对偏移量?
#define MY_OFFSET(type, arg) ((int)&(((type*)0)->arg))