结构体概念;
结构体是一种构造数据类型,像数组也是构造数据类型,但是数组是处理大量相同类型的数据运算,而结构体是一种或者多种构造类型的数据的集合。
结构体类型定义;
定义方法:在使用结构体前必须现有类型,然后用类型定义数据结构
方法一:先定义结构体类型,再去定义结构体变量
struct 结构体类型名{
成员列表
};//记得加分号
例
struct stu {
int num;
char name[20];
char sex;
};
有了结构体类型后,就可以用类型定义变量了;
struct stu lucy,bob,liel;//lucy,bob,liel这三个人你分别有了num,name,sex 这三个属性
方法二:在定义结构体类型的时候顺便定义结构体变量,以后还可以定义结构体变量
struct 结构体类型名{
成员列表
};结构变量1,结构变量2;
struct 结构体类型名 变量3,变量4;
例
struct stu {
int num;
char name[20];
char sex;
};lucy,bob,liel;
struct stu xiaohong,xiaoming ;
方法三:在定义结构体类型的时候,没有结构体类型名,顺便定义结构体变量,因为没有类型名,所以以后不能再定义相关类型的数据了
例
struct {
int num;
char name[20];
char sex;
};lucy,bob,liel;
方法四:最常用的方法
通常我们将一个结构体类型冲刺拿起一个类型名,用新的类型名替代原先的类型
步骤1:先用结构体类型定义变量
例
struct stu {
int num;
char name[20];
char sex;
};bob;
步骤二:新的类型名替代变量名
例
struct stu {
int num;
char name[20];
char sex;
}STU;
步骤三:在最前面加typedef
例
typedef struct stu{
int num;
char name[20];
char sex;
}STU;
注意:步骤一和步骤二,在草稿上做的,步骤三是程序中我们需要的代码
结构体变量的定义初始化及使用;
1结构体变脸的定义和初始化
结构体变量,是个变量,这个变量使若干个相同的或者不同的 数据构成的集合
注:
1:在定义结构体变量之前首先得有结构体类型,然后再定义变量
2:在定义变量的时候,可以顺便给结构体变量赋初值,称为结构体的初始化
3:结构体变量初始化的时候,各个成员顺序初始化
#include<stdio.h>
struct stu {
int sum;
char name[20];
char sex;
};
int main()
{
struct stu boy = {
100,
,
'm'//这样中间不赋值是不可以的,但是在最后(sex不赋值)不赋值是可以的
}
struct stu lucy = {
101,
"lucy",
'm'//没有逗号
};
return 0;
}
2结构体变量的使用
1:变量引用方法:结构体变量.成员名
#include<stdio.h>
#include<string>
struct stu {
int sum;
char name[20];
char sex;
};
int main()
{
struct stu bob;
bob.num = 100;
printf("bob.num=%d/n", bob.num);
//bob.name='bob';错误,因为bob,name是个数组的名字,是个常量
strcpy(bob.name, "bob");
printf("bob.name=%s\n", bob.name);
return 0;
}
3结构体变量大小:变量大小是其所有成员之和
4结构体成员多级引用
#include<stdio.h>
struct date {
int year;
int month;
int day;
};
struct stu {
int num;
char name[20];
char sex;
struct date birthday;
};
int main()
{
struct stu boy = {
101,
"lilei",
'm'
};
boy.birthday. year = 2000;
boy.birthday.month = 3;
boy.birthday.day = 1;
printf("%d %s %c\n", boy.num, boy.name, boy.sex);
printf("%d %d %d\n", boy.birthday.year, boy.birthday.month, boy.birthday.day);
return 0;
}
运行结果:
101 lilei m
2000 3 1C:\Users\86152\source\repos\实验四\x64\Debug\实验四.exe (进程 25936)已退出,代码为 0。
按任意键关闭此窗口. . .
5结构体变量的相互赋值:
相同类型的结构体变量才可以赋值
结构体数组;
结构体数组是一个数组,有若干个相同类型的结构体变量构成的集合;
1定义方法:
struct 结构体类型名 数组名【元素个数】
struct stu {
int num;
char name[20];
char sex;
};
struct stu edu[3];//定义了 struct stu类型的结构体数组edu,这个数组有三个元素,分别是edu[0],edu[1],edu[2].
2数组元素的使用
edu[0].num=101;//把101赋值给edu[0];
strcpy(edu[1].name,"lucy");
#include<stdio.h>
typedef struct student {
int num;
char name[20];
float score;
} STU;
int main()
{
STU edu[3] = {
{101,"lucy",78},
{102,"bob",59.5},
{103,"tom",85}
};
float sum = 0;
int i;
for (i = 0; i < 3; i++) {
sum += edu[i].score;
}
printf("平均成绩为:%f\n", (float)(sum / 3));
return 0;
}
结构体指针;
即结构体的地址,结构体变量存放在内存中,也有起始地址。咱们定义一个变量来存放这个地址,那么这个变量就是结构体指针变量。结构体指针变量是一个指针,指针变量占四个字节。
1定义方法
struct 结构体类型名 *结构体指针变量;
例:struct stu *p;//定义了一个struct stu*类型的指针变量
struct stu boy;
p=&boy;
2访问结构体变量的成员方法
A:boy.num=101;//可以
B:(*p).num=101;//可以*p相当于p指向的变量boy
C:p->num=101;//可以,指针->成员名//前提是指针必须先指向一个结构体变量
3指针应用场景1:保存结构体变量的地址
4指针应用场景2:传 结构体变量的地址
#include<stdio.h>
#include<string>
typedef struct student {
int num;
char name[20];
float score;
} STU;
void fun(STU* p) {//因为没有返回值所以用void
p->num = 101;
strcpy(p->name, "lucy");
p->score = 88.6;//(*p.score=88.6);
}
int main()
{
STU girl;
fun(&girl);//把girl的地址传给fun函数
printf("%d %s %f\n", girl.num, girl.name, girl.score);
return 0;
}
5指针应用场景3:传结构体数组的地址
结构体数组的地址就是第零个结构体的地址,
#include<stdio.h>
#include<string.h>
typedef struct student {
int num;
char name[20];
float score;
} STU;
void fun(STU* p,int n) {//因为没有返回值所以用void
int i;
for (i = 0; i < n; i++) {
printf("%d %s %f\n", p[i].num, p[i].name, p[i].score);
}
}
int main()
{
STU edu[3] = {
{101,"lucy",88.3f},//f的作用是把double 型转化为float型
{102,"bob",78.6f},
{103,"lilei",93.7f}
};
fun(edu,3);
return 0;
}
6注意
A:结构体变量的地址编号和结构体第一个成员的地址编号相同,但指针的类型不同(STU*类型与int*类型)
B: 结构体数组的地址就是结构体数组中第零个元素的地址
结构体内存分配;
结构体内存分配概述
结构体变量大小是它所有成员的大小之和
结构体内存分配规则1 以多少个字节为单位开辟内存
给结构体变量分配内存时,回去结构体变量中找基本类型的成员,那个类型的成员站的字节多就以他为大小开辟内存,但在gcc中出现double时例外
1:成员中只有char 类型的,一个字节
2:最大short int ,以两个字节为单位开辟内存
3:in或者float最大,四个字节
4:出现了double类型的数据
A 在vc.6.0和VS中,以八个字节为单位开辟内存
B在Linux环境gcc里,以四个字节为单位开辟
无论在那种环境double型变量占八个字节
如果在结构体中出现了数组,数组可以看成多个变量的集合
如果出现指针的话,没有占字节数更大的类型的,以四个字节为单位开辟内存
在内存中存储结构体成员的时候,按定义的结构体成员的顺序存储
结构体内存分配规则2 字节对齐
1:char 1字节对齐,即存放char型的变量,内存单元的编号是一的倍数
2:short int ,2字节对齐
3:int 4字节对齐
4:long int,4字节对齐
5:float四字节对齐
6:double
A 在vc.6.0和VS中,以八个字节为对齐
B gcc里,四个字节对齐
注意:1当结构体成员中出现数组时,可以看作多个变量
2开辟内存是从上向下一次按成员在结构体中的位置顺序开辟空间
四个四个字节的开辟
字节对齐的目的
用空间来换时间,提高cpu读取数据的效率
指定对齐原则
使用#pragme pack改变默认对齐原则,每一个编译器都有其默认的对齐原则,使用#pragme pack可以改变默认原则
格式:#pragme pack(value)时指定对齐值value
注意:1 value只能是1,2,4,8等2的指数
2:指定对齐值与数据类型对齐值相比取较小值
(1):以多少字节为单位开辟内存
结构体成员中,占字节数最大的类型长度和value比较,取较小值,为单位开辟内存
#pragme pack(2)
struct stu {
char a;
int b;
};//以两字节位单位开辟内存
位段
在结构体之中,以位为单位的成员,称之为位段
关于这个图,int类型以四字节开辟内存,而a,b,c,d加起来才占了十六位两个字节,所以有两个字节十六位被剩下 ,注意不能对位段成员取地址
#include<stdio.h>
struct stu {
unsigned int a : 2;//意思是a只占了两位,一个字节是八位
unsigned int b : 6;
unsigned int c : 4;
unsigned int d : 4;
unsigned int i ;
};
int main() {
struct stu data;
printf("sizeof(data)=%d\n", sizeof(data));printf("&data=%p\n", &data);
printf("&(data.i)=%p\n", &(data.i));
return 0;
}//验证上图
位段注意:
1、对于位段成员的引用如下:
data.a=2
赋值时,不要超出位段定义的范围;如段成员a定义为2位(二进制的两位),最大值为3,即(11)2
所以data.a=5,就会取5的低二位进行赋值101,101就变成了01也就是1;
2、位段成员的类型必须指定为整形或字符型
3、一个位段必须存放在一个存储单元中,不能跨两个单元,第一个单元空间不能容纳下一个位段,则该空间不用,而从下一个单元起存放该位段
位段的存储单元
1、char类型位段,存储单元是一个字节
2、short int 2个字节
3、int 4个字节
4、long int 4个字节
struct stu{
char a:7;
char b:7;
char c:2;
}temp;//七加七加二等于十六是两个字节,但是实际是占3个字节,因为b不能跨存储单元存储只能从下一个开辟的字节存放
结果为:3、证明位段不能跨其存储单元存储
注意:不能取temp.b(位段)的地址,因为b可能不够一个字节,不能取地址
4、位段的长度不能大于存储单元的长度
(1):char型位段不能大于8为
(2):short int 型 不能大于16位
(3):int 的位段,不能大于32位
(4):long int 的位段,位段不能大于32位
5、如一个段要从另一个存储单元开始,可以定义:
unsighed char a:1;
unsighed char b:2;
unsighed char :0;
unsighed char c:3;(另一个单元)
由于用了长度为0的位段,其作用是使下一个位段从下一个存储单元开始存放
将a,b存储在一个存储单元中,c另存在下一个单元中
6、可以定义无意义的位段,如
unsighed a:1;
unsighed :2;//这里指在a之后要浪费两位
unsighed b:3;