C语言结构体

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))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值