赵老师笔记----结构体
是一种构造数据类型
跟数组一样,也是构造数据类型
数组:
相同数据类型数据的集合
引入:
教务系统录入每个同学的成绩
int num;
char name[20];
char sex;
int age;
int score[7];
录入一个班的学生如何解决
解决方案一,用变量名区别每个学生:
int num1;
char name1[20];
char sex1;
int age1;
int score1[7];
int num2;
char name2[20];
char sex2;
int age2;
int score2[7];
解决方案二,用数组解决:
int num[50];
char name[50][20];
char sex[50];
int age[50];
int score[50][7];
一、结构体的概念及定义方法
1、概念:
结构体是一种构造数据类型,是一种不同数据类型的变量的集合
2、定义方法:
①先定义结构体类型,再去定义变量
struct 结构体类型名
{
成员变量;
};
struct 结构体类型名 变量名;
struct student
{
int num;
char name[20];
char sex;
int age;
int score[7];
};
struct student class[50];
②定义结构体时,顺便定义变量
struct 结构体类型名
{
成员变量;
}变量名,变量名2;
struct student
{
int num;
char name[20];
char sex;
int age;
int score[7];
}class1[50],class2[50];
struct student class3[50];
③在定义结构体时可以没有结构体类型名,这样只能顺便定义变量。
由于没有类型名,所以以后不能再定义该结构体型的变量了
struct
{
成员变量;
}变量名,变量名2;
struct
{
int num;
char name[20];
char sex;
int age;
int score[7];
}class1[50],class2[50];
④最常用方法
先用结构体类型定义类型名,然后用新的类型名去定义变量
typedef struct 结构体类型名
{
成员变量;
}新类型名;
新类型名 变量名;
typedef struct student
{
int num;
char name[20];
char sex;
int age;
int score[7];
}STU;
STU class1[50],class2[50];
struct student class1[50],class2[50];
二、结构体变量的初始化及使用
(1)整体初始化
typedef struct student
{
int num;
char name[20];
char sex;
int age;
}STU;
STU liming={100,"liming",'m',19};
(2)利用单个成员变量初始化
typedef struct student
{
int num;
char name[20];
char sex;
int age;
}STU;
STU liming;
liming.num=100;
strcpy(liming->name,"liming");
liming.sex='m';
liming.age=19;
(3)使用时通过.去引用个成员变量
liming.num=100;
strcpy(liming.name,"liming");
liming.sex='m';
liming.age=19;
(4)若是结构体指针变量,如何引用成员变量??
typedef struct student
{
int num;
char name[20];
char sex;
int age;
}STU;
STU *liming;
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int main(int argc, char *argv[])
{
typedef struct student
{
int num;
char name[20];
char sex;
int age;
}STU;
STU *liming=(STU *)malloc(sizeof(STU));
liming->num=100;
strcpy(liming->name,"liming");
liming->sex='m';
liming->age=19;
printf("%d---%s----%c----%d\n",liming->num,liming->name,liming->sex,liming->age);
return 0;
}
(5)结构体多级引用
struct date
{
int year;
int month;
int day;
};
typedef struct student
{
int num;
char name[20];
char sex;
struct date birthday;
}STU;
STU liming;
liming.birthday.year
练习:利用多级结构体定义,打印学生的生日信息,指针或普通变量
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int main(int argc, char *argv[])
{
struct date
{
int year;
int month;
int day;
};
typedef struct student
{
int num;
char name[20];
char sex;
struct date birthday;
}STU;
STU liming={100,"liming",'m',{2005,10,20}};
STU *pliming;
pliming=&liming;
printf("%d---%d----%d\n",liming.birthday.year,liming.birthday.month,liming.birthday.day);
printf("%d---%d----%d\n",pliming->birthday.year,pliming->birthday.month,pliming->birthday.day);
printf("%d---%d----%d\n",(*pliming).birthday.year,(*pliming).birthday.month,(*pliming).birthday.day);
return 0;
}
(6)相同的结构体可以整体赋值;
typedef struct student
{
int num;
char name[20];
char sex;
int age;
}STU;
STU liming={100,"liming",'m',19},zhangsan;
zhangsan=liming;
(7)结构体递归定义
typedef struct student
{
int num;
char name[20];
char sex;
int age;
struct student *next;
}STU;
三、结构体数组
数组,其次他是相同结构体类型的集合
typedef struct student
{
int num;
char name[20];
char sex;
int age;
}STU;
STU class[50];
练习:定义一个结构体数组,求学生平均成绩
四、结构体指针
1.定义 typedef struct student
{
int num;
char name[20];
char sex;
struct date birthday;
}STU;
STU liming={100,"liming",'m',{2005,10,20}};
STU *pliming=&liming;
2.访问结构体变量的成员
①通过普通结构体变量去访问
liming.num;//通过结构体变量名.成员变量名
②(*pliming).num;//*pliming相当于liming
③pliming->num;//指针->成员变量名,千万注意这时候它只是一个普通变量,而非指针
以上三种方式等价。
3.结构体指针应用场合
①利用结构体指针可以保存结构体变量的地址
STU liming={100,"liming",'m',{2005,10,20}};
STU *pliming=&liming;
②利用该地址可以进行传参给函数,可以改值
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct student
{
int num;
char name[20];
char sex;
}STU;
void chgname(STU *p)
{
strcpy(p->name,"zhangsan");
p->num=110;
p->sex='F';
}
int main(int argc, char *argv[])
{
STU liming={100,"liming",'m'};
printf("%d---%s----%c\n",liming.num,liming.name,liming.sex);
chgname(&liming);
printf("**********************\n");
printf("%d---%s----%c\n",liming.num,liming.name,liming.sex);
return 0;
}
③传结构体数组的地址,同样可以改值
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct student
{
int num;
char name[20];
char sex;
}STU;
void chgname(STU *p)
{
strcpy(p[1].name,"libai");
p[1].num=110;
(*(p+0)).sex='f';
}
int main(int argc, char *argv[])
{
int i;
STU liming[2]={{100,"liming",'m'},{101,"zhangsan",'f'}};
for (i=0;i<2;i++)
printf("%d---%s----%c\n",liming[i].num,liming[i].name,liming[i].sex);
chgname(liming);
printf("**********************\n");
for (i=0;i<2;i++)
printf("%d---%s----%c\n",liming[i].num,liming[i].name,liming[i].sex);
printf("%p\n",liming);
printf("%p\n",&liming[0]);
printf("%p\n",&(liming[0].num));
return 0;
}
注意:结构体变量的地址编号和结构体第一个成员变量的地址编号相同,但指针的类型不同
结构体数组的地址就是结构体数组中第0个元素的地址
五、结构体内存分配
结构体的总大小是否是各成员变量大小的简单只和???
typedef struct A
{
char sex;
int age;
short num;
}A; sizeof(A)=12
typedef struct B
{
char sex;
short num;
int age;
}B; sizeof(B)=8
①字节序
系统向内存中存放多字节数据时,数据中个字节的排序
unsigned int x=0x12345678;
何为大端计算机何为小端计算机??
编写一个小程序实现计算机大小端的判断,并在屏幕输出提示信息。
说明:大端计算机表示,高地址存放数据低位,低地址存放数据高位;小端计算机表示,低地址存放数据低位,高地址存放数据高位。
#include "stdio.h"
int main(int argc, char *argv[])
{
unsigned int x=0x12345678;
char b=0x78;
char c=(char)x;
if (c==b)
printf("小端计算机\n");
else
printf("大端计算机\n");
return 0;
}
②地址对齐
为了提高cpu访问内存数据的效率,牺牲空间来换取效率
char a;1
short b;2
int c;4
float d;4
double e;8
cpu 32bit 4byte
(1)自然对齐
起始地址能被长度整除,称为自然对齐
(2)适当对齐
起始地址能被M值整除称为适当对齐
M值:长度<机器字长,M值=长度
长度>=机器字长,M值=机器字长
数组:按元素类型适当对齐
结构体:成员中M值最大的对齐
公用体:成员中M值最大的对齐
(3)使用#pragma pack改变默认对其原则
格式:
#pragma pack (value)时的指定对齐值value。
1.value只能是:1 2 4 8等
2.指定对齐值与数据类型对齐值相比取较小值
如:如果指定对齐值:
设为1:则short、int、float等均为1
设为2:则char仍为1,short为2,int 变为2
#include "stdio.h"
int main(int argc, char *argv[])
{
#pragma pack(2)
typedef struct
{
int aa1; //2个字节对齐 1111 4
char bb1;//1个字节对齐 1
short cc1;//2个字节对齐 011 4
char dd1; //1个字节对齐 1 2
} testlength1;
int length1 = sizeof(testlength1);
printf("A的大小%d\n",length1); 10
return 0;
}
#include "stdio.h"
int main(int argc, char *argv[])
{
#pragma pack(4)
typedef struct
{
int aa1; //4个字节对齐 1111 4
char bb1;//1个字节对齐 1
short cc1;//2个字节对齐 011 4
char dd1; //1个字节对齐 1 4
} testlength1;
int length1 = sizeof(testlength1);
printf("A的大小%d\n",length1); 12
return 0;
}
规则1:以多少个字节单元去开辟内存
没有指定,就以默认的M值去开辟空间,以较大的数据类型占的字节数去开辟空间
typedef struct A
{
char sex;2
short num;2
}A; sizeof(A)=4
typedef struct A
{
char sex;4
int age;4
short num;4
}A; sizeof(A)=12
#pragma pack(value)以value个字节去开辟内存
#pragma pack(2)
typedef struct A
{
char sex;2
int age;4
short num;2
}A; sizeof(A)=8
#pragma pack(4)
typedef struct A
{
char sex;4
int age;4
short num;4
}A; sizeof(A)=12
规则2:字节对齐
#pragma pack(4)
typedef struct A
{
char sex;1
short num;011
int age;4
}A; sizeof(A)=8
#pragma pack(2)
typedef struct A
{
char sex;2
short num;2
int age;4
}A; sizeof(A)=8
六、位段
在结构体中,以位为单位的成员变量,称之为位段(位域)
struct packed_data
{
unsigned int a:2;
unsigned int b:1;
unsigned int :5;无意义位段
unsigned int c:6;
unsigned int :0;
unsigned int d:23;(另一个单元)
}
例子:
#include "stdio.h"
int main(int argc, char *argv[])
{
typedef struct A
{
unsigned char led:2;
unsigned char :2;
unsigned char key:1;
unsigned char button:2;
}A;
int length1 = sizeof(A);
A aa;
aa.led=2;
aa.key=0;
aa.button=2;
unsigned char bb=*((char*)&aa);
printf("A的大小%d\n",length1);
printf("bb的值%x\n",bb);
return 0;
}
七、公用体
union
定义方式同结构体,有三种方式
最常用方法
先用结构体类型定义类型名,然后用新的类型名去定义变量
typedef union 公用体类型名
{
成员变量;
}新类型名;
新类型名 变量名;
typedef union
{
int num;
int age;
char sex;
}DATA;
公用体特点:
①成员变量公用一块内存
②在某一时刻,只有一个成员变量起作用
③所有成员变量地址相同
④成员变量的初始化
DATA a ={123};//初始化公用体的第一成员
#include "stdio.h"
int main(int argc, char *argv[])
{
typedef union
{
int num;
int age;
char sex;
}DATA;
DATA aa;
aa.num=20;
aa.age=30;
aa.sex=10;
printf("num+age+sex=%d\n",aa.num+aa.age+aa.sex);
return 0;
}
对齐:公用体按最大的成员变量的字节数对齐
八、枚举
enum
定义:
enum 枚举名
{
枚举值表 //多个时逗号隔开
};
举例:
enum week
{mon, tue ,wed ,thu, fri, sat, sun};
#include "stdio.h"
int main(int argc, char *argv[])
{
enum week{mon, tue ,wed ,thu, fri, sat, sun}a,b,c;
enum bool{false,true}d;
a=mon;
b=thu;
c=sun;
d=true;
printf("%d,%d,%d\n",a,b,c);
if (d==true)
printf("d为真!\n");
return 0;
}
可以改变枚举值的默认值:
enum week //枚举类型
{
mon=3,tue,wed,thu,fri,sat,sun
};
mon=3 tue=4,以此类推