结构体
结构体的意义
问题引入:
学籍管理需要每个学生的下列数据:学号、姓名、性别、年龄、分数,请用C语言程序存储并处理一组学生的学籍。
结构体的定义和使用
结构体的定义:结构体是由一批数据组合而成的结构型数据。组成结构型数据的每个数据称为结构型数据的“成员”,其描述了一块内存区间的大小及解释意义。
结构体的定义
语法:
struct 结构体名
{
<结构体成员列表>
} ;
#include<stdio.h>
struct student
{
char name[16]; //姓名
int num; //学号
float score; //成绩
};
结构体的使用(赋值)方式之一
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct student
{
char name[16]; //姓名
int num; //学号
float score; //成绩
//3.定义结构体时赋值
}stu4("王五",103,99);
int main()
{
//1.定义后赋值
struct student stu1;
stu1.num = 100;
strcpy(stu1.name, "张三");
stu1.score = 100;
printf("name = %s , num = %d , score = %f\n", stu1.name, stu1.num, stu1.score);
//2.定义时赋值
//a.全部赋值
struct student stu2 = { "李四",101,98 };
printf("name = %s , num = %d , score = %f\n", stu2.name, stu2.num, stu2.score);
//a.部分赋值
struct student stu3 = {
.name = "",
.num = 102,
.score = 99
};
printf("name = %s , num = %d , score = %f\n", stu3.name, stu3.num, stu3.score);
return 0;
}
结构体的使用(赋值)方式之二—结构体数组
作用:将自定义的结构体放入到数组中方便维护。
语法:
struct 结构体名 数组名[元素个数] = {{},{},……{}} ;
注意:在C语言中,数组初始化应该在声明时进行,或者通过逐个元素赋值。
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct student
{
char name[16]; //姓名
int num; //学号
float score; //成绩
};
int main()
{
struct student stu[3] = { {"张三",100,100},{"李四",101,98},{"王五",103,99} };
int i;
for (i = 0; i < 3; i++)
{
printf("%s %d %f\n", stu[i].name, stu[i].num, stu[i].score);
}
return 0;
}
结构体的使用(赋值)方式之三 — 结构体指针
作用:
通过指针访问结构体中的成员。
语法:
struct 结构体名 * 指针名;
利用操作符 ->可以通过结构体指针访问结构体。
普通变量访问结构体用的是 . 。
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct student
{
char name[16]; //姓名
int num; //学号
float score; //成绩
};
int main()
{
struct student stu1;
//通过结构体变量去赋值
strcpy(stu1.name, "李四");
stu1.num = 100;
stu1.score = 101;
//通过结构体指针去赋值
struct student stu2;
struct student* p = &stu2;
strcpy(p->name,"李四");
p->num = 101;
p->score = 98;
printf("%s %d %f", p->name, p->num, p->score);
return 0;
}
结构体嵌套结构体
结构体中的成员可以是另一个结构体。
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct person
{
char name[16];
char sex[5];
int age;
};
struct student
{
struct person stu;
int score;
};
struct teacher
{
struct person tea;
char phone[12];
};
int main()
{
struct student stu1;
strcpy(stu1.stu.name,"张三");
//注意:有两个 .
strcpy(stu1.stu.sex,"男");
stu1.stu.age = 16;
stu1.score = 100;
printf("name = %s sex = %s age = %d score = %d\n", stu1.stu.name, stu1.stu.sex, stu1.stu.age, stu1.score);
return 0;
}
结构体的大小
问题引入:为什么会出现以下结果。
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct A
{
char a;
int b;
char c;
char d;
};
struct B
{
char a;
short b;
char c;
char d;
};
int main()
{
printf("%ld %ld\n", sizeof(int), sizeof(struct A)); //4 12
printf("%ld %ld\n", sizeof(short), sizeof(struct B));//2 6
return 0;
}
字节对齐
字节对齐主要是针对结构体而言的,通常编译器会自动对其成员变量进行对齐,以提高数据存取的效率。
问题引入:计算机每次读取数据都要对取多少字节数据进行判断,十分不便。
struct A
{
char a;//1byte
int b;//4byte
double c;//8byte
};
作用:
平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
结构体大小的计算方法(重要)
1.自身对齐 — 数据类型
2.默认对齐 — 机器
3.有效对齐 — 最终状态
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct A
{ // 自身对齐 默认对齐(32位机) 有效对齐 存放地址(要能整除有效对齐)
char a; //sizeof(char)= 1 4 1(1和4选最小) 0(补1,2,3)
int b; // 4 4 4 4(4,5,6,7)
char c; // 1 4 1 8
char d; // 1 4 1 9(补10,11)
};
//-----------整个字节按有效对齐方式中最大的(4字节)对齐,根据存放地址来看,一共需要12个字节大小-----------------
int main()
{
printf("%d\n", sizeof(struct A));
return 0;
}
位域
位域是把一个字节中的二进制位分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
语法:struct 位域结构体名
{
位域列表
};
位域列表:类型说明符 位域名:位域长度
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct a
{
unsigned char a ;
unsigned char b ;
unsigned char c ;
};
struct A
{
unsigned char a : 2;//两个比特位,最大值11,最大值为3
unsigned char b : 3;
unsigned char c : 3;
};
int main()
{
printf("%d\n", sizeof(struct a));//3
printf("%d\n", sizeof(struct A));//1(节省了两个字节的空间)
//1.先定义再赋值
struct A t;
t.a = 1;//可以把a改成4试试
t.b = 2;
t.c = 3;
printf("%d %d %d\n", t.a, t.b, t.c);
//2.定义变量时进行赋值
struct A t = { 1,2,3 };
printf("%d %d %d\n", t.a, t.b, t.c);
return 0;
}
共用体
引入
问题引入:老师和学生能否应用相同的管理系统?
共用体的定义和使用
在C语言中,不同数据类型的数据可以使用共同的存储区域,这种数据构造类型称为共用体,简称共用,又称联合体。
共用体的定义
union 共用体名
{
共用体成员列表
};
struct person
{
char name[16];
int age;
char sex;
char phone[12];
};
union un
{
int num;
struct person stu;
struct person tea;
};
共用体的使用
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct person
{
char name[16];
int age;
char sex;
char phone[12];
};
union un
{
int num;
char ch;
struct person stu;
struct person tea;
};
int main()
{
//1.定义完赋值
union un u;
u.num = 67;
printf("num = %d ch = %c\n", u.num,u.ch); //num = 67 ch = C (因为C的ASCII码值是67)。ch和num共用一个空间。
//2.定义时赋值
union un u1 = {.stu.name = "张三",.stu.age = 18, };
printf("name = %s age = %d \n",u1.stu.name, u1.stu.age);
return 0;
}
和结构体的区别
共用体三个变量用一个内存空间,结构体分别用三个内存空间。
共用体的大小
问题引入:
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
union A
{
char a; //1字节
int b; //4字节
double c; //8字节
};
//找最大值:8字节(因为union变量共用一个空间)
union B
{
int a; //4字节
char s[7]; //7字节
};
//7不能被4整除,所以是8字节。(字节对齐)
union C
{
char a;
char s[7];
};
//找最大值:7字节
int main()
{
printf("%ld\n", sizeof(union A));
printf("%ld\n", sizeof(union B));
printf("%ld\n", sizeof(union C));
return 0;
}
枚举
枚举的意义
在开发中,有些变量只有几种可能的取值,比如:一周有七天、一年有四季、在枚举的定义中,会将变量一一列出来。
枚举的定义
语法:
enum 枚举名
{
枚举成员列表,
枚举成员列表...
};
注意:不同枚举,成员名不可以一样。
枚举的使用
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
enum week
{
Monday,
Tuesday = 4 ,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
int main()
{
enum e t;
t = Monday;
printf("%d\n", t);//值从0开始
t = Tuesday; //已经对Tuesday进行赋值
printf("%d\n", t);//4
t = Wednesday;
printf("%d\n", t);//5
return 0;
}
//结论:枚举成员从0开始,依次加一,可以对成员进行赋值,后面的成员在其基础上依次加1。
typedef关键字
作用
typedef 是在计算机编程语言中用来为复杂的声明定义简单的别名。
意义
给变量一个易记且意义明确的新名字。
使用
语法:
typedef <已有数据类型> <新数据类型>;
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct person
{
char name[16];
int age;
char sex;
char phone[12];
};
//1.定义结构体后重命名
typedef struct person sp;
//2.定义结构体时直接重命名
typedef union un
{
int num;
char ch;
sp stu;
sp tea;
}a;
int main()
{
a u;
u.num = 67;
printf("num = %d ch = %c\n", u.num, u.ch);
a u1 = { .stu.name = "张三",.stu.age = 18, };
printf("name = %s age = %d \n", u1.stu.name, u1.stu.age);
return 0;
}