【C语言】1. 结构体struct(结构体概念、结构体指针、结构体作为函数参数、传值与传地址、内存对齐(struct与union))

1. 结构体struct

1.1 结构体类型的概念

“结构体”是一种构造类型,它是由若干“成员”组成的,其中的每一个成员可以是一个基本数据类型也可以是一个构造类型。
假如在程序中要使用“学生”这样一个类型,学生具有姓名、性别、年龄等属性
声明结构体使用的关键字是struct,其一般形式为:

struct 结构体名
{
	成员列表
};

关键字struct表示声明结构,其后的结构体名表示该结构的类型名
注意:大括号最后面有一个分号“ ; ”,不要忘记
例如:

struct Student
{
	char _name[10];
	char _gender[10];
	int _age;
};

使用关键字struct声明一个名为Student的结构体类型,在结构体中定义的变量是Student结构的成员。

1.2 结构体变量的定义

1.2.1 声明结构体类型,再定义变量(最常用)

//创建结构体模板
struct Student
{
	char _name[10];
	char _gender[10];
	int _age;
};
//使用该模板创建3个变量stu1,stu2,stu3
struct Student stu1,stu2,stu3;

缺点就是定义变量时必须带上struct
可以使用typedef进行简写,这样在定义变量时比较简洁

//结构体模板struct Student重新命名为Stu
typedef struct Student
{
	char _name[10];
	char _gender[10];
	int _age;
}Stu;
//使用Stu创建3个变量stu1,stu2,stu3
Stu stu1,stu2,stu3

此处使用typedef为结构体模板struct Student定义一个别名Stu

1.2.2 在声明结构体类型时,定义变量

struct Student
{
	char _name[10];
	char _gender[10];
	int _age;
}stu1,stu2,stu3;

1.2.3 直接定义结构体类型变量

struct 
{
	char _name[10];
	char _gender[10];
	int _age;
}stu1,stu2,stu3;

缺点:不能用该结构定义新的变量。

1.3 结构体变量的引用

结构体变量名.成员名

在引用结构的成员时,可以在结构的变量名的后面加上成员运算符“ . ”和成员的名字

Stu._name = "Hanmei";
Stu._age = 15;

2. 结构体数组

定义结构体数组的一般形式如下:

struct 结构体名
{
	成员列表
}数组名;
struct Student
{
	char _name[10];
	char _gender[10];
	int _age;
}stu[10];

也可以先声明结构体类型再定义结构体数组

typedef struct Student
{
	char _name[10];
	char _gender[10];
	int _age;
}Stu;

在主函数中定义结构体数组

Stu stu[10];

3. 结构体指针

3.1 概念

结构体指针:指向结构体变量的指针
定义结构体指针的一般形式:

结构体类型* 指针名

定义一个指向struct Student结构类型的 p 指针变量如下:

struct Student* p;

使用指向结构体变量的指针访问成员有以下两种方法:

3.2 第一种方法是使用点运算符引用结构成员

(*p).成员名;

注意:*p一定要使用括号,因为点运算符的优先级是最高的

3.3 第二种方法是指向运算符引用结构成员

p->成员名;

假如student为结构体变量,p为指向结构体变量的指针,则下列3种形式的效果是等价的

student.成员名;
(*p).成员名;
p->成员名;

在使用"->"引用成员时,要注意分析以下情况:
p->iGrade; //表示指向结构体变量中成员iGrade的值
p->iGrade++; //表示指向结构体变量中成员iGrade的值,使用后该值加1
++p->iGrade; //表示指向结构体变量中成员iGrade的值加1,计算后再使用

4. 结构体作为函数参数

4.1 使用结构体变量作为函数参数

使用结构体变量作为函数的实际参数时,采取的是“值传递”,它会将结构体变量所占内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量

void Display(struct Student stu);

在形参的位置使用结构体变量,但是函数调用期间,形参也要占用内存单元,这种传递方式在空间和时间上开销都比较大
另外,根据函数参数传值方式,如果在函数内部修改了变量中成员的值,则改变的值不会返回到主调函数中

4.2 使用指向结构体变量的指针作为函数参数

在传递结构体变量的指针时,只是将结构体变量的首地址进行传递,并没有将变量的副本进行传递

void Display(struct Student *stu);

5. 传值与传地址

5.1 传值

实际是把实参的值赋值给行参,相当于copy。那么对行参的修改,不会影响实参的值

5.2 传地址

实际是传值的一种特殊方式,只是他传递的是地址,不是普通的赋值,那么传地址以后,实参和行参都指向同一个对象,因此对形参的修改会影响到实参

5.3 传值举例

在这里插入图片描述
在这里插入图片描述
值传递:可以看到a,b的值并没有被交换
在main函数中swap(a,b)将a,b两个值传给了调用函数swap中的x,y,在swap调用函数中完成了x和y的交换,但是只是完成了x,y的交换,跟主函数中的a,b没有任何关系。这只是一次单向的传递过程,x,y是定义在函数swap中的局部变量,当函数调用结束后,它俩就over了,被残忍抛弃了(子函数的生命期为子函数开始调用到结束调用,调用结束后就主动释放了),因此它们没有渠道把交换的值传回给a,b

5.4 传地址举例

在这里插入图片描述
在这里插入图片描述
传地址是实参和行参都指向同一个对象,因此对形参的修改会影响到实参

6. 内存对齐(struct 与 union)

6.1 struct 与 union区别

struct:用户自定义数据类型,是一些变量的集合体。
union:也是一种特殊的自定义类型,也包含一系列的成员,特征是这些成员公用同一块内存空间,所以联合变量的大小,至少是最大成员的大小。
(1)struct可以存储多个成员信息,而union只能存储最后一个成员的信息;(2)struct会给每一个成员分配内存空间,而union的所有成员公用一块内存空间;
(3)union的不同成员赋值,将会对其他成员重写,而struct的不同成员赋值是互不影响的。

6.2 结构体内存对齐

(1)第一个成员在偏移量为0的地址处;
(2)其他成员变量对齐到某个数字的整数倍地址处,这个数是编译器默认的对齐数与该成员大小的较小值,VS中默认是8,也可以使用#pragma pack来修改默认对齐数;
(3)结构体的总大小为最大对齐数的整数倍。

6.3 联合体内存对齐

(1)联合的大小至少是最大成员的大小;
(2)当最大成员的大小不是最大对齐数的整数倍时,要对齐到最大对齐数的整数倍。

6.4 类型所占字节数

在这里插入图片描述

6.5 内存对齐示例

示例1

struct name1
{
	char str;  //1字节
	short x;   //2字节
	int num;   //4字节
};
sizeof(name1) = 8  // 1(2) + 2 + 4 = 8

示例2

struct A
{
char t:4; //4表示占一个字节的4个比特位
char k:4;
unsigned short i:8;
unsigned long m;
}; 

一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。

sizeof(A) = 8   //1 + 1 + 2 + 4 = 8

示例3

struct name2
{
	char str;
	int num;
	short x;
}; 
sizeof(name2) = 12   // 1(4) + 4 + 2(4) = 12

示例4

struct st1
{
	unsigned chara:7;/*字段a占用了一个字节的7个bit*/

	unsigned charb:2;/*字段b占用了2个bit*/

	unsigned charc:7;/*字段c占用了7个bit*/
}s1;
sizeof(s1) = 3  // 1 + 1 + 1 = 3

示例5

struct st2
{
	unsigned inta:31;

	unsigned intb:2;/*前一个整型变量只剩下1个bit,容不下2个bit,所以只能存放在下一个整型变量*/

	unsigned int c:31;
}s2;
sizeof(s2) = 12   // 4 + 4 + 4 = 12
  • 16
    点赞
  • 150
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值