学生信息管理系统_C语言实现_单链表

学生信息管理系统–C语言实现–单链表

**项目名称:学生信息管理系统**

语言:C语言

使用的数据结构:单链表_头插法_来存储学生的信息 

作者:关水水

备注:制作学生信息系统	学生信息的查询	学生信息的输入	学生信息的打印
学生信息的保存	统计目前所有的学生人数	学生信息的修改	学生信息的增加
学生信息的删除	学生信息的导出	系统的退出

开始时间:2022.07.08
截止时间:2022.07.11

.c文件源码:

/* 
项目名称:学生信息管理系统
语言:C语言
使用的数据结构:单链表_头插法_来存储学生的信息 
作者:关水水

备注:制作学生信息系统	学生信息的查询	学生信息的输入	学生信息的打印
学生信息的保存	统计目前所有的学生人数	学生信息的修改	学生信息的增加
学生信息的删除	学生信息的导出	系统的退出

链接:
https://www.bilibili.com/video/BV13z4y117qC?p=4&spm_id_from=pageDriver&vd_source=7c3b0ba3dc2b79a3af3a86fcc97eec91
 
开始时间:2022.07.08
截止时间:2022.07.11
*
*/ 
#include "StudentManageSystem.h"


int main()
{
	while(1)
	{
		Welcome_entrance();	// 函数调用 
		
		char ch=getch(); // 从键盘接收一个字符 
		/* 另外的方式: scanf	输入后需要敲回车才可被接收  					
		*	getchar()	输入后需要敲回车才可被接收  
		*	getch() 需要戴上#include <conio.h>该头文件 
		*/ 
		
			switch (ch) //	括号里面只能存放整数类型	而char类型在内存中是以ASCII码储存的 而 ASCII码也是整数类型 所以可以 
	{
		case '1':	//1.录入学生信息
			InputStudentInfo();// 函数调用 
			break;	//跳出switch语句,不让它继续执行下一个case 
		case '2':	//2.打印录入的学生信息
			PrintStudntInfo(); 
			break;
		case '3':	//3.保存学生信息
			SaveStudentInfo();
			break;
		case '4':	//4.读取文件原有学生信息
			ReadStudentInfo();
			break;
		case '5':	//5.统计所有学生人数
			CountStudent();
			break;
		case '6':	//6.查找学生信息
			{
				Node* p=FindStudent();
				if(p!=NULL)
				{
					printf("姓名:%s\t学号:%d\t年龄:%d\t总评成绩:%d\t\n",
					p->stu.name,
					p->stu.stuNum,
					p->stu.age,
					p->stu.score);
				}
				else
				{
					printf("没有查询至该学生的信息!\n");
				}
				system("pause"); 				//	系统暂停
				system("cls");					//	系统清屏 
				break;
			}
			
		case '7':	//7.修改学生信息
			ModifyStudent();
			break;
		case '8':	//8.删除学生信息
			DeleteStudent();
			break;
		case '0':	//0.退出系统
			printf("您已经退出系统!\n");
			return 0;
			default:
				printf("您的输入有误,请重新输入.\n");
				system("pause"); 				//	系统暂停
				system("cls");					//	系统清屏 
				break;
	}
		
		
		
	}
	
	return 0;
}


//	学生管理系统界面入口
 
void Welcome_entrance() // 函数体 带() 且不需要;
{
	printf("*************************************************\n");	// 换行符 \n   49个* 
	printf("*\t欢迎使用高校学生成绩管理系统V1.0\t*\n");	// 水平制表符 \t 类似Tab键 相当于8个空格  
	printf("*************************************************\n");
	printf("*\t\t请选择功能列表\t\t\t*\n");
	printf("*************************************************\n");
	printf("*\t\t1.录入学生信息\t\t\t*\n");
	printf("*\t\t2.打印录入的学生信息\t\t*\n");
	printf("*\t\t3.保存学生信息\t\t\t*\n");
	printf("*\t\t4.读取原有学生信息\t\t*\n");
	printf("*\t\t5.统计所有学生人数\t\t*\n");
	printf("*\t\t6.查找学生信息\t\t\t*\n");
	printf("*\t\t7.修改学生信息\t\t\t*\n");
	printf("*\t\t8.删除学生信息\t\t\t*\n");
	printf("*\t\t0.退出系统\t\t\t*\n");
	printf("*************************************************\n");
	printf("*\t\t请输入您的选项:\t\t*\n");
}

// 1.录入学生信息
void InputStudentInfo()
{
	// 创建一个新节点	可以理解为是要插入的学生的信息节点 
	Node* pNewNode=(Node*)malloc(sizeof(Node));	// 向内存申请一个"节点"大小的空间 返回一个 pNewNode新节点的指针类型
	pNewNode->pNext=NULL; 	// 此时这是一个头节点也是一个尾节点,且尾节点的指针域为Null 
	
	// 头插法、尾插法来实现学生信息的插入
	// 分情况讨论,当头节点为空以及头节点不为空时
	 if(g_pHead==NULL)
	 {
	 	g_pHead=pNewNode;	// 当头节点为空的时候,将创建的新的要插入的学生信息节点设置为头节点 
	 }
	 else
	 {
	 	pNewNode->pNext=g_pHead;	//	当头节点不为空时,所创建的新节点的下一个地址指向原本的头节点
		 g_pHead=pNewNode;			//	此时,将头节点指向新插入的学生信息的节点 
	 }
	 
	
	printf("请输入学生的姓名:");
	scanf("%s",pNewNode->stu.name);	//	从键盘格式化接收一个字符串,整数等等 
	printf("请输入学生的学号:");
	scanf("%d",&pNewNode->stu.stuNum);	//	 &取地址运算符 
	printf("请输入学生的年龄:");
	scanf("%d",&pNewNode->stu.age);
	printf("请输入学生的总评成绩:");
	scanf("%d",&pNewNode->stu.score); 
	
	printf("学生信息录入成功!\n");		//	\n:换行符
	system("pause"); 				//	系统暂停
	system("cls");					//	系统清屏 
}


//	2.打印学生信息
void PrintStudntInfo()
{
	system("cls");					//	系统清屏 
	printf("*************************************************\n");
	printf("*\t欢迎使用高校学生成绩管理系统V1.0\t*\n");	// 水平制表符 \t 类似Tab键 相当于8个空格  
	printf("*************************************************\n");
	printf("*\t姓名\t学号\t年龄\t总评成绩\t*\n");
	printf("*************************************************\n");
	
	//遍历链表 
	Node* p=g_pHead;				//	设置一个p节点指针指向头节点
	while(p!=NULL)					//	只要p节点不等于空那么就开始遍历 
	{
		printf("*\t%s\t%d\t%d\t%d\t\t*\n",
		p->stu.name,
		p->stu.stuNum,
		p->stu.age,
		p->stu.score
		);
		
		p=p->pNext;
	 } 
	printf("*************************************************\n");
	system("pause"); 				//	系统暂停
	system("cls");					//	系统清屏 
}


//	3.保存学生信息
void SaveStudentInfo()
{
	system("cls");					//	系统清屏 
	
	//	打开文件
	FILE* fp=fopen("D:\\StuManageSystemdata\\StuManageSystemdata.data","w"); //	打开文件,写入操作,返回一个指针fp 
	
	if(fp==NULL)	//	如果没有该文件时那么提示报错打开文件失败 
	{
		printf("打开文件失败,无法保存信息!\n");
		return;
	}
	
	//	遍历链表
	Node* p=g_pHead;
	while(p!=NULL)
	{
		fwrite(&p->stu,1,sizeof(Student),fp);	
		//	执行写入操作
		//	stu结构体的地址		每次写入1个字节		大小为该结构体的大小		返回fp指针,写入至相应文件夹 
		p=p->pNext;
	 } 
	
	//	关闭文件
	fclose(fp);
	printf("\n数据保存成功!\n");
	system("pause"); 				//	系统暂停
	system("cls");					//	系统清屏 
}


//	4.读取原有学生信息
void ReadStudentInfo()
{
	//	打开文件
	FILE* fp=fopen("D:\\StuManageSystemdata\\StuManageSystemdata.data","r");  
	//	FILE与NULL 同理,全部大写,否则报错	[Error] unknown type name 'File'
	if(fp==NULL)
	{
		printf("打开文件失败!\n");
		return;
	}
	
	//	读文件
	Student stu;	//	这里不是特别明白?????????????????????????????? 
	while(fread(&stu,1,sizeof(Student),fp)) 	//	当要读取文件的字节大于>0,则执行读文件操作 
	{
		//	创建一个新节点
		Node* pNewNode=(Node*)malloc(sizeof(Node));
		pNewNode->pNext=NULL;
		
		memcpy(pNewNode,&stu,sizeof(Student));		//	复制节点 
		//	需要添加头文件 #include  <string.h>
		
		//	头插法
		 if(g_pHead==NULL)
		 {
		 	g_pHead=pNewNode; 
		 }
		 else
		 {
		 	pNewNode->pNext=g_pHead;
		 	g_pHead=pNewNode;
		 }
		
	}
	
	//	关闭文件
	fclose(fp); 
	printf("加载数据成功!请选择选项2进行打印!\n");
	system("pause"); 				//	系统暂停
	system("cls");					//	系统清屏 
}


//	5.统计所有学生人数
void CountStudent()
{
	int nCount=0;	//	学生总数
	//	链表遍历
	Node* p=g_pHead;
	while(p!=NULL)
	{
		nCount++;
		p=p->pNext;
	 } 
	printf("学生的总人数为:%d\n",nCount);
	system("pause"); 				//	系统暂停
	system("cls");					//	系统清屏 
}


//	6.查找学生信息
Node* FindStudent()
{
	int nStuNum;	//	要查找的学生的学号 
	char sName[20];//	要查找的学生的姓名
	printf("请输入要查找的学生的学号:\n");
	scanf("%d",&nStuNum);
	printf("请输入要查找的学生的姓名:\n");
	scanf("%s",sName);
	
	Node* p=g_pHead;
	while(p!=NULL)
	{
		//	将输入的信息与链表中的信息进行比较
		//	strcmp字符串比较函数,相等取值为0 
		if(p->stu.stuNum==nStuNum||0==strcmp(p->stu.name,sName))
		{
			return p;
		}
		p=p->pNext;
	}
	
	//	没有找到则返回NULL
	return NULL; 
}


//	7.修改学生信息
void ModifyStudent()
{
	int nStuNum;	 //	newStudentNumber
	printf("请输入需要修改的学生的信息的学号:\n");
	scanf("%d",&nStuNum);
	Node* p=g_pHead;	//	申请一个新节点指向头节点
	while(p!=NULL)
	{
		// strcmp字符串比较函数
		if(p->stu.stuNum==nStuNum)
		{
			printf("需要修改的学生的原有信息如下:姓名:%s\t学号:%d\t年龄:%d\t总评分数:%d\t\n",
					p->stu.name,
					p->stu.stuNum,
					p->stu.age,
					p->stu.score);
			printf("请输入要修改的学生姓名,年龄,成绩:\n");
			scanf("%s %d %d",p->stu.name,&p->stu.age,&p->stu.score);
			printf("修改成功.\n");
			printf("修改后的学生信息如下:姓名:%s\t学号:%d\t年龄:%d\t总评分数:%d\t\n",
					p->stu.name,
					p->stu.stuNum,
					p->stu.age,
					p->stu.score);
			break;
		 } 
		 p=p->pNext;
	 } 
	 
	 if(p==NULL)	//	输入的学号不存在的情况下 
	 {
	 	printf("没有找到该学生信息.\n");
	 }
	system("pause"); 				//	系统暂停
	system("cls");					//	系统清屏 
}

//	8.删除学生信息
void DeleteStudent()
{
	int nStuNum;	//	newStuedentNumber
	printf("请输入要删除的学生的学号:\n");
	scanf("%d",&nStuNum); 
	
	Node* p1,*p2;
	//	判断要删除的节点是不是头节点	两者学号比较即可 
	//		如果是头节点, 让原有头节点的内容备份给节点p1,通过释放p1,达到删除头节点的目的 
	//		同时,记得让原来的头节点的下一个节点成为新的头节点 
	if(g_pHead->stu.stuNum==nStuNum)	//	记住是==号,否则只会删除第一列数据 
	{
		p1=g_pHead;
		g_pHead=g_pHead->pNext;
		free(p1);
		printf("删除成功!\n");
		system("pause"); 				//	系统暂停
		system("cls");					//	系统清屏 
		return;
	 } 
	 
	 //		如果不是头节点 
	 //		节点顺序如下:
	 //		p(g_pHead) 		p2(p->next)			p->next->next
	 Node* p=g_pHead;		//	将头节点的信息备份给节点p 
	
	 
	 while(p->pNext!=NULL)	//	当头节点的指向下一个的地址部分不为空 
	 {
	 	if(p->pNext->stu.stuNum==nStuNum)	//	头节点的指向下一个的地址部分跳转的节点里面的学号信息与要删除的信息相同 							
	 	{
	 		p2=p->pNext;	//	要删除的节点是节点p2 
	 		p->pNext=p->pNext->pNext;		//	将节点p的指向下一个的地址部分指向删除节点的下一个 
	 		free(p2);
	 		printf("删除成功!\n");
	 		system("pause"); 				//	系统暂停
			system("cls");					//	系统清屏 
			return;
		 }
		 p=p->pNext;
		 
		 //		如果要删除的节点是尾节点, 
		 if(p->pNext ==NULL)
		 {
		 	break;
		 }
	 }
	 
	 if(p->pNext==NULL)
	 	{
	 		printf("没有找到该学员的信息!\n");
	 		system("pause"); 				//	系统暂停
			system("cls");					//	系统清屏 
	 	}
}


.h文件源码:

#include <stdio.h>
#include <conio.h>
// 使用该语句【char ch=getch();  从键盘接收一个字符】时所添加的头文件 
#include <stdlib.h>
// 向内存申请空间【malloc(sizeof(Node));】的时候要用到的头文件 
#include  <string.h>
//	使用该语句【memcpy(pNewNode,&stu,sizeof(Student));】时所添加的头文件 


//	定义一个学生
typedef struct _Student 
{
	char name[20];	//姓名 
	int stuNum;		//学号 
	int age;		//年龄 
	int score;		//总评成绩 
 } Student;	 //创建一个_student结构体类型的定义	并且取别名为Student 

// 节点(车厢)
typedef struct _Node
{
	Student stu;			// 链表中"车厢 "存放了学生的相关信息
	struct _Node* pNext;	// 以及指向下一个节点的指针 
 } Node;
 
 // 定义一个头节点
 Node *g_pHead = NULL; 		//	注意是NULL不要打错,不然会报错


//	学生管理系统界面入口
void Welcome_entrance();  // 函数声明 带() 带结束标志; 

//	1.录入学生信息
void InputStudentInfo();

//	2.打印学生信息
void PrintStudntInfo();

//	3.保存学生信息
void SaveStudentInfo();

//	4.读取原有学生信息
void ReadStudentInfo();

//	5.统计所有学生人数
void CountStudent();

//	6.查找学生信息
Node* FindStudent();

//	7.修改学生信息
void ModifyStudent();

//	8.删除学生信息
void DeleteStudent();


第一次跟写出现的一些问题

  • 不知道用Dev C++如何创建头文件

  • 解决:devc++建立头文件步骤-百度经验 (baidu.com)

  • 水平制表符 \t 类似Tab键 相当于8个空格

  • 死循环可以直接写 while(1){~~~};

  • 函数声明以及函数体的区别:

  • 函数声明:在这里插入图片描述

  • 函数体:在这里插入图片描述

  • 函数调用:在这里插入图片描述

  • 接收用户的字符的语句有三种:
    在这里插入图片描述

  • 用switch语句时候你的格式是错误的,请查看正确的格式:
    在这里插入图片描述

  • 不会定义结构体,请看正确格式:(不要忘记char类型后面需要带上大小,但是int不用)
    在这里插入图片描述

  • 不会创建结构体–组成链表的元素的创建:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JTxNd2ia-1657540292558)(C:\Users\Yingge\AppData\Roaming\Typora\typora-user-images\1657305500118.png)]

  • 链表示意图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTxtaCSs-1657540292559)(C:\Users\Yingge\AppData\Roaming\Typora\typora-user-images\1657306081417.png)]

  • 忘记在主文件那里加入头文件

  •  #include "StudentManageSystem.h"
    
  • struct结构体打错了,少打了一个r

  • NULL 没有打对,打了Null,所以报错出现了该错误,但其实只要把所有改成对的NULL
    -在这里插入图片描述

  • Student打错了一直没有找到,浪费时间了

  • 报错ld returned 1 exit status
  • 记住是==号,否则只会删除第一列数据 ,由于少打了一个=号导致结果错误
    在这里插入图片描述

运行成功截图

  • 录入学生信息成功在这里插入图片描述

  • 打印学生信息成功
    在这里插入图片描述

  • 保存学生信息成功
    在这里插入图片描述

  • 读取原有学生信息成功在这里插入图片描述

  • 统计所有学生人数成功

  • 在这里插入图片描述

  • 查找学生信息成功
    在这里插入图片描述

  • 修改学生信息成功

  • 在这里插入图片描述

  • 删除学生信息成功
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 退出系统成功
    在这里插入图片描述
    在这里插入图片描述

  • 11
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值