保存你们信息:
姓名char name[20];
性别char sex[10];
年龄int age;
学号int id;
成绩float score;
但是这些数据是独立吧,而这些信息是学生整体一部分,希望能封装成一个整体的类型
用该类型表示一个 从学生。
----->结构体
1、结构体
人为构造一种组合数据类型,可以包含很多其他类型
(1) 怎么声明结构体类型
用关键字 struct 来声明结构体类型
具体语法:
struct 结构体名
{
成员类型1 成员变量名1;
成员类型2 成员变量名2;
.........
};
结构体类型一般声明为全局,特殊情况下可以声明为局部的
结构体名、成员变量名 只要符合C语言标识符规定就 ok
成员类型 只要合法就 ok
struct student
{
char name[20];
char sex[10];
int age;
int id;
float score;
//.....
};
声明好了之后,就可以使用这个类型(struct 结构体名),
怎么使用,和 int char ...... 一样
类型在什么时候用?
定义变量时用
函数返回值类型
强制转换
....
怎么定义一个结构体变量?
结构体类型 结构体变量名;
// 类型变量名
int a;
struct student stu;
struct student 是结构体类型 ,stu 结构体变量的名字
这个变量 stu 有5部分, 分别是 name、sex、age、id、score
怎么 通过结构体变量去访问该变量的各个成员变量
(2)结构体成员变量的访问
a.通过结构体变量去访问成员变量
结构体变量名.成员变量名;
// stu.name = "张三"; 错的
// stu.sex = "男";错的
strncpy(stu.name,"张三",19);
strncpy(stu.sex,"男",9);
stu.age = 18;
stu.id = 36;
stu.score = 100;
b.通过结构体指针去访问成员变量
(* 结构体指针变量).成员变量名; ---> 不常用
struct student * p;
p = &stu;
strncpy((*p).name,"张三",19);
strncpy((*p).sex,"男",9);
(*p).age = 18;
(*p).id = 36;
(*p).score = 100;
结构体指针变量->成员变量名;---> 推荐使用
p->age = 18;
p->id = 36;
p->score = 100;
strncpy(p->name,"张三",19);
strncpy(p->sex,"男",9);
练习:
定义一个"学生"类型变量,从键盘输入它的各个成员变量,最后打印出来
(3)结构体变量初始化
初始化用 {}
①{} 把结构体所有的成员变量的初始值按顺序依次写上,',' 隔开
struct student stu = {"zhangsan","男",18,36,76};
②不按顺序:
struct student stu = {.age = 18,.id = 36,.score = 76};
定义结构体数组
struct student s[3];
// s 是一个数组,3 个元素, 每个元素都是 结构体类型
结构体数组初始化
a.
struct student s[3] = {{....},{....},{....}};
b.
struct student s[3] = {[2] = {....}}; // 只给 s[2] 初始化
(4)结构体变量间直接整体赋值
struct student stu1 = {"zhangsan",18,35,76};
struct student stu2 ;
stu2 = stu1;//相当于下面四句话
//stu2.name = stu1.name; 错的
strcpy(stu2.name,stu1.name);
stu2.age = stu1.age;
stu2.id = stu1.id;
stu2.score = stu1.score;
(5)结构体成员内存布局
struct student
{
char name[20];// 名字20
int age;// 年龄4
int id;// 学号4
double score;// 成绩8
//.....
};
sizeof(struct student) ---> 40
结构体变量的大小不是简单的各个成员变量的所占大小和
因为要考虑到 "字节对齐"
字节对齐 是 从 cpu 寻址的效率上考虑的
字节对齐的方式不是固定的,跟硬件平台或操作系统有关系
我们的设备对齐方式是 每个结构与变量的地址 都要是4的倍数
结构体变量每个成员变量的地址都要能被它自己所占的内存大小整除
并且整个结构体变量的大小要能够被它各个成员变量中最大的那个整除
(如果成员变量中有组合类型,应该要把组合类型分开看)
struct test1
{
char a;
char b;
int c;
};----> 8字节
xx--xxxx
struct test2
{
char a;
int c;
char b;
};----> 12字节
x---xxxxx---
struct student
{
char name[20];// 名字20
int age;// 年龄4
int id;// 学号4
double score;// 成绩8
//.....
};
[xxxx xxxx] [xxxx xxxx] [xxxx xxxx(age)] [xxxx(id) ----] [xxxx xxxx]
2、共用体(联合体)
关键字 union 声明共用体
union 共用体名
{
成员类型1 成员变量名1;
成员类型2 成员变量名2;
.........
};
共用体的声明和结构体差不多,就是关键字不一样
定义共用体变量和结构体类似,就是关键字不一样
访问成员变量的方式和结构体一样
例:
union test
{
char ch1;
char ch2;
int a;
};
int main()
{
union test t;// t 共用体变量
t.ch1 = 'a';
union test *p;
p = &t;
p->a = 5;
}
不同的是:
共用体多大个成员变量共用一块内存,各个成员变量的地址是相同的
union test
{
char ch1;
char ch2;
int a;
};
printf("%p\n%p\n%p\n",&t.ch1,&t.ch2,&t.a);
可以发现地址都一样
数据存储两种模式,大小端模式
如果数据超过一个字节,就会存在一个问题:
低字节的数据存低地址内存还是存高地址内存
高字节的数据存低地址内存还是存高地址内存
大端模式:高字节的数据存低地址内存,低字节的数据存高地址内存
小端模式:低字节的数据存低地址内存,高字节的数据存高地址内存
练习:
用程序验证电脑是哪个模式
①union test
{
char c;
int a;
};
int main()
{
union test t;// t 共用体变量
t.a = 0x11223344;
if(t.c == 0x11)
{
printf("大端模式\n");
}
else
{
printf("小端模式\n");
}
}
②
int n = 0x12345678;
char * p = (char *)&n;
if(*p == 0x12)
{
printf("大端模式\n");
}
else
{
printf("小端模式\n");
}
共用体适用于 各个成员变量不会同时使用的情况,这样做相比于结构体节省空间
3、枚举
把该类型的变量的所有值列举出来
为该类型变量赋值,原则上只能是列举出来的这些值
有些时候,某个变量的值有范围
int a;// 用来表示一个方向
// 1 是 上;2 是 下;3左;4右
if(a == 1)
{
// 上 相关操作
}
.....
这样写可以,但是会出现一些问题,可能在给a值不小心赋了其他值 a = 88;
还有就是忘记代表的意思
--> 使用枚举类型
怎么声明?
enum 枚举名{标识符1,标识符2....};
如:
enum dir{UP,DOWN,LEFT,RIGHT};
定义枚举变量
enum dir a;// 定义了一个枚举变量名,它的值原则上只能是UP,DOWN,LEFT,RIGHT
if(a == UP)
{
...
}
.....
枚举的本质是一个整数,占一个字节,
如果没有初值,分别对应 0,1,2,3,4.....
enum dir{UP,DOWN,LEFT,RIGHT};
0 1 2 3
也可以给一个初值
enum dir{UP = 3,DOWN,LEFT,RIGHT};
3 4 5 6
enum dir{UP,DOWN,LEFT = 8,RIGHT};
0 1 8 9
4、typedef 关键字
作用: 给一个已经有的类型取一个新名字
typedef int ni666;// 给 int 取了个新名字 ni666
int a;
ni666 b;// int b;
给结构体加名字使用多
struct student
{
char name[20];// 名字
int age;// 年龄
int id;// 学号
double score;// 成绩
//.....
};
typedef struct student Stu;// struct student 有了新名字叫 Stu
typedef struct student
{
char name[20];// 名字
int age;// 年龄
int id;// 学号
double score;// 成绩
//.....
}Stu;// 声明了一个结构体类型,并且给了个别名
struct student
{
char name[20];// 名字
int age;// 年龄
int id;// 学号
double score;// 成绩
//.....
}stu;// 声明了一个结构体类型,并且 定义一个结构体变量
bool
enum bool{false,true};
#include <stdbool.h>
包含了头文件 bool
多思考一下
作业:(选做)
定义一个 struct student 数组保存 学生信息,输入各个元素的数据,然后按照 成绩对数组进行排序