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

 更新时间:2019年01月17日 08:38:47   投稿:laozhang  
在本篇文章里小编给大家分享了关于C语言实现学生成绩管理系统实战教学内容,有兴趣的朋友们可以跟着学习参考下。

趁着放假无事,开始用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);
}

相关文章

  • c语言中位字段与结构联合的组合使用详解

    c语言中位字段与结构联合的组合使用详解

    本篇文章是对c语言中位字段与结构联合的组合使用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 浅谈C语言的变量和常量

    浅谈C语言的变量和常量

    这篇文章主要为大家详细介绍了C语言的变量和常量,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • 使用 c++ 在 windows 上定时执行一个函数的示例代码

    使用 c++ 在 windows 上定时执行一个函数的示例代码

    这篇文章主要介绍了使用c++在windows上稳定定时执行一个函数,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • C语言 超详细介绍与实现线性表中的无头单向非循环链表

    C语言 超详细介绍与实现线性表中的无头单向非循环链表

    无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多
    2022-03-03
  • C语言魔塔游戏的实现代码

    C语言魔塔游戏的实现代码

    这篇文章主要介绍了C语言魔塔游戏的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • VSCode配置C/C++并添加非工作区头文件的方法

    VSCode配置C/C++并添加非工作区头文件的方法

    这篇文章主要介绍了VSCode配置C/C++并添加非工作区头文件的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • C++中的const限定符的使用和作用

    C++中的const限定符的使用和作用

    C++ 中的 const 限定符用于声明不可变量,即在变量声明时指定该变量的值不可修改。它的使用可以帮助程序员避免一些常见的编程错误,如误修改不应该被修改的变量的值等
    2023-05-05
  • C语言版猜数字小游戏

    C语言版猜数字小游戏

    这篇文章主要为大家详细介绍了C语言版猜数字小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • C语言超详细讲解函数指针的运用

    C语言超详细讲解函数指针的运用

    函数指针是一个指针变量,它可以存储函数的地址,然后使用函数指针,下面这篇文章主要给大家介绍了关于C语言进阶教程之函数指针的相关资料,需要的朋友可以参考下
    2022-06-06
  • C语言中的逗号运算符详解

    C语言中的逗号运算符详解

    在C语言中逗号“,”也是一种运算符,称为逗号运算符,其功能是把两个表达式连接起来组成一个表达式, 称为逗号表达式,这篇文章主要介绍了C语言中的逗号运算符,需要的朋友可以参考下
    2022-11-11

最新评论