#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define FILE_NAME "student.csv"
#define RD_ID (1<<0)
#define RD_NAME (1<<1)
#define RD_SCORE (1<<2)
//描述1个学生的属性
struct student
{
int ID;
char name[20];
float score;
};
//创建链表的节点数据结构
struct node
{
struct student data;//该节点的数据域
struct node *next;//该节点的指针域
};
void GetInfo(struct student *p,unsigned char flag);
int menu(void); //菜单函数声明
int add(struct node *p); //添加
int del(struct node *p); //删除
int change(struct node *p); //修改
int find(struct node *p); //查找
void all_pri(struct node *p); //打印所有
//int quit(void); //退出
int save(struct node *p); //保存
void read(struct node *p); //读取保存的文件
struct node *head = NULL; //指向头节点的指针变量
static int Add1(struct node *p,struct student temp);
int close(struct node *p1);
int main()
{
int num=0;
read(head);
while(1)
{
num = menu();
switch(num)
{
case 1:add(head);break;
case 2:del(head);break;
case 3:change(head);break;
case 4:find(head);break;
case 5:all_pri(head);break;
case 6:save(head);return 0;
}
}
}
int menu(void)
{
int num;
printf("\t\t*****欢迎进入学生管理系统*****\n");
printf("\t\t***** 1 添加学生 ***** \n");
printf("\t\t***** 2 删除学生 ***** \n");
printf("\t\t***** 3 修改学生 ***** \n");
printf("\t\t***** 4 查找学生 ***** \n");
printf("\t\t***** 5 打印所有信息 ***** \n");
printf("\t\t***** 6 保存并退出学生系统 ***** \n");
printf("请输入选项:");
scanf("%d",&num);
return num;
}
/******************************************
int add(struct node *p)
{
//1.开辟新的节点,使用new指向该新的节点
struct node *new = malloc(sizeof(struct node));
//2.1给节点的数据域赋值
GetInfo(&new->data,RD_ID|RD_NAME|RD_SCORE);
//2.2给节点的指针域赋值
new->next = NULL;
//3.把新的节点添加到链表中去
//3.1 链表为空
if(head == NULL)
{
head = new;
return 0;
}
else//尾插法
{
while(p->next != NULL)
{
p = p->next;
}
//把新节点添加到链表最后节点的后面
p->next = new;
return 0;
}
}
******************************************/
int add(struct node *p)
{
//1.开辟新的节点,使用new指向该新的节点
struct node *new = malloc(sizeof(struct node));
//2.1给节点的数据域赋值
GetInfo(&new->data,RD_ID|RD_NAME|RD_SCORE);
//2.2给节点的指针域赋值
new->next = NULL;
//3.把新的节点添加到链表中去 -- 中间插入
//3.1 链表为空
if(head == NULL)
{
head = new;
return 0;
}
//3.2 查找位置,进行插入
while(p != NULL)
{
if(p->data.ID < new->data.ID)
{
//后续节点为空,直接插入后面
if(p->next == NULL)
{
p->next = new;
return 0;
}
else if(p->next->data.ID > new->data.ID)
{
new->next = p->next;
p->next = new;
return 0;
}
}
else if(p == head)
{
new->next = head;
head = new;
return 0;
}
p = p->next;
}
}
/*
删除链表中某个节点
p1 -- 链表头
返回值: 0 -- 成功
>0 -- 失败
1 -- 链表为空
2 -- 链表中查询不到
*/
int del(struct node *p)
{
if(p == NULL) //空链表
{
return 1;
}
struct student temp={0}; //定义一个结构体数组
GetInfo(&temp,RD_ID); //输入要删除的ID
struct node *del = NULL;
//定义一个结构体指针,用来保存要删除节点的首地址
//1.判断是否是第一个节点
if(p->data.ID == temp.ID)
{
del = p;
head = del->next;
free(del);
return 0;
}
//第2个节点开始
while(p->next != NULL) //寻找到最后一个结点
{
if(p->next->data.ID == temp.ID)
{
del = p->next; //将被删结点的地址给del
p->next = del->next; //被删结点的下个地址给p的next
free(del); //释放被删结点
return 0;
}
p = p->next;
}
printf("无名之辈,不足挂齿\n");
return 2;
}
int change(struct node *p)
{
struct student temp = {0}; //初始化结构体数组
GetInfo(&temp,RD_ID|RD_NAME);//输入你想要修改的学生信息的学号
while(p != NULL)
{
if(p->data.ID == temp.ID)
{
if(strcmp(p->data.name,temp.name)==0)
{
GetInfo(&temp,RD_ID|RD_NAME|RD_SCORE);
//输入想要修改的信息
p->data = temp;
return 0;
}
}
p = p->next;
}
printf("查无此人\n");
return 1;
}
int find(struct node *p)
{
struct student temp = {0}; //保存要查找的信息
GetInfo(&temp,RD_ID); //输入要查找学生的学号
while(p != NULL) //循环比较学号
{
if(p->data.ID == temp.ID)
{
printf("找到该学生,信息如下:\n");
printf("%d\t",p->data.ID);
printf("%s\t",p->data.name);
printf("%f\n",p->data.score);
return 0;
}
p = p->next;
}
printf("查无此人\n");
return 1;
}
void all_pri(struct node *p)
{
printf("打印所有学生信息操作……\n");
printf("学号\t姓名\t成绩\n");
while(p != NULL)
{
printf("%d\t",p->data.ID);
printf("%s\t",p->data.name);
printf("%f\n",p->data.score);
p = p->next;
}
}
/*
flag = 相应的选项是否允许输入
[0]位 -- no_flag 1--允许输入 0 -- 不允许输入
[1]位 -- name_flag 1--允许输入 0 -- 不允许输入
[2]位 -- sex_flag 1--允许输入 0 -- 不允许输入
*/
void GetInfo(struct student *p,unsigned char flag)
{
if(flag & (1<<0))
{
printf("请输入学号:");
scanf("%d",&p->ID);
}
if(flag & (1<<1))
{
printf("请输入姓名:");
scanf("%s",p->name);
}
if(flag &(1<<2))
{
printf("请输入成绩:");
scanf("%f",&p->score);
}
}
int save(struct node *p) //保存
{
FILE *fp = fopen(FILE_NAME,"w");
fprintf(fp,"学号,姓名,分数\n");
if(p == NULL) //链表为空
{
perror("文件打开失败");
return 1;
}
while(p != NULL)
{
fprintf(fp,"%d,",p->data.ID);
fprintf(fp,"%s ,",p->data.name);
fprintf(fp,"%.2f\n",p->data.score);
p = p->next;
}
fclose(fp);
return 0;
}
/**************************************************
void read(struct node *p)
{
FILE *fp = fopen("data.txt","a+");
if (fp == NULL)
{
perror("fopen");
return ;
}
struct node *new = NULL,*end = p;
while (fgetc(fp) != -1)
{
fseek(fp,-1,1);//光标位置
new = malloc(sizeof(struct node));
fscanf(fp,"ID: %d\t 姓名: %s\t\t成绩: %f\t\n",&new->data.ID,new->data.name,&new->data.score);
new->next = NULL;
end->next = new;
end = new;
}
fclose(fp);
//return ;
}
*************************************************/
void read(struct node *p)
{
//1.打开 FILE_NAME r
FILE *fp = fopen(FILE_NAME,"r");
//2.往链表中添加新的数据
//2.1 偏移文件指针 -- 跳过列名
fseek(fp,sizeof("学号,姓名,性别,分数"),SEEK_SET);
//2.2 读取文件信息 -- 判断文件是否到最后
struct student temp={0};
int res = 0;
while(1){
memset(&temp,0,sizeof(temp));
res = fscanf(fp,"%d,",&temp.ID);
res = fscanf(fp,"%s",temp.name);
res = fscanf(fp,"%f",&temp.score);
if(res == EOF){
break;
}
//2.3 往链表中添加
Add1(p,temp);
p = head;//p1从新值指向链表头
}
//3.关闭文件
fclose(fp);
}
static int Add1(struct node *p,struct student temp)
{
//1.开辟新的节点,使用pnew指向该新的节点
struct node *new = malloc(sizeof(struct node));
//2.1给节点的数据域赋值
new->data = temp;
//2.2给节点的指针域赋值
new->next = NULL;
//3.把新的节点添加到链表中去 -- 中间插入
//3.1 是否为空链表
if(head == NULL){
head = new;
return 0;
}
//3.2 查找位置,进行插入
while(p != NULL){
if(p->data.ID < new->data.ID)
{
//后续节点为空,直接插入后面
if(p->next == NULL){
p->next = new;
return 0;
}else if(p->next->data.ID > new->data.ID){
new->next = p->next;
p->next = new;
return 0;
}
}else if(p == head){
new->next = head;
head = new;
return 0;
}
p = p->next;
}
}
int close(struct node *p1)
{
printf("系统正在关闭\n");
save(p1);
printf("系统关闭完成\n");
return 0;
}