最新消息:点击查看大S的省钱秘笈

C语言程序实践源代码-学生成绩管理系统

编程相关 Slyar 9623浏览 9评论

文章作者:姜南(Slyar) 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。

上个学期C语言程序实践课的作业题,发出来给有需要的人参考吧。代码是纯C写的,已加注释。下面是作业要求:

* 设计一个学生成绩管理系统(学号、姓名、总分、物理、化学、计算机、英语、数学、体育)
* 采用单链表的方式设计
* 使用菜单方式进行操作,并具有操作出错提示
* 可以对记录进行增加、显示、保存到文件、读取文件、删除、查询等操作

具体的菜单如下:

” 0. init list”, /*初始化*/
” 1. Enter list”,/*输入记录*/
” 2. Delete a record from list”,  /*从表中删除记录,可以依照学号或姓名进行查找删除。如果删除后没有保存到文件,直接退出系统时,需要提醒保存文件*/
” 3. print list “, /*显示所有记录到屏幕*/
” 4. Search record on name”,/*按照姓名查找记录*/
” 5. Save the file”, /*将单链表中记录保存到文件中*/
” 6. Load the file”,  /*从文件中读入记录*/
” 7. compute the score”, /*计算所有学生的总分和均分*/
” 8. insert record to list “,/*插入记录到表中,插入记录后,直接退出时,需要提醒保存文件*/
” 9. copy the file to new file”,/*复制文件到新的文件中*/
” 10. sort to make new file”,/*排序,将学生按照分数(总分)由高到低排名*/
” 11. append  record to file”,/*追加记录到文件中,追加记录后,直接退出时,需要提醒保存文件*/
” 12. index on number”, /*索引,按照学号进行排序*/
” 13. total on number”,/*分类合计,依据不同学科进行分类统计(平均分)和排名*/
” 14. Quit” /*退出系统*/

只完成这些要求不复杂,我大概花了2个小时,但是考虑下面一些细节的话,就要耗费一番功夫了…

1.命令的操作顺序需要正确。例如所有的操作前必须初始化,按总分排序前必须计算总分等。
2.输入的学号和姓名必须检查合法性,这里限定学号为纯数字串,
姓名为纯大小写字母串,且长度有限。
3.输入信息时要判断是否存在学号相同的学生。
4.因为存在按姓名查找功能,则假定按姓名删除时姓名唯一,否则应按学号查找删除。
因此按姓名查找应能打印多个姓名相同的情况,而按姓名删除不需要删除多个姓名相同的学生信息。
5.复制文件时应排除源文件名与目标文件名相同的情况,否则会得到空白文件。
6.追加记录到文件时,链表中始终不应出现追加的信息,文件中在未保存前也不应出现追加的信息。
追加的信息应位于文件末尾。
7.菜单应能处理用户输入的错误命令,例如输入大数字、字符、字符串等。
8.退出时应释放链表。

下面给出完整的代码,比较长,建议拷贝下来放到IDE里面看…

/*
Slyar
2009.12.1
学生成绩管理系统 C语言 
*/

#include 
#include 
#include 

#define CLASS 6
#define MAXID 10
#define MAXNAME 15
#define MALLOC (Student*) malloc(sizeof(Student))

/* 学生数据结构 */
typedef struct node
{
    char id[20];
    char name[15];
    int score[CLASS];
    int sum;
    double ave;
    struct node *next;
} Student;

/* 头指针 */
Student *head = NULL;
/* 临时指针 */
Student *tmp = NULL;
/* 课程名称 */
char CLASSNAME[CLASS][30] = {"物理", "化学", "计算机", "英语", "数学", "体育"};
/* 命令开关 */
int SWITCH[16] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};

/* 函数声明 */
int Menu();
Student* Init();
int CheckID(char*);
int CheckName(char*);
int CheakScore(int score);
int IsSameID(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("初始化成功\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;
                        /* 排序 */
                    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("【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("请输入命令编号: ");
    scanf("%d", &n);
    return n;
}

/* 初始化 */
Student* Init()
{
    int i;
    Student *head;
    head = MALLOC;
    head->next = NULL;

    /* 命令开关初始化 */
    for (i = 1; i < 16; i++)
    {
        SWITCH[i] = 0;
    }

    SWITCH[1] = 1;
    SWITCH[6] = 1;
    return head;
}

/* 检查学号 */
int CheckID(char* s)
{
    int i;

    if (strlen(s) == 0 || strlen(s) > MAXID) 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) > MAXNAME) 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 IsSameID(char* s)
{
	Student *p = head->next;
	while(p != NULL)
	{
		if (strcmp(s, p->id) == 0) return 1;
		p = p->next;
	}
	return 0;
}

/* 给p指向的节点输入信息 */
void InputNodeInfo(Student* p)
{
    fflush(stdin);
    
    /* 学号 */
    printf("\n请输入学号: ");
    do
    {
        gets(p->id);

        if (!CheckID(p->id))
        {
            printf("数据违法,请重新输入学号: ");
		}
		else if (IsSameID(p->id))
		{
			printf("已存在此学号,请重新输入: ");
		}
    }while (!(CheckID(p->id) && !IsSameID(p->id)));

    /* 姓名 */
    printf("请输入姓名: ");
    do
    {
        gets(p->name);

        if (!CheckName(p->name))
        {
            printf("数据违法,请重新输入姓名: ");
        }
    }
    while (!CheckName(p->name));

    /* 成绩 */
    int i;
    for (i = 0; i < CLASS; 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]));
    }
    
    /* 总分及平均分 */
    p->sum = -1;
    p->ave = -1;
}

/* 输出p指向节点的信息 */
void OutputNodeInfo(Student* p)
{
    int i;
    printf("\n");
    printf("姓名: %s\n", p->name);
    printf("学号: %s\n", p->id);

    for (i = 0; i < CLASS; 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指向的节点 */
void DeleteNode(Student* r)
{
    Student *p = SearchFrontNode(r);
    p->next = r->next;
}

/* 头插法插入节点 */
void InsertBefore()
{
    Student *s = MALLOC;
    InputNodeInfo(s);
    s->next = head->next;
    head->next = s;
}

/* 输入链表 */
void InputList()
{
    int n;
    printf("有多少个学生信息要输入? ");
    scanf("%d", &n);

    while (n--)
    {
        InsertBefore();
    }
}

/* 按学号查找 */
Student* SearchID(char* id)
{
    Student *p = head->next;

    while (p != NULL)
    {
        if (strcmp(p->id, id) == 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 (!(CheckID(str) || CheckName(str)))
        {
            printf("数据违法,请重新输入姓名或学号: ");
        }
    }
    while (!(CheckID(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
    {
        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 < CLASS; i++)
        {
            sum += p->score[i];
        }

        p->sum = sum;
        p->ave = sum * 1.0 / CLASS;
        p = p->next;
    }
}

/* 比较学号 */
int CmpID(Student* a, Student* b, int k)
{
    return strcmp(a->id, b->id);
}

/* 比较总分 */
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)
{
    Student *newhead = MALLOC;
    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;
}

/* 输出p指向节点的信息到文件 */
void OutputToFile(FILE* fp, Student* p, int newline)
{
    int i;
    fprintf(fp, "%s\n", p->name);
    fprintf(fp, "%s\n", p->id);

    for (i = 0; i < CLASS - 1; i++)
    {
        fprintf(fp, "%d\n", p->score[i]);
    }
    
    /* 尾行处理 */
    if (newline)
    {
        fprintf(fp, "%d\n", p->score[i]);
    }
    else
    {
        fprintf(fp, "%d", p->score[i]);
    }
}

/* 将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;
    char file[20];
    fflush(stdin);
    printf("请输入文件名: ");
    gets(file);

    if ((fp = fopen(file, "wt+")) == NULL)
    {
        printf("对不起,无法创建文件!\n");
        return;
    }

    Student *p = head->next;

    while (p != NULL)
    {
        if (p->next != NULL)
        {
            OutputToFile(fp, p, 1);
        }
        else
        {
            OutputToFile(fp, p, 0);
        }

        p = p->next;
    }

    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("请输入文件名: ");
    gets(file);

    if ((fp = fopen(file, "rt")) == NULL)
    {
        printf("对不起,无法打开文件!\n");
        return;
    }

    /* 文件未结束时读入数据 */
    while (!feof(fp))
    {
        Student *s = MALLOC;
        fscanf(fp, "%s", s->name);
        fscanf(fp, "%s", s->id);

        for (i = 0; i < CLASS; i++)
        {
            fscanf(fp, "%d", &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 = MALLOC;
    InputNodeInfo(tmp);
    SWITCH[12] = 1;
}

/* 分类统计 */
void Stat()
{
    int i, j, n = 0;
    int sum[CLASS] = {0};
    Student *p = head->next;

    if (p == NULL)
    {
        printf("暂无学生信息,无法统计\n");
        return;
    }

    /* 统计各科总分 */
    while (p != NULL)
    {
        /* 记录学生总数 */
        n++;

        for (i = 0; i < CLASS; i++)
        {
            sum[i] += p->score[i];
        }

        p = p->next;
    }

    /* 各科分别输出 */
    for (i = 0; i < CLASS; 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("NO.%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);
}

转载请注明:Slyar Home » C语言程序实践源代码-学生成绩管理系统

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (9)

  1. 第34行 int SWITCH[16] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 是什么意思?
    独孤求败8年前 (2013-04-29)回复
  2. 谢谢了!都是学生我们的难处谢谢你能体谅!
    飘行者8年前 (2013-03-04)回复
  3. @xiaoxi 你也忒懒了吧,用别人的代码还懒得改动
    流水账10年前 (2010-09-12)回复
  4. 怎么改才能输入中文名字啊
    yyyo10年前 (2010-06-30)回复
  5. @Slyar 谢谢!
    xiaoxi11年前 (2010-02-20)回复
  6. @xiaoxi wordpress代码高亮插件
    Slyar11年前 (2010-02-19)回复
  7. @Slyar 谢谢你的回复,就是你这篇日志中的代码粘贴出来的这种效果是怎么实现的。
    xiaoxi11年前 (2010-02-19)回复
  8. @xiaoxi 啊?这我就不知道了...
    Slyar11年前 (2010-02-19)回复
  9. 请问怎样粘贴代码,使每行代码前面都有一个编号?谢谢
    xiaoxi11年前 (2010-02-18)回复