学生管理系统

时间:2021-02-22 03:39:28
司联波  
//学生管理系统 完成时间2013 06 08
//大一第一次课程设计
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 3
#define LEN (Student*) malloc(sizeof(Student))
/* 学生数据结构 */
typedef struct node
{
    char num[20];
    char name[15];
    int  score[N];
    int  sum;
    double ave;
    struct node *next;
} Student;
      
/* 头指针 */
Student *head = NULL;
/* 临时指针 */
Student *tmp = NULL;
/* 课程名称 */
char CLASSNAME[N][30] = {"大物", "高数", "c语言"};
/* 命令开关 */
int SWITCH[16] = {0};
/*所有的 函数声明 */
int Menu();
Student* Init();
int CheckNUM(char*);
int CheckName(char*);
int CheakScore(int score);
int Same_NUM(char*);
void InputNodeInfo(Student*);
void OutputNodeInfo(Student*);
Student* SearchFrontNode(Student*);
void DeleteNode(Student*);
void InsertBefore();
void InputList();
Student* SearchID(char*);
Student* SearchName(char*);
void SearchDeleteNode();
void OutList();
void SearchPrintNode();
void Compute();
int CmpID(Student*, Student*, int);
int CmpSum(Student*, Student*, int);
int CmpScore(Student*, Student*, int);
Student* SearchMaxNode(int (*cmp)(Student*, Student*, int), int);
Student* Sort(int (*cmp)(Student*, Student*, int), int);
void OutputToFile(FILE*, Student*, int);
void InsertAfter(Student*);
void SaveToFile();
void LoadFile();
// void CopyFile();
void InsertToFile();
void FreeList(Student* p);
void Stat();
void Quit();
      
/* 主函数 */
int main()
{
    int n; 
      
    while (1)
    {
        n = Menu();   //
        {
            if (n == 1 || n == 15 || SWITCH[1])
            {
                switch (n)
                {
                        /* 执行初始化 */
                    case 1:
                        head = Init();
                        printf("LOOK...初始化成功\n");
                        break;
                        /* 创建链表 ,输入学生信息*/
                    case 2:
                        InputList();
                        break;
                        /* 查找学号或姓名删除信息 */
                    case 3:
                        SearchDeleteNode();
                        break;
                        /* 输出全部学生信息 */
                    case 4:
                        system("cls");
                        OutList();
                        break;
                        /* 按姓名查找学生信息*/
                    case 5:
                        SearchPrintNode();
                        break;
                        /* 保存到文件 */
                    case 6:
                        SaveToFile();
                        break;
                        /* 从文件中读取学生信息*/
                    case 7:
                        if (SWITCH[6])
                        {
                            head = Init();
                            LoadFile();
                        }
                        else
                        {
                            printf("当前文件未保存\n");
                        }
                        break;
                        /* 计算所有学生的总分和平均分 */
                    case 8:
                        Compute();
                        SWITCH[8] = 1;
                        printf("计算完毕\n");
                        break;
                        /* 插入一个学生信息到链表 */
                    case 9:
                        InsertBefore();
                        SWITCH[6] = 0;
                        SWITCH[8] = 0;
                        break;
  //                      /* 复制文件 */
  //                  case 10:
  //                      CopyFile();
                        break;          // 本来想取消复制函数,有一个问题,如果同时取消break 程序会奇怪的出死循环,还没有解决  2013 06 13
                        /* 排序,按总分排序并打印学生信息 */
                    case 11:
                        if (SWITCH[8])
                        {
                            head = Sort(CmpSum, 0);
                            system("cls");
                            OutList();
                        }
                        else
                        {
                            printf("请先计算总分!\n");
                        }
                        break;
                        /* 尾部添加一个学生信息到文件中 */
                    case 12:
                        InsertToFile();
                        SWITCH[6] = 0;
                        printf("尾部添加完毕!\n");
                        break;
                        /* 按学号搜索..学生信息*/
                    case 13:
                        if (SWITCH[8])
                        {
                            head = Sort(CmpID, 0);
                            system("cls");
                            OutList();
                        }
                        else
                        {
                            printf("请先计算总分!\n");
                        }
                        break;
                        /* 分类汇总 */
                    case 14:
                        system("cls");
                        Stat();
                        break;
                        /* 结束 */
                    case 15:
                        Quit();
                        break;
                    default:
                        printf("无效命令编号!\n");
                        fflush(stdin);
                }
                system("pause");
            }
            else
            {
                printf("你必须首先初始化!\n");
                system("pause");
            }
        }
    }
      
    system("pause");
    return 0;
}
      
/* 菜单 */
int Menu()
{
    int n;
    system("cls");
    fflush(stdin);
    printf("*********************************************************************\n");
    printf("*********************************************************************\n");
    printf("【01】 初始化........\n");
    printf("【02】 输入学生信息\n");
    printf("【03】 查找学号或姓名删除信息\n");
    printf("【04】 输出全部学生信息\n");
    printf("【05】 按姓名查找学生信息\n");
    printf("【06】 保存到文件\n");
    printf("【07】 从文件中读取学生信息\n");
    printf("【08】 计算所有学生的总分和平均分\n");
    printf("【09】 插入一个学生信息到链表中\n");
  //  printf("【10】 复制文件\n");
    printf("【11】 按总分排序并打印学生信息\n");
    printf("【12】 尾部添加一个学生信息到文件中\n");
    printf("【13】 按学号搜索..学生信息\n");
    printf("【14】 分类汇总\n");
    printf("【15】 退出\n");
    printf("********************************************************************\n");
    printf("请输入命令编号: ");
    scanf("%d", &n);
    return n;
}
      
/* 初始化 */
Student* Init()
{
    int i;
    Student *head;
    head = LEN;
    head->next = NULL;
      
    /* 命令开关初始化 */
    for (i = 1; i < 16; i++)
    {
        SWITCH[i] = 0;
    }
      
SWITCH[1] = 1;
    SWITCH[6] = 1;
    return head;
}
      
/* 检查学号,要求必须是数字 */
int CheckNUM(char* s)
{
    int i;
      
    if (strlen(s) == 0 || strlen(s) > 10)  return 0;
    for (i = 0; i < strlen(s); i++)
    {
        if (s[i] < '0' || s[i] > '9') return 0;
    }
      
    return 1;
}
      
/* 检查姓名,要求必须是英文字母 */
int CheckName(char* s)
{
    int i;
      
     if (strlen(s) == 0 || strlen(s) > 15) return 0;
      
     for (i = 0; i < strlen(s); i++)
    {
        if (!(s[i] >= 'a' && s[i] <= 'z' || s[i] >= 'A' && s[i] <= 'Z')) return 0;
    }  
         
     return 1;
}
      
/* 检查分数 */
int CheakScore(int score)
{
    if (score > 100 || score <= 0) return 0;
    return 1;
}
      
/* 检查相同学号 */
int Same_NUM(char* s)
{
    Student *p = head->next;
    while(p != NULL)
    {
        if (strcmp(s, p->num) == 0) return 1;
        p = p->next;
    }
    return 0;
}
      
/* 给p指向的节点输入信息 */
void InputNodeInfo(Student* p)
{ int i;
    fflush(stdin);   //实验室人介绍说gcc 下没用   2013 06 07  早
      
    /* 学号 */
    printf("\n请输入学号: ");
    do
    { 
        gets(p->num);
           
        if (!CheckNUM(p->num))
        {
            printf("数据不标准,请重新输入学号: ");
    }
    else
          if (Same_NUM(p->num))
            {
             printf("检测到此学号存在,请重新输入: ");
            }
    }while (!(CheckNUM(p->num) && !Same_NUM(p->num)));
      
    /* 姓名 */
    printf("请输入姓名: ");
    do
    {
        gets(p->name);
    //  getchar();    //    2013 06 13增加,会出现死循环现象
         if (!CheckName(p->name))
        {
            printf("数据不标准,请重新输入姓名: ");
        }
    } while (!CheckName(p->name));
      
    /* 成绩 */
    for (i = 0; i < N; i++)
    {
        printf("请输入 %s 成绩: ", CLASSNAME[i]);
        do
        {
            fflush(stdin);
            scanf("%d", &p->score[i]);
      
            if (!CheakScore(p->score[i]))
            {
                printf("数据不标准,请重新输入 %s 成绩: ", CLASSNAME[i]);
            }
        }
        while (!CheakScore(p->score[i]));
        getchar();
    }
      
    /* 总分及平均分 */      //后面通过计算得出
    p->sum = 0;
    p->ave = 0;
}
      
/* 输出p指向节点的信息 */
void OutputNodeInfo(Student* p)
{
    int i;
    printf("\n");
    printf("姓名: %s\n", p->name);
    printf("学号: %s\n", p->num);
      
    for (i = 0; i < N; i++)
    {
        printf("%s 成绩: %d\n", CLASSNAME[i], p->score[i]);
    }
      
    /* 计算过才输出 */
    if (SWITCH[8]) printf("总分: %d\n", p->sum);
    if (SWITCH[8]) printf("平均分: %.2lf\n", p->ave);
}
      
/* 返回r的前一个节点 */     //与删除模块对应,来自范老师的例子
Student* SearchFrontNode(Student* r)
{
    Student *p = head;
    while (p->next != r)
    p = p->next;
    return p;
}
      
/* 删除r指向的节点 */        //删除的思路,保留下自己需要的部分也就是删除不要(哲学思想 空)
DeleteNode(Student* r)
{
    Student *p = SearchFrontNode(r);
    p->next = r->next;
}
      
/* 头插法插入节点 */
void InsertBefore()
{
    Student *s = LEN;
    InputNodeInfo(s);
    s->next = head->next;
    head->next = s;
}
      
/* 输入链表 */
void InputList()
{
    int n;
    printf("有多少个学生信息要输入? ");
    scanf("%d", &n);
    getchar();
    while (n--)           //简化之后
    {
        InsertBefore();
    }
}
      
/* 按学号查找 */
Student* SearchID(char* num)
{
    Student *p = head->next;
      
    while (p != NULL)
    {
        if (strcmp(p->num, num) == 0) break;
        p = p->next;
    }
    return p;
}
      
/* 按姓名查找 */
Student* SearchName(char* name)
{
    Student *p = head->next;
      
    while (p != NULL)
    {
        if (strcmp(p->name, name) == 0) break;
        p = p->next;
    }
    return p;
}
      
/* 按学号或姓名查找删除节点 */
void SearchDeleteNode()
{
    Student *p;
    fflush(stdin);
    char str[20];
    char sure[20];
      
    /* 输入规范性判断 */
    printf("请输入你要删除的学生的 姓名 或 学号: ");
    do
    {
        gets(str);
        if (!(CheckNUM(str) || CheckName(str)))        //多次修改
        {
            printf("数据不标准,请重新输入姓名或学号: ");
        }
    } while (!(CheckNUM(str) || CheckName(str)));
      
    /* 判断是姓名还是学号 */
    if (str[0] >= '0' && str[0] <= '9')
    {
        p = SearchID(str);
      
        if (p == NULL)
        {
            printf("对不起,找不到这个学号\n");
        }
        else
        {
            OutputNodeInfo(p);
            printf("确认删除? (输入\"y\"确认,任意键取消): ");
            if (strcmp(gets(sure), "y") == 0)
            {
                DeleteNode(p);
                printf("删除成功\n");
                SWITCH[6] = 0;   //不保存
            }
            fflush(stdin);
        }
    }
    else
    {
        p = SearchName(str);
      
        if (p == NULL)
        {
            printf("对不起,找不到这个姓名\n");
        }
        else
        {
            OutputNodeInfo(p);
            printf("确认删除? (输入\"y\"确认,任意键取消): ");
            if (strcmp(gets(sure), "y") == 0)
            {
                DeleteNode(p);
                printf("删除成功!\n");
                SWITCH[6] = 0;
            }
            fflush(stdin);
        }
    }
}
      
/* 输出链表 */
void OutList()
{
    Student *p = head->next;
      
    /* 空链表处理 */
    if (p == NULL)
    {
        printf("暂无学生信息!\n");
    }
      
    while (p != NULL)
    {
        OutputNodeInfo(p);
        p = p->next;
    }
}
      
/* 按姓名查找记录并打印 */
void SearchPrintNode()
{
    Student *p = head->next;
    int ok = 1;
    char name[20];
    fflush(stdin);
      
    /* 姓名合法性判断 */
    printf("请输入你要查找的学生姓名: ");
    do
    {   getchar();
        gets(name);
      
        if (!CheckName(name))
        {
            printf("数据不标准,请重新输入姓名: ");
        }
    }
    while (!CheckName(name));
      
    /* 按姓名查找节点 */
    while (p != NULL)
    {
        if (strcmp(p->name, name) == 0)
        {
            ok = 0;
            OutputNodeInfo(p);
        }
        p = p->next;
    }
      
    if (ok)
    {
        printf("对不起,找不到这个姓名\n");
    }
}
      
/* 计算总分和均分 */
void Compute()
{
    int i;
    Student *p = head->next;
      
    while (p != NULL)
    {
        int sum = 0;
      
        for (i = 0; i < N; i++)
        {
            sum += p->score[i];
        }
      
        p->sum = sum;
        p->ave = sum * 1.0 /N;
        p = p->next;
    }
}
      
/* 比较学号 */
int CmpID(Student* a, Student* b, int k)
{
    return strcmp(a->num, b->num);
}
      
/* 比较总分 */
int CmpSum(Student* a, Student* b, int k)
{
    return b->sum-a->sum;
}
      
/* 比较各科分数 */
int CmpScore(Student* a, Student* b, int k)
{
    return b->score[k] - a->score[k];
}
      
/* 找出其中的最大元素 */
Student* SearchMaxNode(int (*cmp)(Student* a, Student* b, int k), int k)   //借鉴别人,来自网络
{
    Student *p = head->next;
    Student *max = p;
      
    while (p != NULL)
    {
        if (cmp(p, max, k) < 0)
        {
            max = p;
        }
        p = p->next;
    }
      
    return max;
}
      
/* 排序 */
Student* Sort(int (*cmp)(Student* a, Student* b, int k), int k)    //直接应用的是逗号运算表达试的值为最后一个   P25
{
    Student *newhead = LEN;
    Student *p = newhead;
    Student *max;
      
    while (head->next != NULL)
    {
        max = SearchMaxNode(cmp, k);
        p->next = max;
        DeleteNode(max);
        p = p->next;
    }
    /* 表尾处理 */
    p->next = NULL;
    return newhead;
}
/* 将s插入链表尾部 */
void InsertAfter(Student* s)
{
    Student *p = head;
      
    while (p->next != NULL)
    p = p->next;
    s->next = NULL;
    p->next = s;
}
      
/* 保存到文件 */
void SaveToFile()
{  
   /* 处理尾部添加表尾情况 */
    if (SWITCH[12])
    {
        InsertAfter(tmp);
    }
      
    FILE *fp;
    int i;
    Student *p;
    char file[20];
    fflush(stdin);
    printf("请输入要保存的文件名: ");
    scanf("%s",file);
    getchar();
    if ((fp = fopen(file, "wt")) == NULL)
    {
        printf("写文件错误.......!\n");
        return;
    }
   for(p = head->next;p!=NULL;p=p->next) //此段中大括号的使用位置错误直接导致程序出现严重的段错误(linux实验室)
     { fprintf(fp,"%s %s\n",p->name,p->num );
        for(i=0;i<=2;i++)
         {
          fprintf(fp,"%d\n",p->score[i]);
          }
     }
       printf("文件保存成功!\n");
       fclose(fp);
       SWITCH[6] = 1;
          
    /* 处理尾部添加情况 */
    if (SWITCH[12])
    {
        DeleteNode(tmp);
         SWITCH[12] = 0;
    }
}
      
/* 从文件中读入记录 */
void LoadFile()
{
    int i;
    FILE *fp;
    char file[20];
    fflush(stdin);
    printf("请输入文件名: ");
    getchar();
    gets(file);
      
    if ((fp = fopen(file, "rt")) == NULL)
    {
        printf("对不起,无法打开文件!\n");
        return;
    }
      
    /* 文件未结束时读入数据 */
    while (!feof(fp))
    {
        Student *s = LEN;
        fscanf(fp, "%s %s", s->name,s->num);
       for (i = 0; i < N; i++)
        {
            fscanf(fp, "%d\n", &s->score[i]);
        }
      
        s->next = head->next;
        head->next = s;
    }
      
    printf("文件读取成功!\n");
    fclose(fp);
}
      
/* 复制文件 */
//void CopyFile()
//{
//    FILE *fp1, *fp2;
//    char ch, file1[20], file2[20];
//    fflush(stdin);
//    /* 读入源文件 */
//    printf("请输入源文件名: ");
//    gets(file1);
//
//    if ((fp1 = fopen(file1, "rb")) == NULL)
//    {
//        printf("对不起,无法打开文件!\n");
//        return;
//    }
//
//    /* 读入目标文件 */
//    printf("请输入目标文件名: ");
//   gets(file2);
//
//    if ((strcmp(file1, file2) == 0) || ((fp2 = fopen(file2, "wb")) == NULL))
//    {
//        printf("对不起,无法创建文件!\n");
//        return;
//    }
      
//    /* 逐个字符拷贝 */
//    while (!feof(fp1))
//   {
//        ch = fgetc(fp1);
      
//        if (ch != EOF)
//            fputc(ch, fp2);
//    }
//
//    fclose(fp1);
//    fclose(fp2);
//    printf("文件拷贝成功!\n");
//}
      
/* 尾部添加记录到文件中 */
void InsertToFile()
{
    tmp = LEN;
    InputNodeInfo(tmp);
    SWITCH[12] = 1;
}
      
/* 分类统计 */
void Stat()
{
    int i, j, n = 0;
    int sum[N] = {0};
    Student *p = head->next;
      
    if (p == NULL)
    {
        printf("暂无学生信息,无法统计\n");
        return;
    }
      
    /* 统计各科总分 */
    while (p != NULL)
    {
        /* 记录学生总数 */
        n++;
      
        for (i = 0; i < N; i++)
        {
            sum[i] += p->score[i];
        }
      
        p = p->next;
    }
      
    /* 各科分别输出 */
    for (i = 0; i < N; i++)
    {
        printf("%s 的平均分为: %.2lf\n", CLASSNAME[i], sum[i] * 1.0 / n);
        head = Sort(CmpScore, i);
        j = 0;
        p = head->next;
      
        while (p != NULL)
        {
            j++;
            printf("第%d名 %s %d\n", j, p->name, p->score[i]);
            p = p->next;
        }
      
        printf("\n");
    }
}
      
/* 释放链表 */
void FreeList(Student* p)
{
    if (p->next != NULL)
    {
        FreeList(p->next);
    }
    free(p);
}
      
/* 退出 */
void Quit()
{
    if (!SWITCH[6])
    {
        printf("请先保存文件!\n");
        return;
    }
    if (head != NULL)
    {
        FreeList(head);
    }  
    exit(0);
}