首页 > 编程 > C > 正文

C语言实现学生成绩管理系统实战教学

2020-01-26 13:34:03
字体:
来源:转载
供稿:网友

趁着放假无事,开始用C语言开发一些小的项目,巩固基础知识的同时学习新的知识。

学生成绩管理系统实现的功能有:成绩录入、学生成绩查询、删除、修改、通过文件保存等。

开发这样一个系统需要具备的知识:线性表(链表)、文件操作、排序(如果需要成绩排序)。

开发环境为VS2015;在Linux下没有conio.h的头文件,需要修改与getch()函数相关的代码。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <conio.h> /*学生信息结构体*/typedef struct Node{	char Name[10];		//学生姓名	char ID[15];		//学生学号	int Score[3];	//三科成绩(数学、英语、数据结构)	float Ave_Sco;	struct Node *next;}Lnode; void Display();  /*界面显示函数*/void GetScore(Lnode *&h); /*成绩录入函数*/void PrintScore(Lnode *h); /*成绩打印函数*/void ModifyScore(Lnode *h); /*成绩修改函数*/void FindInf(Lnode *h);  /*查找信息*/void Delete(Lnode *h);  /*删除函数*/void Quit(Lnode *h);  /*退出函数*/void SaveInf(Lnode *h);void LoadInf(Lnode *h); /*初始化链表*/void InitList(Lnode *&head) {	head = (Lnode *)malloc(sizeof(Lnode));	if (head == NULL)	{		printf("error!");		exit(1);	}	head->next = NULL;  //使头节点指针域为空} int main(){	Lnode *ScoreList;  //建立成绩链表,所有学生信息存放在此链表	int Function;	char flag; 	int t = 0;	InitList(ScoreList);	LoadInf(ScoreList); 	while (1)	{		Display();		printf("请选择操作: ");		scanf("%d", &Function);		switch (Function)		{		case 1: while (1)		{			GetScore(ScoreList);			printf("是否继续输入 (Y/N)");			scanf("%s", &flag);			if (flag == 'N' || flag == 'n')break;		} 	system("cls"); break;		case 2: PrintScore(ScoreList);	_getch(); system("cls"); break;		case 3: ModifyScore(ScoreList);	system("cls"); break;		case 4: FindInf(ScoreList); _getch(); system("cls"); break;		case 5: Delete(ScoreList); _getch(); system("cls"); break;		case 6: Quit(ScoreList); break; 		default: printf("Error!!! 请重新输入:");			break;		} //switch结束	}		return 0;} /*系统界面显示*/void Display(){	printf("/t/t**********************************************/n");	printf("/t/t*************欢迎使用成绩管理系统*************/n");	printf("/t/t**********************************************/n");	printf("/t/t/t/t1、录入成绩/n");	printf("/t/t/t/t2、打印成绩/n");	printf("/t/t/t/t3、修改成绩/n");	printf("/t/t/t/t4、查找学生信息/n");	printf("/t/t/t/t5、删除学生信息/n");	printf("/t/t/t/t6、退出系统/n");	printf("/n/n/n/n/n/n");} /*成绩录入*/void GetScore(Lnode *&h){	Lnode *p, *q = h;	char name[10], id[15];	int Math, English, Datastruct;	p = (Lnode *)malloc(sizeof(Lnode));		//为学生信息申请节点	printf("请依次输入学生信息:/n");	printf("姓名 学号 数学 英语 数据结构/n");	scanf("%s %s %d %d %d", &name, &id, &Math, &English, &Datastruct); 	for (; q->next != NULL; q = q->next){;}  //移动到尾节点		strcpy(p->Name, name);	strcpy(p->ID, id);	p->Score[0] = Math;	p->Score[1] = English;	p->Score[2] = Datastruct;	p->Ave_Sco = ((float)((p->Score[0] + p->Score[1] + p->Score[2]) - 150)) / 30; 	p->next = NULL;	q->next = p;	q = p;} /*成绩打印*/void PrintScore(Lnode *h){ 	Lnode *p = h->next;	printf("%-14s%-8s%-8s%-8s%-8s%-8s/n","排名", "学号", "姓名", "数学", "英语", "数据结构", "平均绩点");	while (p != NULL)	{		printf("%-14s%-8s%-8d%-8d%-8d%.2f/n", p->ID, p->Name, p->Score[0], p->Score[1], p->Score[2], p->Ave_Sco);		p = p->next;	}} /*成绩修改*/void ModifyScore(Lnode *h){	Lnode *p = h->next;	char name[10], id[15];	int Math, English, Datastruct;	printf("请输入学生姓名:");	scanf("%s", name);	printf("请输入学生学号:");	scanf("%s", id); 	while (p)	{		if (strcmp(p->Name, name)==0 && strcmp(p->ID, id)==0)		{			printf("当前学生信息:/n");			printf("%-14s%-8s%-8s%-8s%-8s/n", "学号", "姓名", "数学", "英语", "数据结构");			printf("%-14s%-8s%-8d%-8d%-8d/n", p->ID, p->Name, p->Score[0], p->Score[1], p->Score[2]);			printf("请输入更正后的数学成绩:");			scanf("%d", &Math);			printf("请输入更正后的英语成绩:");			scanf("%d", &English);			printf("请输入更正后的数据结构成绩:");			scanf("%d", &Datastruct);			p->Score[0] = Math;			p->Score[1] = English;			p->Score[2] = Datastruct;			break;		}		else		{			p = p->next;		}	}//while循环结束} /*信息查找*/void FindInf(Lnode *h){	Lnode *p = h->next;	char name[10], id[15];	printf("请输入学生姓名:");	scanf("%s", name);	printf("请输入学生学号:");	scanf("%s", id); 	while (p)	{		if (strcmp(p->Name, name) == 0 && strcmp(p->ID, id) == 0)		{			printf("当前学生信息:/n");			printf("%-14s%-8s%-8s%-8s%-8s/n", "学号", "姓名", "数学", "英语", "数据结构");			printf("%-14s%-8s%-8d%-8d%-8d/n", p->ID, p->Name, p->Score[0], p->Score[1], p->Score[2]);			break;		}		else		{			p = p->next;		}	}//while循环结束} /*删除*/void Delete(Lnode *h){	Lnode *p = h, *q;	q = p->next;	char name[10], id[15];	printf("请输入学生姓名:");	scanf("%s", name);	printf("请输入学生学号:");	scanf("%s", id); 	while (q)	{		if (strcmp(q->Name, name) == 0 && strcmp(q->ID, id) == 0)		{			p->next = q->next;			free(q);  //删除p节点					printf("删除成功/n");			break;		}		else		{			p = p->next;			q = q->next;		}	}//while循环结束} /*退出系统*/void Quit(Lnode *h){	SaveInf(h);  //退出时保存信息	exit(0);} /*打开文件*/void LoadInf(Lnode *h){	Lnode *p = h;	Lnode *q;  //临时变量 用于保存从文件中读取的信息	FILE* file = fopen("./Information.dat", "rb");	if (!file)	{		printf("文件打开失败!");		return ;	} 	/*		使用feof判断文件是否为结束要注意的问题:			当读取文件结束时,feof函数不会立即设置标志符为-1,而是			需要再读取一次后,才会设置。所以要先读一次。	*/	q = (Lnode *)malloc(sizeof(Lnode));	fread(q, sizeof(Lnode), 1, file);	while (!feof(file))  //一直读到文件末尾	{		p->next = q;		p = q;		q = (Lnode *)malloc(sizeof(Lnode));		fread(q, sizeof(Lnode), 1, file);	} //while循环结束 	p->next = NULL;	fclose(file);} /*保存信息到文件中*/void SaveInf(Lnode *h){	Lnode *p = h->next;	int flag;	FILE* file = fopen("./Information.dat", "wb");	if (!file)	{		printf("文件打开失败!");		return;	}	while (p != NULL)	{		flag = fwrite(p, sizeof(Lnode), 1, file);  //将p的内容写到文件中		if (flag != 1)		{			break;		}		p = p->next;	}	fclose(file);}

虽然是很简单的小项目,还是有很多问题。

一:链表相关

在写成绩录入和成绩打印功能时,发现始终只能保存(没加入文件保存)最后一个数据,确定链表的相关操作没有问题,仔细判断逻辑关系后,发现是每次在头节点传到GetScore()函数,为新节点申请内存后,直接将数据保存在了新申请的节点里面,没有将链表移动到尾节点,导致每次录入成绩,都会覆盖前一次输入的数据。解决办法是链表传到函数后,先移动到最后一个节点,将新申请的节点挂接在最后一个节点之后。

/*成绩录入*/void GetScore(Lnode *&h){	Lnode *p, *q = h;	char name[10], id[15];	int Math, English, Datastruct;	p = (Lnode *)malloc(sizeof(Lnode));		//为学生信息申请节点	printf("请依次输入学生信息:/n");	printf("姓名 学号 数学 英语 数据结构/n");	scanf("%s %s %d %d %d", &name, &id, &Math, &English, &Datastruct); 	for (; q->next != NULL; q = q->next){;}  //移动到尾节点	//保存数据	strcpy(p->Name, name);	strcpy(p->ID, id);	p->Score[0] = Math;	p->Score[1] = English;	p->Score[2] = Datastruct;	p->Ave_Sco = ((float)((p->Score[0] + p->Score[1] + p->Score[2]) - 150)) / 30;        //始终指向最后一个节点	p->next = NULL;	q->next = p;	q = p;}

二、文件操作

用文件保存遇到的问题主要是每次打印数据时除正常数据外,始终多一行乱码。判断方法是while(!feof(file))。排除错误时确定了两种可能性:多保存了一行;多读取了一行。经过某度feof()与EOF的关系后,确定是多读取了一行数据。

用feof()函数进行文件尾判断时,当文件已经到达尾部后,还需要在读取一次后,feof()函数才会返回-1,所以会出现多读一次的情况;解决办法时,在循环读取之前先将第一个数据读取出来,然后在正常读取。即注意多读一次的问题。

/*打开文件*/void LoadInf(Lnode *h){	Lnode *p = h;	Lnode *q;  //临时变量 用于保存从文件中读取的信息	FILE* file = fopen("./Information.dat", "rb");	if (!file)	{		printf("文件打开失败!");		return ;	} 	/*		使用feof判断文件是否为结束要注意的问题:			当读取文件结束时,feof函数不会立即设置标志符为-1,而是			需要再读取一次后,才会设置。所以要先读一次。	*/	q = (Lnode *)malloc(sizeof(Lnode));	fread(q, sizeof(Lnode), 1, file);	while (!feof(file))  //一直读到文件末尾	{		p->next = q;		p = q;		q = (Lnode *)malloc(sizeof(Lnode));		fread(q, sizeof(Lnode), 1, file);	} //while循环结束	p->next = NULL;	fclose(file);}

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选