C语言学生信息管理系统终极版

本源码包含功能:输入、浏览全部信息、单个查找、添加、删除、修改、排序


思路:

1.模块化设计是C语言的特点
2.防止特殊情况导致程序崩溃——空文件,所以重要函数都设有保护机制
3.UI方面实在无能为力,C语言知识就储备那一点,没办法


设计过程:

1.读写文件
分为只读(如查询、遍历等,不需要操作的)和只写(重写文件,把2中链表重新导到原文件中,覆盖原文件)两种,需要分情况选择。
为什么要分?主要是根据w,r,a的不同而决定的。

2.读数据
每次打开应用都用一个create()函数从文件里把数据读到一个链表中,之后只要对这个链表操作就可以了。

3.排序
由于每个结构体中的数据比较多,所以如果还是通过对值进行排序,其代码的运行效率显然会比较低,所以考虑直接对链表进行排序。

4.查询
想法:如果数据比较多,每次都遍历一遍显然会导致代码的低效率,所以排序显得格外必要。在排完序的前提下,利用fseek等函数+学号进行查询,效率会高很多。
但是,如果按名字查询,显然还是得遍历。除非再创建一个按名字排序的文件与链表。
最后实现:遍历法查询

5.添加
直接在链表中添加,再重写。

6.删除
直接在链表中删除,再重写。

7.修改
直接在链表中修改,再重写。

8.遍历
直接读取链表。

9.输入输出函数以及格式控制
输出函数printf需要注意控制格式,让输出的数据如表格一样好看。
输入函数可以把scanf分开写,每次输入前给个提示要输入什么。
输入字符串限制长度。

总的思想:把文件操作问题变成链表操作问题,这样,学生信息管理系统就显得格外简单,因为链表的相关操作函数我们已经写过了,只需把之前的函数稍微处理一下,就可以了。

问题:刚刚开始做实验时想把ui画好看一些,想加一个框,但这样的话就需要在每一次输入、输出、回车之后得调节一次光标位置,很复杂。
临时想到一个解决方法:自己这一个print、scan函数,把gotoxy()以及坐标控制也直接加到里面。当然,这样还是很复杂。


运行结果:

在这里插入图片描述

注意:
照搬源码可能会出错,原因是文件名可能不一致(文件路径不一致),这里需要自己根据个人电脑情况修改


源码(共330+行):

//本源码仅供参考学习,远水救不了近火,关键的还是要自己写呀。
//掌握在自己手中的才叫技术。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

typedef struct Student{
   //学生信息包括:学号,姓名,年龄,性别,出生年月,地址,电话,E-mail。
	int number;
	char name[20];
	char age[4];
	char sex[6];
	char birthday[12];
	char address[20];
	char phone[12];
	char email[20];
	struct Student *next;
}Student;

//辅助功能函数 
void Refresh()//刷新界面 
{
   
	system("cls");//清空屏幕 
	printf( "\n"
			"\t|================|\n"
			"\t||录入学生信息:p||\n"
			"\t||浏览学生信息:b||\n"
			"\t||查询学生信息:f||\n"
			"\t||修改学生信息:m||\n"
			"\t||插入学生信息:i||\n"
			"\t||删除学生信息:d||\n"
			"\t||退出学生系统:e||\n"
			"\t|================|\n"
			"\n--------------------------------\n"
			"你想做些什么吗?\n");
}			
Student *Creat()//创建临时链表函数
{
   
	Student *head=NULL,*pre=NULL,*current=NULL;
	FILE *fp;
	if(!(fp=fopen("file1","w"))){
   	//打开文件 
		puts("Cannot open this file!");
		system("pause");
		return head;
	}
	
	char ch=fgetc(fp);
	rewind(fp);//此处很重要,如果丢失了就会出错 ,因为上一条语句后fp不是指向文件开头了 
	if(ch!=EOF){
   //保护机制:判断文件是否为空,解决文件为空的情况 
		head=pre=current=(Student *)malloc(sizeof(Student));//创建链表 
		fread(current,sizeof(Student),1,fp);
		while(current->next){
   
			pre=current;
			current=(Student *)malloc(sizeof(Student));
			pre->next=current;
			fread(current,sizeof(Student),1,fp);
		} 
	}else{
   
		puts("This list is empty.");//提示 
		system("pause");
	} 
	
	fclose(fp);//关闭文件 
	Refresh();//刷新界面 
	return head
  • 14
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
这段代码存在一些问题,我来解释一下: 1. 在函数开头定义了三个指针变量,但只初始化了其中一个(fnl),另外两个(ch和p)没有初始化,这可能导致程序出错。 2. 在第5行中,将fnl指向head的next节点,但此时head指针还未赋值,所以会出现未定义的行为。 3. 在第10行中,如果ch是头节点,那么就将head指针指向head的下一个节点,从而删除了头节点,但是此时没有更新p指针,导致p指向了一个被删除的节点,可能导致程序出错。 4. 在第22行中,应该返回剩余的两个节点中任意一个节点,而不是返回head节点,因为head节点可能已经被删除了。 下面是修改后的代码: ``` node* FindJoseph(node* head, int step) { if (head == nullptr || head->next == nullptr) { return head; // 链表为空或只有一个节点,直接返回 } node* cur = head; while (cur->next != head) { cur = cur->next; // 找到链表最后一个节点 } int num = 1; node* p = cur; // p指向链表的最后一个节点 while (cur != head) { num++; cur = cur->next; } int i = 1; while (num > 2) { if (i % step == 0) { node* ch = p->next; if (ch == head) { head = head->next; } p->next = ch->next; delete ch; num--; } else { p = p->next; } i++; } return head->next; // 返回任意一个剩余的节点 } ``` 这段代码解决了上述问题,并且对代码进行了一些简化,比如直接在链表末尾添加一个新的节点,避免了头节点和尾节点的特殊处理逻辑。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值