C/C++实现学生选课管理系统——(文章末尾有完整代码)

一.前言

学生选课管理系统用到的就是链表这个数据结构,在里面还涉及到了对文件的操作。需要用到一些对文件操作的函数。下面我们来一步一步实现学生选课管理系统。

二.实现系统

1.文件的安排

我们在这里需要用到三个文件。分别是实现选课系统的头文件,以及.c源文件,还有就是包含主函数test.c源文件。通过这三个文件的配合来实现系统。

StudentSubjectSelectingSystem.h:主要包含库中的头文件,以及对各种函数的声明。

StudentSubjectSelectingSystem.c:主要包含函数的定义

test.c:主要包含主函数,以及整个系统执行的逻辑。

文件名可以自己定义,不必于此相同。

2.菜单的打印

在写一些系统的时候,我们可以从需要实现的功能出发,根据要实现的功能来一步一步实现该系统。因为菜单的打印比较简单,这里我直接给出菜单,大家可以自行往里面补充。

//菜单的打印
void menu()
{
	printf("*****************************************\n");
	printf("*\t\t学生选课系统\t\t*\n");
	printf("*****************************************\n");
	printf("*\t\t1.录入学生信息\t\t*\n");
	printf("*\t\t2.打印学生信息\t\t*\n");
	printf("*\t\t3.保存学生信息\t\t*\n");
	printf("*\t\t4.读取学生信息\t\t*\n");
	printf("*\t\t5.统计学生人数\t\t*\n");
	printf("*\t\t6.查找学生信息\t\t*\n");
	printf("*\t\t7.删除学生信息\t\t*\n");
	printf("*\t\t8.修改学生信息\t\t*\n");
	printf("*\t\t9.退出选课系统\t\t*\n");
	printf("*****************************************\n");

	printf("注意:为避免数据丢失,请每次使用前先读取一次学生信息,并在使用结束后,保存学生信息!!!\n");
}

注意:我们不要把很多的代码直接写到主函数中,我们可以把某个功能写成函数,只需在主函数中调用该函数即可。这样可以让程序整个的运行逻辑更加清晰。

3.主函数

我们知道一个程序有且只有一个主函数,主函数是程序的入口,所以主函数的编写非常重要。我们实现的系统一运行肯定首先要打印一次菜单,接下来根据用户的选择,来执行不同的功能。而且在每次执行完某个功能之后,应该在重新打印一次菜单,供用户选择下一次要使用的功能。

所以我们可以利用dowhile循环,来实现菜单的多次打印。下面给出主函数的框架:

int main()
{
	do
	{
		menu();

	} while ();
	return 0;
}

那我们怎么实现不同功能的执行呢?这里我们可以利用switch语句来实现。根据我们输入的不同,switch语句会走向不同的case语句,以此来实现不同的功能。 

int main()
{
	char ch = 0;
	do
	{
		menu();
		ch = _getch();
		switch (ch)
		{
		case '1':
			//录入学生信息
			break;
		case '2':
			//打印学生信息
			break;
		case '3':
			//保存学生信息
			break;
		case '4':
			//读取学生信息
			break;
		case '5':
			//统计学生人数
			break;
		case '6':
			//查找学生信息
			break;
		case '7':
			//删除学生信息
			break;
		case '8':
			//修改学生信息
			break;
		case '9':
			//退出选课系统
			break;
		default:
			//其他情况
			break;
		}
	} while (ch);
	return 0;
}

_getch这个函数在输入的时候不需要我们按下回车就可以直接进入功能。_getch需要包含头文件#include <conio.h>。大家用scanf也是可以的。

这就是我们主函数的逻辑:首先打印一次菜单,根据我们输入的不同指向不同的功能,然后判断循环条件是否成立,如果成立就在打印菜单,进行功能选择。如此循环就实现了该系统的基本逻辑。

4.菜单功能的实现 

4.1学生信息的录入

该系统需要用到链表。所以学生的信息我们可以利用链表来维护。链表节点的声明也写到头文件中。

//学生
typedef struct Student
{
	int ID;//学号
	char name[20];//学生姓名
	int SubjectNum;//课程号
	char SubjectName[40];//课程名
	int Hours;//学时
	int Score;//学分
}student;

//链表节点
typedef struct Node
{
	student s;
	struct Node* next;
}Node;

我们先定义出学生的基本信息,然后将其放入链表节点中,利用链表来维护每一个学生的信息。typedef的作用是给这两个结构体重新起一个名字。struct Student == student,struct Node == Node。

我们这里用到的是单链表(单向不循环不带头链表)。链表是由一个一个的节点维护的,单链表的节点由数据域和指针域组成。数据域就是该节点存储的数据,指针域存储着下一个节点的地址。

不了解单链表的可以看这篇文章C——单链表-CSDN博客

学生信息的录入其实就是将一个一个的节点插入到链表中。而链表的插入有头插和尾插,我们在这里用尾插来实现。

我们首先在函数实现.c文件中定义一个全局的头节点。以此来连接之后的节点。 

既然要插入节点,那我们首先得要有节点。所以我们先定义一个函数用来创建节点。

链表中的节点都是动态开辟的,所以要用到malloc函数C语言动态内存管理-CSDN博客

//学生信息的创建
Node* CreatInformation()
{
	Node* newnode = (Node*)malloc(sizeof(Node));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	printf("请输入学生学号:\n");
	scanf("%d", &newnode->s.ID);
	printf("请输入学生姓名:\n");
	scanf("%s", newnode->s.name);
	printf("请输入课程号:\n");
	scanf("%d", &newnode->s.SubjectNum);
	printf("请输入课程名:\n");
	scanf("%s", newnode->s.SubjectName);
	printf("请输入学时:\n");
	scanf("%d", &newnode->s.Hours);
	printf("请输入学分:\n");
	scanf("%d", &newnode->s.Score);
	newnode->next = NULL;

	return newnode;
}

我们创建结点的时候,就要给里面的学生信息附上值,而给指针域先附上NULL。最后返回该结点指针。

接下里在进行插入操作:

//学生信息的录入
void InsertInformation()
{
	//创建学生信息
	Node* newnode = CreatInformation();//调用节点创建函数

	//将学生信息插入到链表中
	//尾插法
	//判断链表是否为空
	if (head == NULL)
	{
		//空链表
		head = newnode;
	}
	else
	{
		//非空链表,将学生信息尾插到链表中
		//找到尾节点
		Node* tail = head;
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

 下面我们来调试该功能:

QQ2024628-103625

我们看到,当我连续插入两个节点后,head头节点中也连接了两个节点。这说明我们信息录入这个功能已经实现了。那我们录入成功是不是要提醒以下使用者录入成功了。所以我们利用system("cls")先实现清屏操作,在打印录入成功信息。

	system("cls");
	printf("录入成功!\n");

将这二句再加入录入函数末尾即可。

4.2学生信息的打印

打印学生信息的话,我们得要有表头,然后只需遍历链表,将链表中每一个节点的数据打印出来即可。

//打印学生信息
void PrintInformation()
{
	//遍历链表打印
	system("cls");
	//打印表头
	printf("*********************************************\n");
	printf("*学号\t姓名\t课程号\t课程名\t学时\t学分*\n");
	printf("*********************************************\n");
	Node* cur = head;
	while (cur)
	{
		printf("%d\t%s\t%d\t%s\t%d\t%d\t\n",
			cur->s.ID,
			cur->s.name,
			cur->s.SubjectNum,
			cur->s.SubjectName,
			cur->s.Hours,
			cur->s.Score);
		cur = cur->next;
	}
}

在遍历链表的时候,最好不要用head进行遍历,head是一个全局变量,所有的操作都围绕这head进行,如果head在遍历的时候移动了位置,那在后续操作中就有可能造成错误。所以我们可以定义一个临时变量来遍历链表。

当我插入一个节点后打印就会呈现这种效果。大家可以插入多组节点后再试试看。

4.3保存学生信息

我们在录入学生的信息之后肯定不可能在关闭程序之后就把信息丢失了。我们要将录入的学生信息写入到一个文件中,之后方便查询已经录入的学生信息。

这下就需要用到文件操作了。如果不了解文件操作的可以看一下这篇文章C——文件操作-CSDN博客。我们需要用到里面介绍的函数来实现文件操作。

那我们怎么实现将链表中的数据写入文件中呢?其实很简单,我们只需要遍历链表,在遍历链表的时候将节点中的数据写入文件中即可。

//保存学生信息
void SaveInformation()
{
	//将学生信息保存到一个文件中
	//打开文件
	FILE* pf = fopen("studentinformation.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}

	char arr[100] = { 0 };
	Node* cur = head;
	//将信息写入文件中
	while (cur)
	{
		//将节点中数据转换为字符串
		sprintf(arr, "%d %s %d %s %d %d\n",
			cur->s.ID,
			cur->s.name,
			cur->s.SubjectNum,
			cur->s.SubjectName,
			cur->s.Hours,
			cur->s.Score);
		
		//将转换后的字符串写入文件中
		fputs(arr, pf);

		//遍历下一个节点
		cur = cur->next;
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	printf("数据保存成功!\n");
}

同样的,我们借助临时变量来遍历链表。我们先将节点中的数据借助sprintf函数转换成字符串,然后利用fputs函数,将字符串写入文件中。fopen函数的第一个参数就是文件名,写文件名是要包含后缀名。”w“的意思是写,以写的形式打开文件。记住,在写完数据之后要关闭文件。下面我们来测试该方法:

我们看到最开始,是没有该文件的,我们运行之后,添加节点后保存数据观察该文件的变化。 

 当我输入一个学生信息之后,选择保存学生信息之后,系统显示保存成功!然后我们打开该文件发现,该文件中写入了刚才我们输入的信息,由此证明,我们该方法写的没有问题。

4.4读取学生信息

我们将信息写入文件之后,如果想对已经输入的信息进行修改删除等操作的时候,就得从文件中读取数据到链表中。然后再进行各种操作。其实读取学生信息和保存学生信息是两个刚好相反的操作。唯一的区别就是我们在读取之后直接将该信息插入到链表中。下面给出代码:


//读取学生信息
void ReadInformation()
{
	//从文件中读取数据
	//打开文件
	FILE* pf = fopen("studentinformation.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		exit(-1);
	}

	char arr[50] = { 0 };

	//读取文件信息
	while (fgets(arr, 100, pf))//遇到文件末尾,fgets会返回NULL
	{
		Node* newnode = (Node*)malloc(sizeof(Node));
		sscanf(arr, "%d %s %d %s %d %d",
			&(newnode->s.ID),
			newnode->s.name,
			&(newnode->s.SubjectNum),
			newnode->s.SubjectName,
			&(newnode->s.Hours),
			&(newnode->s.Score));
		newnode->next = NULL;

		//尾插法
		//判断链表是否为空
		if (head == NULL)
		{
			//空链表
			head = newnode;
		}
		else
		{
			//非空链表,将学生信息尾插到链表中
			//找到尾节点
			Node* tail = head;
			while (tail->next)
			{
				tail = tail->next;
			}
			tail->next = newnode;
		}
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	printf("数据加载成功!\n");
}

我们再读取操作的时候看到,有的数据用了&,而有些没有,这是因为带了&的都是整数,我们需要将数据写到变量中,就要传地址,而没有&的变量他们实质上是字符数组,数组名就代表了首元素的地址,所以不用&。

我们先往文件中写几组数据,来测试读取操作是否正确。

 当我们读取之后,的确将文件中的数据读取了。

但是,对于读取和保存这两个方法有一定的问题:我们是以"w"的方式打开文件的,每一次保存就会覆盖之前的内容。如果文件中本来就有数据,我们贸然保存就会丢失之前的内容。所以我们在使用该系统之前可以先读取一次文件中的内容,防止信息丢失。但是读取也有一点问题。如果我们不小心连续点了两次读取数据,在当前的链表中就会有重复的数据出现。所以读取操作只能进行一次,要不在程序一开始时就执行,要不就是要保存新数据前先读取一次,在保存。这样既保留了旧数据和新数据,也避免了数据的重复。 

4.5统计学生人数

统计学生人数也非常简单,我们同样也是只需要遍历链表,在遍历链表的时候定义一个计数器count,只要进去循环计数器就+1,最后打印计数器的值即可。

//统计学生人数
void CountStudentNumber()
{
	int count = 0;
	Node* cur = head;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	printf("学生总人数为:%d\n", count);
}

4.6查找学生信息

在查找学生信息的时候我们既可以根据学生姓名查找,也可以根据学生学号查找。所以当我们选择该功能的时候,应该在跳出两个选择,按照学号查找或者按照姓名查找。那么接下来的操作就是遍历链表,判断链表中是否有数据与我们输入的数据相同。如果相同,那就打印该数据,如果没有,那就说明没有该学生信息,我们就要提醒用户查无此人。

//查找学生信息
void FindStudent()
{
	system("cls");
	printf("1.FindByID            2.FindByName\n");
	char ch = getch();
	switch (ch)
	{
	case '1':
	{
		printf("请输入学号:\n");
		//以学号查
		int id = 0;
		scanf("%d", &id);

		//遍历链表
		Node* cur = head;
		while (cur)
		{
			if (cur->s.ID == id)
			{
				printf("%d\t%s\t%d\t%s\t%d\t%d\t\n",
					cur->s.ID,
					cur->s.name,
					cur->s.SubjectNum,
					cur->s.SubjectName,
					cur->s.Hours,
					cur->s.Score);
				goto end1;
			}
			cur = cur->next;
		}
		//遍历完链表依旧没有找到该学生
		printf("找不到该学生!");
	}
		end1:break;
	case '2':
	{
		printf("请输入姓名:\n");
		//以姓名查
		char arr[20] = { 0 };
		scanf("%s", arr);

		Node* cur = head;
		while (cur)
		{
			if (0 == strcmp(cur->s.name, arr))
			{
				printf("%d\t%s\t%d\t%s\t%d\t%d\t\n",
					cur->s.ID,
					cur->s.name,
					cur->s.SubjectNum,
					cur->s.SubjectName,
					cur->s.Hours,
					cur->s.Score);
				goto end2;
			}
			cur = cur->next;
		}
		//遍历完该链表依旧找不到该学生
		printf("找不到该学生!");
	}
	end2:break;
	}
}

4.7删除学生信息

在链表中,删除节点可以有尾删和头删两种基础方法,但是我们这里不同于头删与尾删,而是删除特定节点。那么第一步依旧是遍历链表,找到指定的节点,然后再找到该节点的前一个节点和后一个节点。将这两个节点连接起来,然后再释放到要删除的节点。下面给出图示:


//删除学生信息
void DeleteStudnet()
{
	printf("请输入要删除的学生的姓名及学号:\n");
	int id = 0;
	char arr[20] = { 0 };
	scanf("%d %s", &id, arr);

	printf("是否要删除?\n");
	printf("1.yes   2.no\n");
	int a = 0;
	scanf("%d", &a);
	if(a == 1)
	{
		//遍历链表
		Node* cur = head;
		while (cur)
		{
			if (cur->s.ID == id || 0 == strcmp(cur->s.name, arr))//找到该学生,然后删除
			{
				//cur就是待删除的节点

				if (cur->s.ID == head->s.ID)
				{
					//要删除的节点就是头节点
					head = cur->next;
					free(cur);
					cur = NULL;
				}
				else
				{
					//要删除的节点是其他节点
					Node* prev = head;
					while (prev->next->s.ID != cur->s.ID)
					{
						prev = prev->next;
					}
					//到这里,prev就是cur的前一个节点
					prev->next = prev->next->next;
					free(cur);
					cur = NULL;
				}
				printf("删除成功!\n");
				break;
			}
			cur = cur->next;
		}
	}
	else
	{
		printf("取消删除成功!\n");
	}
}

 4.8修改学生信息

要修改学生的话,我们首先还是遍历链表,找到要修改的学号,然后在对其内容进行修改即可。

//修改学生信息
void ReviseStudent()
{
	printf("请输入待修改的学生学号:\n");
	int id = 0;
	scanf("%d", &id);
	Node* cur = head;
	while (cur)
	{
		if (cur->s.ID == id)
		{
			//找到要修改的学生
			printf("请输入要修改的姓名:\n");
			scanf("%s", cur->s.name);

			printf("请输入要修改的课程号:\n");
			scanf("%d", &cur->s.SubjectNum);

			printf("请输入要修改的课程名:\n");
			scanf("%s", cur->s.SubjectName);

			printf("请输入要修改的学时:\n");
			scanf("%d", &cur->s.Hours);

			printf("请输入要修改的学分:\n");
			scanf("%d", &cur->s.Score);

			printf("修改成功!");
			break;
		}
		cur = cur->next;
	}
	if (cur == NULL)
	{
		printf("找不到该学生!\n");
	}
}

4.9退出选课系统

当我们退出系统的时候难道就可以直接跳出循环然后退出程序么?当然不行了。我们在使用程序时创建了若干个节点,每一个节点都是通过malloc动态申请的内存空间。而内存空间是有限的,当我们需要的时候就申请,当我们不再需要的时候,就应该把申请内存还给操作系统,以供给其他程序使用。所以我们在退出程序之前应该销毁我们所创建的链表。

链表的销毁非常简单,我们只需要一个一个节点的销毁就行了。

//销毁链表
void Destory()
{
	Node* current = head;
	while (current)
	{
		Node* next = current->next;
		free(current);
		current = next;
	}
	head = NULL;
	printf("链表已经销毁!\n");
}

三.完整代码

StudentSubjectSelectingSystem.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>

//学生
typedef struct Student
{
	int ID;//学号
	char name[20];//学生姓名
	int SubjectNum;//课程号
	char SubjectName[40];//课程名
	int Hours;//学时
	int Score;//学分
}student;

//链表节点
typedef struct Node
{
	student s;
	struct Node* next;
}Node;

//学生信息的录入
void InsertInformation();

//打印学生信息
void PrintInformation();

//保存学生信息
void SaveInformation();

//读取学生信息
void ReadInformation();

//统计学生人数
void CountStudentNumber();

//查找学生信息
void FindStudent();

//删除学生信息
void DeleteStudnet();

//修改学生信息
void ReviseStudent();

//销毁链表
void Destory();

StudentSubjectSelectingSystem.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "StudentSubjectSelectingSystem.h"

//头节点
Node* head = NULL;

//学生信息的创建
Node* CreatInformation()
{
	Node* newnode = (Node*)malloc(sizeof(Node));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	printf("请输入学生学号:\n");
	scanf("%d", &newnode->s.ID);
	printf("请输入学生姓名:\n");
	scanf("%s", newnode->s.name);
	printf("请输入课程号:\n");
	scanf("%d", &newnode->s.SubjectNum);
	printf("请输入课程名:\n");
	scanf("%s", newnode->s.SubjectName);
	printf("请输入学时:\n");
	scanf("%d", &newnode->s.Hours);
	printf("请输入学分:\n");
	scanf("%d", &newnode->s.Score);
	newnode->next = NULL;

	return newnode;
}

//学生信息的录入
void InsertInformation()
{
	//创建学生信息
	Node* newnode = CreatInformation();

	//将学生信息插入到链表中
	//尾插法
	//判断链表是否为空
	if (head == NULL)
	{
		//空链表
		head = newnode;
	}
	else
	{
		//非空链表,将学生信息尾插到链表中
		//找到尾节点
		Node* tail = head;
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
	system("cls");
	printf("录入成功!\n");
}

//打印学生信息
void PrintInformation()
{
	//遍历链表打印
	system("cls");
	//打印表头
	printf("*********************************************\n");
	printf("*学号\t姓名\t课程号\t课程名\t学时\t学分*\n");
	printf("*********************************************\n");
	Node* cur = head;
	while (cur)
	{
		printf("%d\t%s\t%d\t%s\t%d\t%d\t\n",
			cur->s.ID,
			cur->s.name,
			cur->s.SubjectNum,
			cur->s.SubjectName,
			cur->s.Hours,
			cur->s.Score);
		cur = cur->next;
	}
}

//保存学生信息
void SaveInformation()
{
	//将学生信息保存到一个文件中
	//打开文件
	FILE* pf = fopen("studentinformation.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}

	char arr[100] = { 0 };
	Node* cur = head;
	//将信息写入文件中
	while (cur)
	{
		//将节点中数据转换为字符串
		sprintf(arr, "%d %s %d %s %d %d\n",
			cur->s.ID,
			cur->s.name,
			cur->s.SubjectNum,
			cur->s.SubjectName,
			cur->s.Hours,
			cur->s.Score);
		
		//将转换后的字符串写入文件中
		fputs(arr, pf);

		//遍历下一个节点
		cur = cur->next;
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	printf("数据保存成功!\n");
}

//读取学生信息
void ReadInformation()
{
	//从文件中读取数据
	//打开文件
	FILE* pf = fopen("studentinformation.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		exit(-1);
	}

	char arr[50] = { 0 };

	//读取文件信息
	while (fgets(arr, 100, pf))//遇到文件末尾,fgets会返回NULL
	{
		Node* newnode = (Node*)malloc(sizeof(Node));
		sscanf(arr, "%d %s %d %s %d %d",
			&(newnode->s.ID),
			newnode->s.name,
			&(newnode->s.SubjectNum),
			newnode->s.SubjectName,
			&(newnode->s.Hours),
			&(newnode->s.Score));
		newnode->next = NULL;

		//尾插法
		//判断链表是否为空
		if (head == NULL)
		{
			//空链表
			head = newnode;
		}
		else
		{
			//非空链表,将学生信息尾插到链表中
			//找到尾节点
			Node* tail = head;
			while (tail->next)
			{
				tail = tail->next;
			}
			tail->next = newnode;
		}
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	printf("数据加载成功!\n");
}

//统计学生人数
void CountStudentNumber()
{
	int count = 0;
	Node* cur = head;
	while (cur)
	{
		count++;
		cur = cur->next;
	}
	printf("学生总人数为:%d\n", count);
}

//查找学生信息
void FindStudent()
{
	system("cls");
	printf("1.FindByID            2.FindByName\n");
	char ch = getch();
	switch (ch)
	{
	case '1':
	{
		printf("请输入学号:\n");
		//以学号查
		int id = 0;
		scanf("%d", &id);

		//遍历链表
		Node* cur = head;
		while (cur)
		{
			if (cur->s.ID == id)
			{
				printf("%d\t%s\t%d\t%s\t%d\t%d\t\n",
					cur->s.ID,
					cur->s.name,
					cur->s.SubjectNum,
					cur->s.SubjectName,
					cur->s.Hours,
					cur->s.Score);
				goto end1;
			}
			cur = cur->next;
		}
		//遍历完链表依旧没有找到该学生
		printf("找不到该学生!");
	}
		end1:break;
	case '2':
	{
		printf("请输入姓名:\n");
		//以姓名查
		char arr[20] = { 0 };
		scanf("%s", arr);

		Node* cur = head;
		while (cur)
		{
			if (0 == strcmp(cur->s.name, arr))
			{
				printf("%d\t%s\t%d\t%s\t%d\t%d\t\n",
					cur->s.ID,
					cur->s.name,
					cur->s.SubjectNum,
					cur->s.SubjectName,
					cur->s.Hours,
					cur->s.Score);
				goto end2;
			}
			cur = cur->next;
		}
		//遍历完该链表依旧找不到该学生
		printf("找不到该学生!");
	}
	end2:break;
	}
}

//删除学生信息
void DeleteStudnet()
{
	printf("请输入要删除的学生的姓名及学号:\n");
	int id = 0;
	char arr[20] = { 0 };
	scanf("%d %s", &id, arr);

	printf("是否要删除?\n");
	printf("1.yes   2.no\n");
	int a = 0;
	scanf("%d", &a);
	if(a == 1)
	{
		//遍历链表
		Node* cur = head;
		while (cur)
		{
			if (cur->s.ID == id || 0 == strcmp(cur->s.name, arr))//找到该学生,然后删除
			{
				//cur就是待删除的节点

				if (cur->s.ID == head->s.ID)
				{
					//要删除的节点就是头节点
					head = cur->next;
					free(cur);
					cur = NULL;
				}
				else
				{
					//要删除的节点是其他节点
					Node* prev = head;
					while (prev->next->s.ID != cur->s.ID)
					{
						prev = prev->next;
					}
					//到这里,prev就是cur的前一个节点
					prev->next = prev->next->next;
					free(cur);
					cur = NULL;
				}
				printf("删除成功!\n");
				break;
			}
			cur = cur->next;
		}
	}
	else
	{
		printf("取消删除成功!\n");
	}
}

//修改学生信息
void ReviseStudent()
{
	printf("请输入待修改的学生学号:\n");
	int id = 0;
	scanf("%d", &id);
	Node* cur = head;
	while (cur)
	{
		if (cur->s.ID == id)
		{
			//找到要修改的学生
			printf("请输入要修改的姓名:\n");
			scanf("%s", cur->s.name);

			printf("请输入要修改的课程号:\n");
			scanf("%d", &cur->s.SubjectNum);

			printf("请输入要修改的课程名:\n");
			scanf("%s", cur->s.SubjectName);

			printf("请输入要修改的学时:\n");
			scanf("%d", &cur->s.Hours);

			printf("请输入要修改的学分:\n");
			scanf("%d", &cur->s.Score);

			printf("修改成功!");
			break;
		}
		cur = cur->next;
	}
	if (cur == NULL)
	{
		printf("找不到该学生!\n");
	}
}

//销毁链表
void Destory()
{
	Node* current = head;
	while (current)
	{
		Node* next = current->next;
		free(current);
		current = next;
	}
	head = NULL;
	printf("链表已经销毁!\n");
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "StudentSubjectSelectingSystem.h"

//菜单的打印
void menu()
{
	printf("*****************************************\n");
	printf("*\t\t学生选课系统\t\t*\n");
	printf("*****************************************\n");
	printf("*\t\t1.录入学生信息\t\t*\n");
	printf("*\t\t2.打印学生信息\t\t*\n");
	printf("*\t\t3.保存学生信息\t\t*\n");
	printf("*\t\t4.读取学生信息\t\t*\n");
	printf("*\t\t5.统计学生人数\t\t*\n");
	printf("*\t\t6.查找学生信息\t\t*\n");
	printf("*\t\t7.删除学生信息\t\t*\n");
	printf("*\t\t8.修改学生信息\t\t*\n");
	printf("*\t\t9.退出选课系统\t\t*\n");
	printf("*****************************************\n");

	printf("注意:为避免数据丢失,请每次使用前先读取一次学生信息,并在使用结束后,保存学生信息!!!\n");
}

int main()
{
	while (1)
	{
		menu();
		char ch = getch();
		switch (ch)
		{
		case '1':
			//录入学生信息
			InsertInformation();
			break;
		case '2':
			//打印学生信息
			PrintInformation();
			break;
		case '3':
			//保存学生信息
			SaveInformation();
			break;
		case '4':
			//读取学生信息
			ReadInformation();
			break;
		case '5':
			//统计学生人数
			CountStudentNumber();
			break;
		case '6':
			//查找学生信息
			FindStudent();
			break;
		case '7':
			//删除学生信息
			DeleteStudnet();
			break;
		case '8':
			//修改学生信息
			ReviseStudent();
			break;
		case '9':
		{
			system("cls");
			//退出选课系统
			//销毁链表
			printf("是否要退出选课系统?\n");
			printf("1.yes   2.no\n");
			int a = 0;
			scanf("%d", &a);
			if (a == 1)
			{
				Destory();
				printf("退出选课系统!");
				return 0;
			}
			else
			{
				printf("取消退出成功!\n");
			}
			break;
		}
		default:
			//其他情况
			printf("非法选择,请重新选择:\n");
		}
		system("pause");
		system("cls");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值