day13: 结构体,位域,共用体,枚举,链表操作

This commit is contained in:
flykhan 2023-07-20 09:35:00 +08:00
parent 9e1c7ca87f
commit 7b504aa38b
14 changed files with 696 additions and 0 deletions

View File

@ -17,3 +17,5 @@
#### day11: 动态内存申请,内存泄漏,字符串处理函数
#### day12: 字符串处理函数const结构体
#### day13: 结构体,位域,共用体,枚举,链表操作

99
day13/ANSI_TMP.c Normal file
View File

@ -0,0 +1,99 @@
/*
ANSI转义序列可以用来设置终端中文本的颜色ANSI颜色代码及其对应的颜色值
-
- `\033[30m`
- `\033[31m`
- 绿`\033[32m`
- `\033[33m`
- `\033[34m`
- `\033[35m`
- `\033[36m`
- `\033[37m`
-
- `\033[40m`
- `\033[41m`
- 绿`\033[42m`
- `\033[43m`
- `\033[44m`
- `\033[45m`
- `\033[46m`
- `\033[47m`
ANSI转义序列还可以用来设置其他文本属性线ANSI属性代码及其对应的属性
- `\033[1m`
- 线`\033[4m`
- `\033[5m`
- `\033[7m`
- 使`\033[8m`
使使`\033[31;1m`
ANSI转义序列还可以用来控制终端的显示ANSI控制代码及其对应的操作
- `\033[2J`
- `\033[H` `\033[1;1H`
- n行`\033[nA`
- n行`\033[nB`
- n列`\033[nC`
- n列`\033[nD`
- `\033[?25l`
- `\033[?25h`
ANSI转义序列
- BEL`\a`
- ESC`\e` `\033`
- CSI`\033[`
- OSC`\033]`
OSC代码可以用来向终端发送自定义的命令使OSC代码设置终端的图标
使
*/
#include <stdio.h>
#include <string.h>
typedef enum front_color_e
{
BLACK = 30, // 黑色
RED, // 红色
GREEN, // 绿色
YELLOW, // 黄色
BLUE, // 蓝色
PURPLE, // 紫色
CYAN, // 青色
WHITE, // 白色
} Front_Color; // 前景色
typedef enum back_color_e
{
BLACK_B = 40, // 黑色
RED_B, // 红色
GREEN_B, // 绿色
YELLOW_B, // 黄色
BLUE_B, // 蓝色
PURPLE_B, // 紫色
CYAN_B, // 青色
WHITE_B, // 白色
} Back_Color; // 背景色
typedef enum attr_e
{
BOLD = 1, // 加粗
UNDERLINE = 4, // 下划线
BLINK, // 闪烁
REVERSE = 7, // 反显
HIDE, // 隐藏
} Attr; // 文本属性

19
day13/d1.c Normal file
View File

@ -0,0 +1,19 @@
// 结构体内存分配
#include <stdio.h>
struct stu
{
char sex;
int age;
} lucy;
int main()
{
// 是 8 而不是 5因为结构体内存分配是按照最大的数据类型来分配的
// 即使是 char 类型,也会分配 4 个字节
// 但是如果是数组,就会按照数组的大小来分配
// 例如char name[10],那么就会分配 10 个字节
// 本题中8 = 4 + 4
printf("lucy size: %lu\n", sizeof(lucy));
return 0;
}

19
day13/d2.c Normal file
View File

@ -0,0 +1,19 @@
#include <stdio.h>
struct
{
// short m;
char c[13];
int x[4];
// long y[10];
// int y;
// short c;
// char x;
} p1;
int main()
{
printf("p1 size: %lu B\n", sizeof(p1));
printf("%p %p\n", &p1.c, &p1.x);
return 0;
}

15
day13/d3.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdio.h>
#pragma pack(1) // 手动指定内存对齐,优点:可以减少内存的浪费,缺点:会降低内存的读取速度
struct
{
char a;
short b;
int c;
} p1;
int main()
{
printf("p1 size: %lu B\n", sizeof(p1));
printf("%p %p %p\n", &p1.a, &p1.b, &p1.c);
return 0;
}

24
day13/d4.c Normal file
View File

@ -0,0 +1,24 @@
// 位段: 是啥? 为啥要用?
// 位段: 用来节省内存空间的
// 位段: 用来存储多个不同的数据
// 位段: 用来存储多个不同的数据, 但是这些数据的取值范围都比较小
// 位段的定义: struct 结构体名
// {
// 数据类型 变量名: 位数;
// 数据类型 变量名: 位数;
// };
// 位段的使用: 位段的使用和结构体的使用是一样的
// 位段的注意事项: 位段的位数不能超过数据类型的位数
#include <stdio.h>
struct
{
char a : 3;
short b : 9;
short : 1; // 下一个变量的位段从新的存储单元开始
int c : 19;
} p1;
int main()
{
printf("p1 size: %lu B\n", sizeof(p1));
return 0;
}

33
day13/d5.c Normal file
View File

@ -0,0 +1,33 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct
{
unsigned char a : 2;
unsigned char : 1; // 占位符
unsigned char b : 2;
unsigned char : 1; // 占位符
unsigned char c : 2;
} REG;
int main()
{
REG.a = 3;
REG.b = 1;
REG.c = 2;
printf("%ld B\n", sizeof(REG)); // 1 B
char reg = *((char *)&REG); // 原理: 位段的内存存储是从低位到高位的
printf("%#hhx\n", reg); // 0x11
// 打印二进制
printf("reg = 0b");
for (int i = 7; i >= 0; i--)
{
printf("%d", (reg >> i) & 1);
}
printf("\n");
return 0;
}

39
day13/d6.c Normal file
View File

@ -0,0 +1,39 @@
// 共用体
// 特点:
// 1. 共用体中的所有成员共用一块内存空间
// 2. 共用体的大小是最大成员的大小
// 3. 共用体的成员可以是不同的数据类型
// 只初始化第一个成员
// 不能同时使用其他的成员
// 变量中起作用的只有最后一次赋值
// 在存入一个新的值之前, 会把上一个值覆盖掉
#include <stdio.h>
union data1_uni
{
unsigned char a;
short b;
int c;
} data1, data2;
int main()
{
printf("%ld\n", sizeof(union data1_uni));
data1.a = 10;
data1.c = 20;
printf("a = %d, b = %d, c = %d\n", data1.a, data1.b, data1.c);
union data1_uni data2 = {14};
printf("a = %d, b = %d, c = %d\n", data2.a, data2.b, data2.c);
union data1_uni data3 = {257};
printf("a = %d, b = %d, c = %d\n", data3.a, data3.b, data3.c);
union data1_uni data4;
data4.b = 300;
printf("a = %d, b = %d, c = %d\n", data4.a, data4.b, data4.c);
union data1_uni data5;
data5.c = 32769;
printf("a = %d, b = %d, c = %d\n", data5.a, data5.b, data5.c);
return 0;
}

30
day13/d7.c Normal file
View File

@ -0,0 +1,30 @@
// 共用体和结构体结合使用
// 可以解决不同类型的数据在内存中的存储问题
#include <stdio.h>
struct REG
{
unsigned char a : 1; // 低位
unsigned char b : 1;
unsigned char c : 1;
unsigned char d : 1;
unsigned char e : 1;
unsigned char f : 1;
unsigned char g : 1;
unsigned char h : 1; // 高位
};
union REG_UNI
{
struct REG reg;
unsigned char ch;
};
int main()
{
union REG_UNI reg1 = {{1, 0, 0, 0, 1, 0, 0, 0}};
// reg1.ch 可以把每一位的值都取出来,但是不能修改,读取顺序是从低位到高位,倒序读取 0b00001001
printf("%#x\n", reg1.ch); // 0x11
return 0;
}

43
day13/d8.c Normal file
View File

@ -0,0 +1,43 @@
// 枚举 enum
#include <stdio.h>
typedef enum front_color_e
{
BLACK = 30, // 黑色
RED, // 红色
GREEN, // 绿色
YELLOW, // 黄色
BLUE, // 蓝色
PURPLE, // 紫色
CYAN, // 青色
WHITE, // 白色
} Front_Color; // 前景色
typedef enum back_color_e
{
BLACK_B = 40, // 黑色
RED_B, // 红色
GREEN_B, // 绿色
YELLOW_B, // 黄色
BLUE_B, // 蓝色
PURPLE_B, // 紫色
CYAN_B, // 青色
WHITE_B, // 白色
} Back_Color; // 背景色
typedef enum attr_e
{
BOLD = 1, // 加粗
UNDERLINE = 4, // 下划线
BLINK, // 闪烁
REVERSE = 7, // 反显
HIDE, // 隐藏
} Attr; // 文本属性
int main()
{
// 彩色字体测试
printf("\033[%d;%d;%dmHello, \033[0m\033[%d;%d;%dmworld!\033[0m \n", BOLD, RED, CYAN_B, GREEN, WHITE_B, UNDERLINE);
return 0;
}

92
day13/d9.c Normal file
View File

@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdlib.h>
// 定义学生信息的数据结构,链表的节点
typedef struct stu_s
{
char sid;
char name[32];
int age;
struct stu_s *next;
} STU;
void shows(STU *head)
{
STU *pi = head;
printf("学号\t姓名\t年龄\n");
while (NULL != pi)
{
printf("%d\t%s\t%d\n", pi->sid, pi->name, pi->age);
pi = pi->next;
}
}
STU *insert_head(STU *head, STU *item)
{
printf("2 %p\n", head);
// 实现头部插入
if (NULL == head) // 如果是第一个节点(空链表)
{
head = item;
}
else
{
item->next = head; // 新节点指向原来的头节点
head = item; // item 变成新的头节点
}
printf("3 %p\n", head);
return head; // 返回头节点,头指针不能改变
}
STU *insert_end(STU *head, STU *item)
{
// 实现尾部插入
if (NULL == head) // 如果是第一个节点(空链表)
{
head = item;
}
else
{
STU *pi = head;
while (NULL != pi->next)
{
pi = pi->next;
}
pi->next = item;
}
return head; // 返回头节点,头指针不能改变
}
int main()
{
// 静态生成学生信息的链表
STU s1 = {1, "张三", 18, NULL}; // 头节点: 参数说明: 学号, 姓名, 年龄, 下一个节点的地址
STU s2 = {2, "李四", 19, NULL};
STU s3 = {3, "王五", 20, NULL};
STU *head = &s1; // 头节点
s1.next = &s2; // 头节点指向第二个节点
s2.next = &s3; // 第二个节点指向第三个节点
s3.next = NULL; // 第三个节点指向空
STU s4 = {4, "赵六", 21};
head = insert_head(head, &s4); // 头插法,地址会改变,需要返回头节点,主函数需要接收
printf("1 %p\n", head);
shows(head);
// insert_end(head, &(STU){5, "孙七", 22, NULL});
head = insert_head(head, &(STU){5, "孙七", 22, NULL}); // 临时变量,存在栈中,函数结束后会被释放,需要返回头节点,主函数需要接收
printf("1 %p\n", head);
shows(head);
return 0;
}

107
day13/d9_2.c Normal file
View File

@ -0,0 +1,107 @@
#include <stdio.h>
#include <stdlib.h>
// 定义学生信息的数据结构,链表的节点
typedef struct stu_s
{
char sid;
char name[32];
int age;
struct stu_s *next;
} STU;
void shows(STU *head)
{
STU *pi = head;
printf("学号\t姓名\t年龄\n");
while (NULL != pi)
{
printf("%d\t%s\t%d\n", pi->sid, pi->name, pi->age);
pi = pi->next;
}
}
STU *insert_head(STU *head, STU new_stu)
{
// 动态创建新节点
STU *new_node = (STU *)malloc(sizeof(STU));
*new_node = new_stu;
// 实现头部插入
if (NULL == head) // 如果是第一个节点(空链表)
{
head = new_node;
}
else
{
// 头结点变第二个节点,新节点变头结点
new_node->next = head; // 新节点指向头节点
head = new_node; // 头指针指向新节点
}
return head; // 返回头节点,头指针不能改变
}
STU *insert_end(STU *head, STU *item)
{
// 实现尾部插入
if (NULL == head) // 如果是第一个节点(空链表)
{
head = item;
}
else
{
STU *pi = head;
while (NULL != pi->next)
{
pi = pi->next;
}
pi->next = item;
}
return head; // 返回头节点,头指针不能改变
}
STU *insert_sort(STU *head, STU *item)
{
if (NULL == head)
return item;
if (head->age > item->age)
{
item->next = head;
head = item;
}
else
{
STU *pi = head;
while (NULL != pi->next && pi->next->age < item->age)
{
pi = pi->next;
}
item->next = pi->next;
pi->next = item;
}
return head;
}
int main()
{
// 静态生成学生信息的链表
STU s1 = {1, "张三", 18, NULL}; // 头节点: 参数说明: 学号, 姓名, 年龄, 下一个节点的地址
STU s2 = {2, "李四", 19, NULL};
STU s3 = {3, "王五", 20, NULL};
STU *head = NULL; // 头节点
head = insert_sort(head, &s1);
head = insert_sort(head, &s2);
head = insert_sort(head, &s3);
head = insert_sort(head, &(STU){4, "赵六", 17, NULL});
shows(head);
return 0;
}

88
day13/d9_3_delete.c Normal file
View File

@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdlib.h>
// 定义学生信息的数据结构,链表的节点
typedef struct stu_s
{
char sid;
char name[32];
int age;
struct stu_s *next;
} STU;
void shows(STU *head)
{
STU *pi = head;
printf("学号\t姓名\t年龄\n");
while (NULL != pi)
{
printf("%d\t%s\t%d\n", pi->sid, pi->name, pi->age);
pi = pi->next;
}
}
STU *delete_stu(STU *head, char sid)
{
if (NULL == head)
{
printf("链表为空,无法删除\n");
return NULL;
}
if (head->sid == sid)
{
// 如果 head 节点的内存是在堆区分配的,那么需要释放
// STU *tmp = head;
head = head->next;
// free(tmp);
// return head;
}
else
{
STU *pi = head;
while (NULL != pi->next && pi->next->sid != sid)
{
pi = pi->next;
}
// 如果没有找到删除的节点
if (NULL == pi->next)
{
printf("没有找到要删除的节点\n");
return head;
}
// 找到了要删除的节点
STU *pn = pi->next; // 要删除的节点
pi->next = pn->next; // 要删除的节点的前一个节点指向要删除的节点的后一个节点
free(pn); // 释放要删除的节点
printf("删除成功\n");
// return head;
}
return head;
}
int main()
{
// 静态生成学生信息的链表
STU s1 = {1, "张三", 18, NULL}; // 头节点: 参数说明: 学号, 姓名, 年龄, 下一个节点的地址
STU s2 = {2, "李四", 19, NULL};
STU s3 = {3, "王五", 20, NULL};
STU *head = &s1; // 头节点
s1.next = &s2; // 头节点指向第二个节点
s2.next = &s3; // 第二个节点指向第三个节点
s3.next = NULL; // 第三个节点指向空
printf("1 %p\n", head);
shows(head);
head = delete_stu(head, 1);
printf("1 %p\n", head);
shows(head);
return 0;
}

86
day13/d9_4_find.c Normal file
View File

@ -0,0 +1,86 @@
#include <stdio.h>
#include <stdlib.h>
// 定义学生信息的数据结构,链表的节点
typedef struct stu_s
{
char sid;
char name[32];
int age;
struct stu_s *next;
} STU;
void shows(STU *head)
{
STU *pi = head;
printf("学号\t姓名\t年龄\n");
while (NULL != pi)
{
printf("%d\t%s\t%d\n", pi->sid, pi->name, pi->age);
pi = pi->next;
}
}
STU *find_stu(STU *head, char sid)
{
if (NULL == head)
{
printf("链表为空,无法查找\n");
return NULL;
}
if (head->sid == sid)
{
return head;
}
else
{
STU *pi = head;
while (NULL != pi->next && pi->next->sid != sid)
{
pi = pi->next;
}
// 如果没有找到删除的节点
if (NULL == pi->next)
{
printf("没有找到要查找的节点\n");
return NULL;
}
// 找到了要删除的节点
STU *pn = pi->next; // 要删除的节点
return pn;
}
}
int main()
{
// 静态生成学生信息的链表
STU s1 = {1, "张三", 18, NULL}; // 头节点: 参数说明: 学号, 姓名, 年龄, 下一个节点的地址
STU s2 = {2, "李四", 19, NULL};
STU s3 = {3, "王五", 20, NULL};
STU *head = &s1; // 头节点
s1.next = &s2; // 头节点指向第二个节点
s2.next = &s3; // 第二个节点指向第三个节点
s3.next = NULL; // 第三个节点指向空
shows(head);
STU *item = find_stu(head, 2);
if (NULL != item)
{
printf("找到了\n");
printf("%d\t%s\t%d\n", item->sid, item->name, item->age);
}
else
{
printf("没有找到\n");
}
// shows(head);
return 0;
}