结构体: 是一个构造数据类型
- 引入: 描述一个人
- 姓名name 性别sex 年龄age 身高 high
- char[20] char[10] int float
- 有编程者 先定义一个结构体类型 然后利用定义的类型 定义变量
- 成员: 结构体中的 数据对象 称 成员
1. 定义一个 人 结构体类型
struct 类型名
{//成员表
成员类型 成员名;
char sex[10];
int age;
float high;
};
示例:
struct people
{//成员表
char name[20];
char sex[10];
int age;
float high;
};
2. 使用类型定义变量
//用结构体类型 定义变量 才会分配内存空间
struct people zhang3;
//定义变量并初始化
struct people li4 = { "李4" , "男" , 18 , 1.80 };
3. 结构体变量 成员引用
- . 成员引用运算符
- 结构体变量名.成员名 ;
- 结构体变量 类型相同可以直接赋值;
4. 结构体指针
- 一个指针指向一个结构体
- 通过结构体指针 访问结构体
- -> 结构体指针成员引用运算符
5. 类型别名 给类型取别名
- typedef 原类型名 别名;
- //定义类型别名
- typedef struct people ren_t;
- typedef struct people * ren_p;
定义类型同时就取别名
typedef struct people
{//成员表
char name[20];
char sex[10];
int age;
float high;
} ren_t ;
定义类型同时就定义变量
struct people
{//成员表
char name[20];
char sex[10];
int age;
float high;
} zhang3;
定义类型同时就定义变量同时初始化
struct people
{//成员表
char name[20];
char sex[10];
int age;
float high;
} zhang3 = {"张三" , "男" , 18 , 1.80};
关于结构体的类型:
- 结构体的类型 由定义结构体类型时给定的名字决定, 名字不同则 类型不同
无名结构体:
struct
{//成员表
char name[20];
char sex[10];
int age;
float high;
} zhang3;
结构体存储模型:
- 1.结构体类型 成员顺序 在内存中 按同样顺序排列
- 2.遵循紧凑排列
- 3.默认遵循 自动字节对齐
字节对齐:
- 计算机为了 方便快速找到一个变量的位置 因此而引入字节对齐
- 多字节类型(int,short) 要求其首地址 应该能够被 其长度 整除
- #pragma pack (2) /*指定按2字节对齐,后面定义的结构体均遵循这个规则*/
- #pragma pack () /*取消指定对齐,恢复缺省对齐 自动字节对齐*/
结构体数组 :
- 本质一个数组 其元素是 结构体
- struct people arr[5];
- 0号元素的name arr[0].name
结构体指针数组
- 本质一个数组 其元素 结构体指针
- struct people *arr[5];
- 0号元素的name arr[0]->name
结构体数组指针
- 本质一个指针 指向 一个数组 数组元素是结构体
- struct people (*p)[5];
- 访问p指向的数组中的 0号 结构体中的 name
- (*p)[0].name ;
结构体中的成员是一个结构体:(链表)
struct stu
{
struct people ren;
int id;
};
struct stu zhang3;
zhang3.ren.name;
struct people
{//成员表
char name[20];
char sex[10];
int age;
float high;
struct people *next;
};
共用体:
- 跟结构体类似, 区别在于 共用体成员 共用 同一块内存空间
- 其占用内存大小由 最大空间的那个成员决定
定义 共用体类型 :
- union 共用体类型名
- {
- 成员类型 成员名;
- ....};
定义共用体变量:
- union 共用体类型名 变量名;
- 案例:
- 写一个函数 实现 两个数求和
- 这两个数 有可能是int型 也有可能是 float
定义一个共用体类型
union num_t
{
int i_t;
float f_t;
char c_t;
};
共用体应用案例
struct msg
{
int type; //存放消息类型
union num_t // 共用体 存储消息本身
{
int i_t;
float f_t;
char c_t;
};
};
枚举类型: 参考示例
//定义一个枚举类型 描述 type 给常量取别名 优于宏定义会进行语法检查
enum type_t
{
type_int = 0,
type_float = 1,
type_char = 2
};
对常量进行 取别名
enum 类型名
{
常量表;
};
动态内存分配:
- 就是向操作系统 申请堆区内存
- 可以在程序运行中 动态的 申请你想要的大小
内存的申请 与 释放:
#include <stdlib.h>
void *malloc(size_t size); //申请内存
void free(void *ptr); //释放内存
- size: 要申请的内存大小 单位字节
- void *: 返回值 是一个无类型指针
- 申请成功时 该指针指向 你申请的堆区内存
- 申请失败 返回 NULL指针
- 使用堆区内存时, 必须先将堆区内存地址 强制转换为 你要的内存
- 然后才能访问
- ptr: 你申请时 系统给的堆区地址, 释放是需要作为free的参数
关于申请与释放 注意事项:
- 1. 申请时 给的堆区地址, 在没有释放前,不能丢失(p=NULL)
- 丢失堆区指针,将导致 内存泄漏
- 生命周期 从申请开始 到释放结束
- 2. 已经释放的 堆区内存 不能再访问了 继续访问 则段错误
- 3. 不能重复释放
- 4. 不能部分释放
通常 malloc 申请的空间
struct people* p = (struct people*)malloc(sizeof(struct people));
p->name
练习:
申请一个结构体大小的堆区空间 输入 一个struct people 类型的结构体
makefile工程管理器: 用于辅助编译的工具
- 对多文件编译时, 可以自动 对改变的.c文件进行 重新编译
- 通过对 文件的 时间戳 来判断.c文件与.o的新旧 来确定是否需要重新编译
使用:
- make
- make 目标
- 编写makefile,来配置工程管理器的编译过程
编写规则:
- 目标:依赖
- <table>shell命令 用于将依赖编译为 目标文件的 shell命令
变量定义:
- shell定义变量类似
- 变量名 = 值
自动变量:
- $* 不包含扩展名的目标文件名称
- $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件
- $< 第一个依赖文件的名称
- $? 所有时间戳比目标文件晚的的依赖文件,并以空格分开
- $@ 目标文件的完整名称
- $^ 所有不重复的目标依赖文件,以空格分开
- $% 如果目标是归档成员,则该变量表示目标的归档成员名称
参考 示例 makefile
项目: C语言 字符界面象棋
棋盘: 二维数组 结构体 *arr[10][9]
棋子: 属性 结构体
颜色
字面
坐标
状态 生死
规则:
判断输赢: