结构体
Posted fengzi759
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构体相关的知识,希望对你有一定的参考价值。
-
-
不是基本类型的数据结构也不是指针,它是若干个相同或不同类型的数据构成的集合
-
描述一组具有相同类型数据的有序集合,用于处理大量相同类型的数据运算,有时我们需要将不同类型的数据组合成一个有机的整体,以便于引用。
-
-
结构体类型的概念及定义
-
概念:
-
结构体是一种构造类型的数据结构,是一种或多种基本类型或构造类型的数据的集合
-
-
结构体类型的定义方法
-
在使用结构体之前必须先有类型,然后用类型定义数据结构,这个类型相当于一个摸具。
-
先定义结构体类型,再去定义结构体变量
-
struct 结构体类型名
-
成员列表
-
;
-
举例
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
-
-
//有了 结构体类型后,就可以用类型定义变量了
-
struct stu lucy,bob,lilei; //定义了三个 struct stu 类型的变量
-
每个变量都有三个成员, 分别是 num name sex
-
我们可以暂时认为 结构体变量的大小是它所有成员之和
-
-
在定义结构体类型的时候 顺便定义结构体变量
-
struct 结构体类型名
-
成员列表;
-
结构体 变量1,变量2;
-
struct 结构体类型名 变量3,变量4;
-
举例
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
lucy,bob,lilei;
-
int main()
-
struct stu xiaohong,xiaoming;
-
-
-
-
在定义结构体类型的时候,没有结构体类型名,顺便定义结构体变量,因为没有类型名,所以以后不能再定义相关类型的数据了
-
struct
-
成员列表:
-
变量1,变量2;
-
举例
-
struct
-
int num;
-
char name[20];
-
char sex;
-
lucy,bob;
-
以后没法再定义这个结构体类型的数据了,因为没有类型名
-
-
-
最常用的方法
-
通常咱们将一个结构体类型重新起个类型名,用新的类型名代替原先的类型
-
步骤1:先用结构体类型定义变量
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
bob;
-
-
步骤2 : 新的类型名替代变量名
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
STU;
-
-
步骤3: 再在 最前面加 typedef
-
typedef struct stu
-
int num;
-
char name[20];
-
cahr sex;
-
STU;
-
以后STU 就相当于 struct stu
-
STU lucy; 和 structural stu lucy; 是等价的
-
-
-
-
-
结构体变量的定义初始化及使用
-
结构体变量的定义和初始化
-
结构体变量,是个变量,这个变量是若干个数据的集合
-
注意:
-
在定义结构体变量之前首先得有结构体类型,然后再定义变量
-
再定义结构体变量的时候,可以顺便给结构体变量赋初值,被称为结构体的初始化。
-
结构体变量初始化的时候,各个成员顺便初始化
-
-
举例
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
;
-
struct stu boy;
-
struct stu lucy =
-
101,
-
"lucy",
-
‘f‘
-
;
-
-
-
结构体变量的使用
-
定义了结构体变量后,要使用变量
-
结构体变量成员的引用方法
-
结构体变量.成员名
-
-
举例
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
;
-
struct stu bob;
-
bob.num = 101;//bob 是个结构体变量,但是bob.num是个int类型的变量
-
bob.name 是个字符数组,是个字符数组的名字,代表字符数组的地址,是个常量
-
bob.name = "bob"; //是不可行,是个常量
-
strcpy(bob.name,"bob");
-
-
举例
-
struct stu
-
int num;
-
char name[20];
-
int score;
-
char *addr;
-
;
-
int main
-
struct stu bob;
-
printf("%d\n",sizeof(bob));
-
printf("%d\n",sizeof(bob.name));
-
printf("%d\n",sizeof(bob.addr));
-
-
-
-
-
结构体成员多级引用
-
struct date
-
int year;
-
int month;
-
int day;
-
;
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
struct date birthday;
-
;
-
int main
-
struct stu lilei =101,"lilei",‘m‘;
-
lilei.birthday.year = 1986;
-
lilei.birthday.month = 1;
-
lilei.birthday.day = 8;
-
printf("%d %s %c\n",lilei.num,lilei.name,lilei.sex);
-
printf("%d %d %d\n",lilei.birthday.year,lilei.birthday.month,lilei.birthday.day)
-
-
-
-
相同类型的结构体变量可以相互赋值
-
注意:必须是相同类型的结构体变量,才能相互赋值
-
举例
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
;
-
int main()
-
struct stu bob = 101,"bob",‘m‘;
-
struct stu lilei ;
-
lilei =bob;
-
//那么 lilei 里面的变量就等于 bob 里面的变量
-
-
-
-
结构体数组
-
结构体数组是个数组,由若干个相同类型的结构体变量构成的集合
-
结构体数组的定义方法
-
struct 结构体类型名 数组名[元素个数];
-
举例
-
struct stu
-
int num;
-
char name[20];
-
char sex;
-
;
-
struct stu edu[3]; //定义了一个struct stu 类型的结构体数组 edu
-
这个数组有3个元素 分别是 edu[0], edu[1] edu[2]
-
-
-
结构体数组元素的引用 数组名[下标
-
数组元素的使用
-
edu[0].num = 101;//用101 给edu数组的第0个结构体 变量的num赋值
-
strcpy(edu[1].name,"lucy");
-
-
举例
-
typedef struct student
-
int num;
-
char name[20];
-
float score;
-
STU;
-
STU edu[3] =
-
101,"lucy",78,
-
102,"bob",59.5,
-
103,"Tom",85
-
;
-
int main()
-
int i;
-
float sum=0
-
for(i = 0;i<3;i++)
-
-
sum+=edu[i].score;
-
-
printf("评价成绩为%f\n",sum/3);
-
-
-
-
结构体指针及大小计算
-
结构体指针及结构体的地址,结构体变量存放内存中,也有起始地址,咱们定义一个变量来存放这个地址,那这个变量就是结构体指针变量
-
结构体指针变量的定义方法
-
struct 结构体类型名 *结构体指针变量名
-
举例
-
struct stu
-
int num;
-
char name[20];
-
;
-
struct stu*p ;//定义了一个 struct stu *类型的指针变量
-
变量名 是p ,p占4个字节,用来保存结构体变量的地址编号
-
struct stu boy;
-
p = &boy;
-
-
-
访问结构体变量的成员方法
-
boy.num = 101;//可以 ,通过结构体变量名.成员名
-
(* p).num = 101;//可以 *P 相当于p指向的变量boy
-
p-> num = 101;// 可以,指针 ->成员名
-
通过结构体指针来引用指针指向的结构体的成员,前提是指针必须先指向一个结构体变量
-
-
结构体指针经常用到的地方:
-
保存结构体变量的地址
-
typedef struct stu
-
int num;
-
char name[20];
-
float score;
-
STU;
-
int main()
-
STU*p,lucy;
-
p=&lucy;
-
p->num = 101;
-
strcpy(p->name,"boby");
-
// p->name ="baby" ;//错误 ,因为p->name 相当于lucy.name
-
-
-
传结构体变量的地址
-
typedef struct stu
-
int num;
-
char name[20];
-
float score;
-
STU;
-
void fun(STU*p)
-
-
p->num = 101;
-
(*p).score = 87.6;
-
strcpy(p->name,"lucy");
-
-
int main()
-
STU girl;
-
fun(&girl);
-
printf("%d %s %f\n",girl.num,girl.name,girl.score);
-
-
-
传结构体数组的地址
-
结构体数组,是由多个相同类型的结构体变量构成的。存放再内存里,也有起始地址,其实就是第0个结构体的地址
-
举例
-
typedef struct stu
-
int num;
-
char name[20];
-
float score;
-
STU;
-
void fun(STU*p)
-
-
p[1].num = 101;
-
(*(p+1)).score = 88.6;
-
-
int main()
-
STU edu[3];
-
fun(edu);
-
printf("%d %f\n",edu[1].num,edu[1].score);
-
-
-
-
注意 :结构体变量的地址编号和结构体第一个成员的地址编号相同,但指针的类型不同
-
举例
-
struct stu
-
int num;
-
char name[20];
-
int score;
-
;
-
int main()
-
struct stu bob;
-
printf("%p\n",&bob);
-
printf("%p\n",&(bob.num));
-
-
-
-
结构体数组的地址就是结构体数组中第0个元素的地址
-
举例
-
struct stu
-
int num;
-
char name[20];
-
int score;
-
;
-
int main()
-
struct stu edu[3];
-
printf("%p\n",edu); //struct stu*
-
pritnf("%p\n",&(edu[0]));// struct stu*
-
printf("%p\n",&(edu[0].num));//int *
-
-
-
-
-
-
结构体内存分配
-
规则1:以多少个字节为单位开辟内存
-
给结构体变量分配内存的时候,会去结构体变量中找基本类型的成员,哪个基本类型的成员占字节数多,就以它大小为单位开辟内存
-
在gcc中出现double类型的,例外
-
成员中只有char型数据,以1字节为单位开辟内存
-
成员中出现了short int 类型数据,没有更大字节数的基本类型数据,就以2字节为单位开辟内存
-
出现了 int float 没有更大字节的基本类型数据的时候以4字节为单位开辟内存
-
出现了double类型的数据
-
情况1:
-
在vc里,以8字节为单位开辟内存
-
-
情况2
-
在gcc里,以4字节为单位开辟内存
-
-
-
无论是那种环境,double型变量,占8字节
-
注意:n如果在结构体中出现了数组,数组可以看成多个变量的集合。如果出现指针的话,没有占字节数更大的类型的,以4字节为单位开辟内存
-
在内存中存储结构体成员的时候,按定义的结构体成员的顺序存储
-
举例
-
struct stu
-
char sex;
-
int age;
-
lucy;
-
lucy 的大小4 的倍数
-
-
-
规则2:字节对齐
-
char 1 字节对齐,即存放char 型的变量,内存单元的编号是1的倍数即可
-
short int 2 字节对齐,即存放short int 型的变量,起始内存单位的编号是2的倍数即可
-
int 4字节对齐,即存放int 型的变量,起始内存单元的编号是4的倍数即可
-
long int 在32位平台下,4字节对齐,即存放long int 型的变量,起始内存单元的编号是4的倍数即可
-
float 4 字节对齐,即存放 float 型的变量, 起始内存单元的编号是4的倍数即可
-
double
-
vc环境下
-
8字节对齐,即存放double型变量的起始地址,必须是8的倍数,double变量占8个字节
-
-
gcc 环境下
-
4字节对齐,即存放double 型变量的起始地址,必须是4的倍数,double变量占8个字节
-
-
-
注意:当结构体成员中出现数组的时候,可以看出多个变量
-
注意:开辟内存的时候,从上向下依次按成员在结构体中的位置顺序开辟空间
-
-
举例
-
struct stu
-
char a;
-
short int b;
-
int c;
-
temp;
-
int main()
-
printf("%d\n",sizeof(temp));
-
printf("%p\n",&(temp.a));
-
printf("%p\n",&(temp.b));
-
printf("%p\n",&(temp.c));
-
-
结果分析: a的地址和b的地址差2个字节
-
b的地址和c的地址差2个字节
-
-
struct stu
-
char a;
-
int c;
-
short int b;
-
temp;
-
int main()
-
printf("%d\n",sizeof(temp));
-
printf("%p\n",&(temp.a));
-
printf("%p\n",&(temp.b));
-
printf("%p\n",&(temp.c));
-
-
结果分析: a和c的地址差4个字节
-
c和b的地址差4个字节
-
-
-
struct stu
-
char buf[10];
-
int a;
-
temp;
-
// temp 占16个字节
-
-
在vc 中占 16个字节 a和b 的地址差8个字节
-
在gcc中 占12个字节 a 和b 的地址差 4个字节
-
struct stu
-
char a;
-
double b;
-
temp;
-
int main()
-
printf("%d\n",sizeof(temp));
-
-
-
-
为什么要有字节对齐
-
用空间来换时间,提高cpu读取数据的效率
-
指定对齐原则
-
使用 #pragma pack 改变默认对其原则
-
格式:
-
#pragma pack(value) 时的指定对齐值 value
-
-
注意:
-
value 只能时 :1 2 4 8 等
-
指定对齐值与数据类型对齐值相比取较小值
-
说明: 咱们制定一个value
-
以多少个字节为单位开辟内存
-
结构体成员中,占字节数最大的类型长度和value比较,取较小值,为单位开辟内存
-
举例
-
pragma pack(2)
-
struct stu
-
char a;
-
int b ;
-
; 以2个字节 为单位开辟 内存
-
-
举例
-
#pragma pack(2)
-
struct stu
-
char a;
-
int b;
-
int c;
-
short int d;
-
temp;
-
int main()
-
printf("%d\n",sizeof(temp));
-
temp 为6个字节 a和b的地址差2个字节
-
-
举例
-
#pragma pack(8)
-
struct stu
-
char a;
-
int b;
-
temp;
-
int main()
-
printf("%d\n",sizeof(temp));
-
temp 的大小为8个字节 a和b的地址 差4字节
-
-
-
-
-
字节对齐
-
结构体成员中成员的对齐方法,各个默认的对齐字数和value相比,取较小值
-
举例
-
#pragma pack(2)
-
struct stu
-
char a;
-
int b;
-
temp;
-
int main()
-
printf("%d\n",sizeof(temp));
-
-
b成员是2字节对齐,a和b的地址差2个字节
-
-
如果指定对齐值
-
设为1: 则 short int float 等均为1
-
设为2 : 则 char 仍为 short 为2 int 变为2
-
-
-
-
-
-
位段(位域)
-
位段的概念
-
在大多数的计算机系统中, 一个字节是由八个更小的, 称作为位的单位组成的。位是比字节更小的单位。位只有两个值, 1 或 0 。因此, 存储在计算机存储器中的一个字节可以看成由八个二进制数字形成的串。
-
例如, 一个存放值 36 的字节是八个二进制数字的串: 可以表示成 00100100。 存入值24 的字节可以表示成 00010100。
-
-
注意: 不能对位段成员取地址
-
举例
-
struct packed_data
-
unsigned int a:2;
-
unsigned int b:6;
-
unsigned int c:4;
-
unsigned int d:4;
-
unsigned int i;
-
data;
-
int main()
-
printf("%d\n",sizeof(data));
-
printf("%p\n",&data);
-
printf("%p\n",&(data.i));
-
-
-
-
位段注意
-
对于位段成员的引用如下
-
data.a = 2
-
赋值时,不要超出位段定义的范围
-
如段成员 a定义为2位,最大值为3,即(11) 2
-
所以 data.a = 5, 就会取5的低两位进行赋值 101
-
-
位段成员的类型必须指定为整型或字符型
-
一个位段必须存放在一个存储单元中,不能跨两个单元,第一个单元空间不能容纳下一个位段,则该空间不用, 而从下一个单元起存放该位段
-
-
位段的存储单元
-
char 型位段 存储单元是1个字节
-
short int 型的位段存储单元是2个字节
-
int 的位段,存储单元是4字节
-
long int 的位段,存储单元是4个字节
-
举例
-
struct stu
-
char a:7;
-
char b:7;
-
char c:2;
-
temp; //占3个字节,b不能跨存储单元存储
-
int main()
-
printf("%d\n",sizeoof(temp));
-
-
结果为:3 证明位段不能跨其存储单元存储
-
-
注意: 不能取 temp.b的地址,因为b可能不够1字节,不能取地址
-
-
位段的长度不能大于存储单元的长度
-
char 型 位段不能大于 8位
-
short int 型位段 不能大于 16位
-
int 型的位段,位段不能大于32位
-
long int的位段,位段不能大于32位
-
举例
-
struct stu
-
char a:9;
-
char b:7;
-
char c:2;
-
temp;
-
int main()
-
printf("%d\n",sizeof(temp));
-
编译出错, 位段a不能大于其存储单元的大小
-
-
-
如一个段要从另一个存储单元开始,可以定义
-
unsigned char a:1;
-
unsigned char b:2;
-
unsigned char :0;
-
unsigned char c:3; (另一个单元)
-
由于用了长度为0 的位段,其作用是使下一个位段从下一个存储单元开始存放
-
将a、b存储在一个存储单元中,c另存在下一个单元
-
举例
-
struct m_type
-
unsigned char a:1;
-
unsigned char b:2;
-
unsigned char :0;
-
unsigned char c:3;
-
;
-
int main()
-
struct m_type temp;
-
printf("%d\n",sizeof(temp));
-
-
-
-
可以定义无意义位段 如:
-
unsigned a:1;
-
unsigned d:2;
-
unsigned b:3;
-
举例
-
位段的应用
-
struct data
-
char a:1;
-
char b:1;
-
char c:1;
-
char d:1;
-
char e:1;
-
char f:1;
-
char g:1;
-
char h:1;
-
temp;
-
int main()
-
char p0;
-
//p0 = 0x01; //0000 0001
-
temp.a = 1;
-
//p0 = temp; //错的,类型不匹配
-
//p0 = (char)temo;//错的,编译器不允许将结构体变量。强制转成基本类型的字符型
-
p0 = *((char *)(&temp));
-
-
-
-
以上是关于结构体的主要内容,如果未能解决你的问题,请参考以下文章
C 语言结构体 ( 结构体类型定义 | 结构体类型别名 | 声明结构体变量的三种方法 | 栈内存中声明结构体变量 | 定义隐式结构体时声明变量 | 定义普通结构体时声明变量 )