学生管理系统 添加文本存储读取; 文件读写复制练习
This commit is contained in:
parent
44331f7bba
commit
5408f0b622
|
@ -0,0 +1,43 @@
|
||||||
|
// 随机生成10位学生的成绩并写入到score.txt文件中
|
||||||
|
// 【要求】随机生成学号和成绩,每一行存储一位学生的成绩,学号与成绩之间用 ","逗号分隔。
|
||||||
|
// 【提示】成绩范围[0, 100]
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct stu_s
|
||||||
|
{
|
||||||
|
int sid;
|
||||||
|
char dh; // 逗号
|
||||||
|
float score;
|
||||||
|
|
||||||
|
struct stu_s *next;
|
||||||
|
} STU;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FILE *fp = fopen("score.txt", "w");
|
||||||
|
srand(time(NULL));
|
||||||
|
// float scorex = rand() % 101;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (NULL == fp)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
STU *stu = malloc(sizeof(STU));
|
||||||
|
|
||||||
|
stu->sid = i + 1;
|
||||||
|
stu->dh = ','; // 间隔的逗号
|
||||||
|
stu->score = rand() % 101;
|
||||||
|
fwrite(stu, sizeof(STU), 1, fp);
|
||||||
|
// fputc('\n', fp); // 添加换行
|
||||||
|
|
||||||
|
free(stu);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// 按行读取score.txt文件的所有内容,打印成绩及格的学号和成绩。
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct stu_s
|
||||||
|
{
|
||||||
|
int sid;
|
||||||
|
char dh; // 逗号
|
||||||
|
float score;
|
||||||
|
|
||||||
|
struct stu_s *next;
|
||||||
|
} STU;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FILE *fp = fopen("score.txt", "r");
|
||||||
|
|
||||||
|
if (NULL == fp)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算文件大小
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long file_size = ftell(fp);
|
||||||
|
printf("score.txt 文件大小: %ld B\n", file_size);
|
||||||
|
|
||||||
|
// 重置光标位置
|
||||||
|
fseek(fp, 0, SEEK_SET); // 等同于使用 rewind(fp);
|
||||||
|
// 按照 STU 的结构存储数据,计算出以存放学生数量
|
||||||
|
int stu_num = file_size / sizeof(STU);
|
||||||
|
printf("学生数量: %d\n", stu_num);
|
||||||
|
|
||||||
|
printf("\n学号\t成绩\n");
|
||||||
|
for (int i = 0; i < stu_num; i++)
|
||||||
|
{
|
||||||
|
STU *s = calloc(1, sizeof(STU));
|
||||||
|
fread(s, sizeof(STU), 1, fp);
|
||||||
|
if (s->score > 60)
|
||||||
|
printf("%d\t%.2f\n", s->sid, s->score);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
// 按行读取score.txt文件的所有内容,并生成有序的链表,且打印链表数据。
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct stu_s
|
||||||
|
{
|
||||||
|
int sid;
|
||||||
|
char dh; // 逗号
|
||||||
|
float score;
|
||||||
|
|
||||||
|
struct stu_s *next;
|
||||||
|
} STU;
|
||||||
|
|
||||||
|
// 打印链表
|
||||||
|
void show(STU *head)
|
||||||
|
{
|
||||||
|
if (NULL == head)
|
||||||
|
{
|
||||||
|
printf("数据为空,无法打印\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
STU *tp = head;
|
||||||
|
printf("\n学号\t成绩\n");
|
||||||
|
while (NULL != tp)
|
||||||
|
{
|
||||||
|
printf("%d\t%.2f\n", tp->sid, tp->score);
|
||||||
|
tp = tp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加学生
|
||||||
|
STU *insert_stu(STU *head, STU *item)
|
||||||
|
{
|
||||||
|
// 如果头指针为空,说明链表为空,直接将新建的节点作为头指针
|
||||||
|
if (head == NULL)
|
||||||
|
{
|
||||||
|
head = item;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果头指针不为空,说明链表不为空,需要找到链表的尾部,将新建的节点插入到尾部
|
||||||
|
STU *p = head; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (p->next != NULL) // 当 p 的下一个节点不为空时,说明 p 不是尾部
|
||||||
|
{
|
||||||
|
p = p->next; // p 一直向后移动,直到找到尾部
|
||||||
|
}
|
||||||
|
p->next = item; // 将 item 插入到尾部
|
||||||
|
}
|
||||||
|
return head; // 返回头指针
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FILE *fp = fopen("score.txt", "r");
|
||||||
|
|
||||||
|
if (NULL == fp)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
STU *head = NULL; // 建立链表头节点
|
||||||
|
|
||||||
|
// 计算文件大小
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long file_size = ftell(fp);
|
||||||
|
printf("score.txt 文件大小: %ld B\n", file_size);
|
||||||
|
|
||||||
|
// 重置光标位置
|
||||||
|
fseek(fp, 0, SEEK_SET); // 等同于使用 rewind(fp);
|
||||||
|
// 按照 STU 的结构存储数据,计算出以存放学生数量
|
||||||
|
int stu_num = file_size / sizeof(STU);
|
||||||
|
printf("学生数量: %d\n", stu_num);
|
||||||
|
|
||||||
|
// printf("\n学号\t成绩\n");
|
||||||
|
for (int i = 0; i < stu_num; i++)
|
||||||
|
{
|
||||||
|
// 为新的链表节点分配内存空间
|
||||||
|
STU *s = calloc(1, sizeof(STU));
|
||||||
|
// 从文件中读取一个学生的数据
|
||||||
|
fread(s, sizeof(STU), 1, fp);
|
||||||
|
|
||||||
|
head = insert_stu(head, s); // 插入链表节点
|
||||||
|
}
|
||||||
|
show(head); // 显示链表内容
|
||||||
|
|
||||||
|
// 最后循环释放动态申请的内存
|
||||||
|
STU *free_tp = head;
|
||||||
|
while (free_tp != NULL)
|
||||||
|
{
|
||||||
|
STU *to_free_this_p = free_tp;
|
||||||
|
free_tp = free_tp->next;
|
||||||
|
free(to_free_this_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
// 从score.txt中查找所有大于90分的学生信息(学号、成绩),并统计学生的数量和平均成绩。
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct stu_s
|
||||||
|
{
|
||||||
|
int sid;
|
||||||
|
char dh; // 逗号
|
||||||
|
float score;
|
||||||
|
|
||||||
|
struct stu_s *next;
|
||||||
|
} STU;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
FILE *fp = fopen("sxxx.dest", "rb");
|
||||||
|
// FILE *fp = fopen("score.txt", "r");
|
||||||
|
|
||||||
|
if (NULL == fp)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算文件大小
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long file_size = ftell(fp);
|
||||||
|
printf("score.txt 文件大小: %ld B\n", file_size);
|
||||||
|
|
||||||
|
// 重置光标位置
|
||||||
|
fseek(fp, 0, SEEK_SET); // 等同于使用 rewind(fp);
|
||||||
|
// 按照 STU 的结构存储数据,计算出以存放学生数量
|
||||||
|
int stu_num = file_size / sizeof(STU);
|
||||||
|
printf("学生数量: %d\n", stu_num);
|
||||||
|
|
||||||
|
int above_90_stu_nums = 0; // 大于 90 分的学生数
|
||||||
|
float sum_score_of_above_90_stus = 0.0f; // 大于 90 分学生的总成绩
|
||||||
|
|
||||||
|
// printf("\n学号\t成绩\n");
|
||||||
|
for (int i = 0; i < stu_num; i++)
|
||||||
|
{
|
||||||
|
// 为新的链表节点分配内存空间
|
||||||
|
STU *s = calloc(1, sizeof(STU));
|
||||||
|
// 从文件中读取一个学生的数据
|
||||||
|
fread(s, sizeof(STU), 1, fp);
|
||||||
|
|
||||||
|
if (s->score > 90)
|
||||||
|
{
|
||||||
|
above_90_stu_nums++;
|
||||||
|
// printf("%.2f\n", s->score);
|
||||||
|
sum_score_of_above_90_stus += s->score;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
float avg_score_of_above_90_stus = sum_score_of_above_90_stus / above_90_stu_nums;
|
||||||
|
printf("\n大于 90 分的学生有 %d 位,他们的平均成绩为 %.2f\n", above_90_stu_nums, avg_score_of_above_90_stus);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
// 设计函数, int filecpy(char *src_file, char *dst_file)的功能,实现文件src_file备份到dst_file, 如果成功返回 0, 失败返回 1
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int filecpy(char *src_file, char *dst_file)
|
||||||
|
{
|
||||||
|
FILE *aF = fopen(src_file, "rb");
|
||||||
|
FILE *bF = fopen(dst_file, "wb");
|
||||||
|
|
||||||
|
if (NULL == aF)
|
||||||
|
{
|
||||||
|
perror("src_file fopen");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (NULL == bF)
|
||||||
|
{
|
||||||
|
perror("dst_file fopen");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int temp_c = fgetc(aF);
|
||||||
|
while (temp_c != EOF)
|
||||||
|
{
|
||||||
|
fputc(temp_c, bF);
|
||||||
|
temp_c = fgetc(aF);
|
||||||
|
}
|
||||||
|
fclose(aF);
|
||||||
|
fclose(bF);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
filecpy("score.txt", "sxxx.dest");
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,523 @@
|
||||||
|
// 优化昨天的学生信息管理系统,将STU的数据持久化到stu.data文件中
|
||||||
|
// 【提示】运行程序时,从文件中加载已有数据并生成链表,在退出程序时,将链表的数据更新到文件中。
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h> // malloc
|
||||||
|
#include <string.h> // strcpy
|
||||||
|
|
||||||
|
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; // 文本属性
|
||||||
|
|
||||||
|
// 定义学生信息结构体,链表的节点
|
||||||
|
typedef struct stu_s
|
||||||
|
{
|
||||||
|
int sid;
|
||||||
|
char name[32];
|
||||||
|
int age;
|
||||||
|
|
||||||
|
struct stu_s *next;
|
||||||
|
} STU;
|
||||||
|
|
||||||
|
// 节点交换
|
||||||
|
void swap(STU *a, STU *b)
|
||||||
|
{
|
||||||
|
// 方法一: 直接通过临时指针交换数据
|
||||||
|
// STU *tp = (STU *)malloc(sizeof(STU));
|
||||||
|
// tp->sid = a->sid;
|
||||||
|
// strcpy(tp->name, a->name);
|
||||||
|
// tp->age = a->age;
|
||||||
|
|
||||||
|
// a->sid = b->sid;
|
||||||
|
// strcpy(a->name, b->name);
|
||||||
|
// a->age = b->age;
|
||||||
|
|
||||||
|
// b->sid = tp->sid;
|
||||||
|
// strcpy(b->name, tp->name);
|
||||||
|
// b->age = tp->age;
|
||||||
|
// free(tp); // 释放临时指针
|
||||||
|
|
||||||
|
// 方法二: 通过结构体指针交换数据
|
||||||
|
// 先换数据
|
||||||
|
STU *tp = malloc(sizeof(STU));
|
||||||
|
*tp = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = *tp;
|
||||||
|
|
||||||
|
// 再换指针的下一个节点指向
|
||||||
|
tp->next = a->next;
|
||||||
|
a->next = b->next;
|
||||||
|
b->next = tp->next;
|
||||||
|
|
||||||
|
free(tp); // 释放临时指针
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加学生
|
||||||
|
STU *insert_stu(STU *head, STU *item)
|
||||||
|
{
|
||||||
|
// 如果头指针为空,说明链表为空,直接将新建的节点作为头指针
|
||||||
|
if (head == NULL)
|
||||||
|
{
|
||||||
|
head = item;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果头指针不为空,说明链表不为空,需要找到链表的尾部,将新建的节点插入到尾部
|
||||||
|
STU *p = head; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (p->next != NULL) // 当 p 的下一个节点不为空时,说明 p 不是尾部
|
||||||
|
{
|
||||||
|
p = p->next; // p 一直向后移动,直到找到尾部
|
||||||
|
}
|
||||||
|
p->next = item; // 将 item 插入到尾部
|
||||||
|
}
|
||||||
|
return head; // 返回头指针
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除学生
|
||||||
|
STU *delete_stu(STU *head, char sid)
|
||||||
|
{
|
||||||
|
if (NULL == head)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无数据,无法删除\033[0m\n", RED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (head->sid == sid)
|
||||||
|
{
|
||||||
|
// *tp 为临时指针,用来保存头指针
|
||||||
|
STU *tp = head; // 保存头指针
|
||||||
|
head = head->next; // 头指针指向下一个节点
|
||||||
|
free(tp); // 释放头指针
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
STU *tp = head; // 保存头指针
|
||||||
|
while (NULL != tp->next && sid != tp->next->sid) // 当 tp 的下一个节点不为空时,且下一个节点的学号不等于要删除的学号时,继续向后移动指针 tp
|
||||||
|
{
|
||||||
|
tp = tp->next; // tp 一直向后移动,直到找到尾部
|
||||||
|
}
|
||||||
|
if (NULL == tp->next) // 到达了链表尾部还是没有找到要删除的内容
|
||||||
|
{
|
||||||
|
printf("\033[%dm未找到 sid = %d 的学生,删除失败\033[0m\n", RED, sid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
STU *tpx = tp->next; // 保存要删除的节点
|
||||||
|
tp->next = tpx->next; // 将链表位置指向要删除的节点的下一个节点
|
||||||
|
free(tpx); // 释放要删除的节点
|
||||||
|
printf("\033[%dm删除 sid = %d 的学生成功\033[0m\n", BLUE, sid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return head; // 返回头指针
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印学生
|
||||||
|
void shows(STU *head)
|
||||||
|
{
|
||||||
|
// 如果头指针为空,说明链表为空,直接返回
|
||||||
|
if (head == NULL)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无数据,无法打印\033[0m\n", RED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果头指针不为空,说明链表不为空,需要遍历链表,打印每一个节点的信息
|
||||||
|
STU *p = head; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
// 清屏
|
||||||
|
// printf("\033[2J");
|
||||||
|
printf("--------------------\n");
|
||||||
|
printf("\033[%dm学号\t姓名\t年龄\033[0m\n", BLUE_B);
|
||||||
|
while (p != NULL) // 当 p 不为空时,说明 p 不是尾部,则打印 p 的信息
|
||||||
|
{
|
||||||
|
printf("\033[%dm%d\t%s\t%d\033[0m\n", BLUE, p->sid, p->name, p->age); // 打印 p 的信息
|
||||||
|
p = p->next; // p 一直向后移动,直到找到尾部
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询学生
|
||||||
|
STU *find_stu(STU *head, char sid)
|
||||||
|
{
|
||||||
|
if (NULL == head)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无数据,无法查询\033[0m\n", RED);
|
||||||
|
return NULL; // 返回空指针,说明没有找到要查询的节点
|
||||||
|
}
|
||||||
|
|
||||||
|
STU *tp = head; // 保存头指针
|
||||||
|
while (NULL != tp->next && sid != tp->sid) // 当 tp 的下一个节点不为空时,且下一个节点的学号不等于要查询的学号时,继续向后移动指针 tp
|
||||||
|
{
|
||||||
|
tp = tp->next; // tp 一直向后移动,直到找到尾部
|
||||||
|
}
|
||||||
|
if (sid == tp->sid)
|
||||||
|
return tp; // 返回当前节点的指针,即为要查询的节点
|
||||||
|
return NULL; // 返回空指针,说明没有找到要查询的节点
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改学生
|
||||||
|
STU *update_stu(STU *head, char sid)
|
||||||
|
{
|
||||||
|
if (NULL == head)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无数据,无法修改\033[0m\n", RED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
STU *tp = find_stu(head, sid); // 查找要修改的节点
|
||||||
|
if (tp == NULL)
|
||||||
|
{
|
||||||
|
printf("\033[%dm未找到 sid = %d 的学生\033[0m\n", RED, sid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 临时变量,用来保存要修改的学生信息
|
||||||
|
char msid;
|
||||||
|
char mname[32];
|
||||||
|
int mage;
|
||||||
|
|
||||||
|
// 输入要修改的内容
|
||||||
|
printf("输入要修改的学生的 学号 姓名 年龄: ");
|
||||||
|
scanf("%hhd %s %d", &msid, mname, &mage);
|
||||||
|
tp->sid = msid;
|
||||||
|
strcpy(tp->name, mname);
|
||||||
|
tp->age = mage;
|
||||||
|
// 修改成功
|
||||||
|
printf("\033[%dm修改 sid = %d 的学生成功\033[0m\n", BLUE, sid);
|
||||||
|
}
|
||||||
|
return head; // 返回头指针
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序学生(选择排序,也可以使用归并排序)
|
||||||
|
STU *sort_stu(STU *head)
|
||||||
|
{
|
||||||
|
if (NULL == head)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无数据,无法排序\033[0m\n", RED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// 选择排序方式: 1) 按照sid 2)按照age
|
||||||
|
int choose; // 选择排序方式
|
||||||
|
printf("选择排序方式: 1) 按照sid 2)按照age: ");
|
||||||
|
scanf("%d", &choose);
|
||||||
|
if (1 == choose) // 按照sid排序
|
||||||
|
{
|
||||||
|
// 选择排序方式: 1) 升序 2)降序
|
||||||
|
int choose2; // 选择排序方式
|
||||||
|
printf("选择排序方式: 1) 升序 2)降序: ");
|
||||||
|
scanf("%d", &choose2);
|
||||||
|
if (1 == choose2) // 升序
|
||||||
|
{
|
||||||
|
// 按照sid升序排序
|
||||||
|
STU *p = head; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (p != NULL) // 相当于 for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
STU *q = p->next; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (q != NULL) // 相当于 for (int j = i + 1; j < len; j++)
|
||||||
|
{
|
||||||
|
if (p->sid > q->sid) // 相当于 if (arr[i] > arr[j])
|
||||||
|
{
|
||||||
|
swap(p, q); // 相当于 swap(arr[i], arr[j]
|
||||||
|
}
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (2 == choose2) // 降序
|
||||||
|
{
|
||||||
|
STU *p = head; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (p != NULL)
|
||||||
|
{
|
||||||
|
STU *q = p->next; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (q != NULL)
|
||||||
|
{
|
||||||
|
if (p->sid < q->sid)
|
||||||
|
{
|
||||||
|
swap(p, q);
|
||||||
|
}
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 选择错误
|
||||||
|
printf("\033[%dm选择错误\033[0m\n", RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (2 == choose) // 按照age排序
|
||||||
|
{
|
||||||
|
// 选择排序方式: 1) 升序 2)降序
|
||||||
|
int choose2; // 选择排序方式
|
||||||
|
printf("选择排序方式: 1) 升序 2)降序: ");
|
||||||
|
scanf("%d", &choose2);
|
||||||
|
if (1 == choose2) // 升序
|
||||||
|
{
|
||||||
|
STU *p = head; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (NULL != p)
|
||||||
|
{
|
||||||
|
STU *q = p->next; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (NULL != q)
|
||||||
|
{
|
||||||
|
if (p->age > q->age)
|
||||||
|
{
|
||||||
|
swap(p, q);
|
||||||
|
}
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (2 == choose2) // 降序
|
||||||
|
{
|
||||||
|
STU *p = head; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (NULL != p)
|
||||||
|
{
|
||||||
|
STU *q = p->next; // 创建一个临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (NULL != q)
|
||||||
|
{
|
||||||
|
if (p->age < q->age)
|
||||||
|
{
|
||||||
|
swap(p, q);
|
||||||
|
}
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 选择错误
|
||||||
|
printf("\033[%dm选择错误\033[0m\n", RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 选择错误
|
||||||
|
printf("\033[%dm选择错误\033[0m\n", RED);
|
||||||
|
}
|
||||||
|
return head; // 返回头指针
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反序学生(头变尾,尾变头)
|
||||||
|
STU *reverse_stu(STU *head)
|
||||||
|
{
|
||||||
|
if (NULL == head)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无数据,无法反序\033[0m\n", RED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
STU *pi = head->next; // 当前节点的下一个节点地址
|
||||||
|
head->next = NULL; // 把头节点的下一个节点置空,让头节点成为尾节点
|
||||||
|
STU *tp = NULL; // 当前节点的下一个节点地址 pi 的下一个节点地址
|
||||||
|
while (pi != NULL) // 当 pi 不为空时,说明 pi 不是尾部,则反序 pi 的信息
|
||||||
|
{
|
||||||
|
tp = pi->next; // 首先 tp 保存 pi 的下一个节点地址
|
||||||
|
pi->next = head; // 然后把 pi 的下一个节点地址指向 head
|
||||||
|
head = pi; // 然后让 hand 指向 pi
|
||||||
|
pi = tp; // 最后找到新的 pi,即 tp
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\033[%dm反序成功\033[0m\n", BLUE);
|
||||||
|
return head; // 返回头指针
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存数据到文件
|
||||||
|
void saveToFile(STU *head, const char *filename)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(filename, "w");
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无法打开文件, 保存数据失败\033[0m", RED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
STU *current = head; // 定义临时指针,用来保存头指针,防止头指针丢失
|
||||||
|
while (current != NULL) // 当 p 不为空时,说明 p 不是尾部,则打印 p 的信息
|
||||||
|
{
|
||||||
|
// 格式化存储数据,每个字段之间用逗号分隔
|
||||||
|
fprintf(file, "%d,%s,%d\n", current->sid, current->name, current->age);
|
||||||
|
current = current->next; // p 一直向后移动,直到找到尾部
|
||||||
|
}
|
||||||
|
printf("保存数据成功\n");
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从文件中读取数据
|
||||||
|
STU *readFromFile(const char *filename)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(filename, "r");
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
printf("\033[%dm无法打开文件, 加载数据失败\033[0m", RED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
STU *head = NULL; // 定义头指针
|
||||||
|
STU *prev = NULL; // 定义尾指针
|
||||||
|
char line[100]; // 100 个字符的数组,用来保存每一行的数据
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), file) != NULL) // 逐行读取文件内容
|
||||||
|
{
|
||||||
|
STU *node = (STU *)malloc(sizeof(STU)); // 申请一个节点的内存, 用来保存学生信息
|
||||||
|
/*
|
||||||
|
%d :表示读取一个整数,并将其存储在 &(node->sid)的地址中,即学生的学号。
|
||||||
|
, :表示读取一个逗号,用于分隔学号和姓名之间的字段。
|
||||||
|
%[^,] :表示读取一个字符串,直到遇到逗号为止,并将其存储在 node -> name 中,即学生的姓名。[^,] 表示匹配除逗号以外的任意字符。
|
||||||
|
, :表示读取一个逗号,用于分隔姓名和年龄之间的字段。
|
||||||
|
%d :表示读取一个整数,并将其存储在 &(node->age)的地址中,即学生的年龄。
|
||||||
|
*/
|
||||||
|
sscanf(line, "%d,%[^,],%d", &(node->sid), node->name, &(node->age)); // 将每一行的数据保存到节点中
|
||||||
|
// fscanf() 每次执行后会丢失数据,所以需要使用 sscanf() 函数,原因是 fscanf() 函数会在每次执行后将文件指针向后移动,而 sscanf() 函数不会移动文件指针。
|
||||||
|
// fscanf(file, "%d,%[^,],%d\n", &(node->sid), node->name, &(node->age)); // 将每一行的数据保存到节点中
|
||||||
|
node->next = NULL; // 新建的节点的下一个节点指向空,因为是尾部插入
|
||||||
|
|
||||||
|
if (head == NULL) // 当头指针为空时,说明链表为空,直接将新建的节点作为头指针
|
||||||
|
{
|
||||||
|
head = node;
|
||||||
|
}
|
||||||
|
else // 否则,说明链表不为空,需要找到链表的尾部,将新建的节点插入到尾部
|
||||||
|
{
|
||||||
|
prev->next = node; // 将新建的节点插入到尾部
|
||||||
|
}
|
||||||
|
prev = node; // 将尾指针指向新建的节点
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
printf("加载数据成功\n");
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[])
|
||||||
|
{
|
||||||
|
STU *head = NULL; // 定义全局的头指针
|
||||||
|
|
||||||
|
// 声明临时变量,用来保存学生信息
|
||||||
|
char tsid;
|
||||||
|
char tname[32];
|
||||||
|
int tage;
|
||||||
|
|
||||||
|
// // 创建几个学生信息,用于测试
|
||||||
|
// STU *stu1 = (STU *)malloc(sizeof(STU));
|
||||||
|
// stu1->sid = 1;
|
||||||
|
// strcpy(stu1->name, "张三");
|
||||||
|
// stu1->age = 18;
|
||||||
|
// STU *stu2 = (STU *)malloc(sizeof(STU));
|
||||||
|
// stu2->sid = 2;
|
||||||
|
// strcpy(stu2->name, "李四");
|
||||||
|
// stu2->age = 21;
|
||||||
|
// STU *stu3 = (STU *)malloc(sizeof(STU));
|
||||||
|
// stu3->sid = 3;
|
||||||
|
// strcpy(stu3->name, "王五");
|
||||||
|
// stu3->age = 15;
|
||||||
|
// STU *stu4 = (STU *)malloc(sizeof(STU));
|
||||||
|
// stu4->sid = 4;
|
||||||
|
// strcpy(stu4->name, "赵六");
|
||||||
|
// stu4->age = 13;
|
||||||
|
// head = insert_stu(head, stu1);
|
||||||
|
// head = insert_stu(head, stu2);
|
||||||
|
// head = insert_stu(head, stu3);
|
||||||
|
// head = insert_stu(head, stu4);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// printf("\033[2J");
|
||||||
|
// printf("--------------------\n");
|
||||||
|
printf("\t\t \033[%d;%dm学生管理系统\033[0m\n\n", BOLD, CYAN_B);
|
||||||
|
printf("\033[%d;%dm1) 添加学生 \t2) 删除学生 \t3) 打印 \n4) 查询 \t5) 修改 \t6) 排序 \n7) 反序 \t8) 加载数据 \t0) 退出(保存数据)\n请输入选项# \033[0m", BOLD, GREEN);
|
||||||
|
int cmd = 0;
|
||||||
|
scanf("%d", &cmd);
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
// store_data(head); // 存储数据
|
||||||
|
saveToFile(head, "stu.date");
|
||||||
|
return 1;
|
||||||
|
case 1:
|
||||||
|
printf("输入学生的 学号 姓名 年龄: ");
|
||||||
|
// 键盘收集数据并动态插入链表
|
||||||
|
scanf("%hhd %s %d", &tsid, tname, &tage); // 键盘收集数据
|
||||||
|
STU *item = (STU *)malloc(sizeof(STU)); // 申请一个节点的内存, 用来保存学生信息
|
||||||
|
item->sid = tsid; // 保存学生学号到新建的节点
|
||||||
|
strcpy(item->name, tname); // 保存学生姓名到新建的节点
|
||||||
|
item->age = tage; // 保存学生年龄到新建的节点
|
||||||
|
item->next = NULL; // 新建的节点的下一个节点指向空,因为是尾部插入
|
||||||
|
head = insert_stu(head, item); // 将新建的节点插入到链表中
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("输入要删除的学生的学号: ");
|
||||||
|
scanf("%hhd", &tsid);
|
||||||
|
head = delete_stu(head, tsid);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
shows(head);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
printf("输入要查询的学生的学号: ");
|
||||||
|
scanf("%hhd", &tsid);
|
||||||
|
head = find_stu(head, tsid);
|
||||||
|
if (head == NULL)
|
||||||
|
{
|
||||||
|
printf("\033[%dm未找到 sid = %d 的学生\033[0m\n", RED, tsid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("查询到的学生信息如下: \n");
|
||||||
|
printf("\033[%dm学号\t姓名\t年龄\033[0m\n", BLUE_B);
|
||||||
|
printf("\033[%dm%d\t%s\t%d\033[0m\n", BLUE, head->sid, head->name, head->age);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
printf("输入要修改的学生的学号:");
|
||||||
|
scanf("%hhd", &tsid);
|
||||||
|
head = update_stu(head, tsid);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
printf("排序学生信息:\n");
|
||||||
|
head = sort_stu(head);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
printf("反序学生信息:\n");
|
||||||
|
head = reverse_stu(head);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
printf("加载数据......\n");
|
||||||
|
head = readFromFile("stu.date");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("\033[%dm选择错误\033[0m\n", RED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
4,赵六,13
|
||||||
|
1,张三,14
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue