学生信息管理系统(C语言)

目录

First.main()

Second.Enter()

Third.Count()

Forth.Delete()

Fifth.Lookup()

Sixth.Modify()

Seventh.Append()

Eighth.Sort()


   本人为大一学生,学C语言时间尚不长,所以本文的解释并不是十分的优美,代码略显臃肿;其次,本人使用的编译器为Visual Studio 2017,有些函数可能与您使用的会有出入(比如scanf与scanf_s,fopen与fopen_s),故请您对于本文仅作参考,希望本文对您有所帮助。


First.main()

首先,本管理系统分为8个函数部分,第一个main()函数部分如下:

#include<stdio.h>
struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10], student1[10];
void functions()
{
	printf("\t-------------------------------------------------------------------------------------------------\n");
	printf("\t|				Functions	   Menu						|\n");
	printf("\t|					1.Enter	(录入)						|\n");
	printf("\t|					2.Delete(删除)					|\n");
	printf("\t|					3.Lookup(查询)					|\n");
	printf("\t|					4.Modify(更改)					|\n");
	printf("\t|					5.Append(添加)						|\n");
	printf("\t|					6.Sort(按成绩排序)					|\n");
	printf("\t|					7.Count(人数)						|\n");
	printf("\t-------------------------------------------------------------------------------------------------\n");
}
int main_n;
int main()
{
	char filename[20];
	printf("please input the filename:\n");
	scanf_s("%s", filename, 20);
	while (1)
	{
		functions();
		if (scanf_s("%d", &main_n) == 1)
		{
			if (main_n <1||main_n>7)
				return 0;
			switch (main_n)
			{
			case 1:
				Enter(filename);
				break;
			case 2:
				Delete(filename);
				break;
			case 3:
				Lookup(filename);
				break;
			case 4:
				Modify(filename);
				break;
			case 5:
				Append(filename);
				break;
			case 6:
				Sort(filename);
				break;
			case 7:
				Count(filename);
				break;
			}
		}
		else 
			return 0;
	}
	return 0;
}

 注:第二行的D:\\c.txt为我已经在D盘中建立的文本文件,在显示出菜单界面后,你只需按下相应功能前的数字即可

 如果你输入的不是数字,又会发生什么呢?结果如下:

 原因戳这里或是这里

这是因为数据不对口,返回值不为1,有兴趣的小伙伴可以试一下%c、%lf等,看看输入不对称的值时scanf_s(scanf)的返回值是多少


Second.Enter()

接下来,编写第二个函数Enter(),可以看出其参量为一个字符指针filename,之后的几个函数也是以字符指针为参量:

#include<stdio.h>
extern struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10], student1[10];
void Enter(char *name)
{
	int enter_n;
	FILE *fp;
	printf("How many students do you want to enter:\n");
	scanf_s("%d", &enter_n);
	printf("Ok!\n");
	errno_t err = fopen_s(&fp, name, "w+");
	if (err != 0)
	{
		printf("error.");
	}
	for (int i = 0; i < enter_n; i++)
	{
		scanf_s("%d", &student[i].iNum);
		scanf_s("%s", student[i].cName, 10);
		scanf_s("%d", &student[i].iScore);
	}
	for (int i = 0; i < enter_n; i++)
	{
		fwrite(&student[i], sizeof(struct Student), 1, fp);
	}
	fclose(fp);//一次fopen对应一次fclose,中间只有一次fopen或一次fclose.
	err = fopen_s(&fp, name, "r+");
	if (err != 0)
	{
		printf("error.");
	}
	for (int i = 0; i < enter_n; i++)
	{
		fread(&student1[i], sizeof(struct Student), 1, fp);
	}
	fclose(fp);
	
}

 注:这里要特别注意的一个前提就是fopen_s和fclose的配对使用,中间只能有一次对文本文件的读取或写入的操作,刚开始编写这个函数时栽了好几个跟头,读者注意这一点

控制台输出如下:


Third.Count()

为了便于读者理解另外几个函数,我们先来介绍Count()函数,其代码如下: 

#include<stdio.h>
extern struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10],student1[10];
int Count(char *filename)
{
	FILE *fp;
	int count_n = 0;
	errno_t err = fopen_s(&fp, filename, "r+");
	if (err != 0)
	{
		printf("error!");
		return 0;
	}
	while(!feof(fp))
	{
		if(fread(&student[count_n], sizeof(struct Student), 1, fp)==1)
		count_n++;
	}
	fclose(fp);
	printf("There are %d students\n", count_n);
	return count_n;
}

这个函数的功能主要是确定文件中学生的人数,先定义一个变量count_n,它的值初始化为0,以便每从文件中读取相应的字节数时它的值相应加1,获得正确的总人数。

这个函数的关键部分是:

while(!feof(fp))
{
	if(fread(&student[count_n], sizeof(struct Student), 1, fp)==1)
	count_n++;
}

通过feof函数我们才得以实现这个功能,相关知识戳这里

而为什么我编写这个函数时它的返回值时count_n呢?我明明可以return 0的啊。

这是因为我的本意是想将这个返回的值用作另外几个函数的参量,另外几个函数也会用到Count()函数的关键代码,这样就可以减少一些代码的重复量,但我并没有这样做是因为我想削弱这几个函数间的关联,让它们各司其职,增强它们的可移植性


 Forth.Delete()

那么接下来就让我们继续了解第四个函数Delete(),先上代码:

#include<stdio.h>
extern struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10], student1[10];

int Delete(char *filename)
{
	FILE *fp;
	int delete_n=0,delete_num=0;
	//delete_n用来保存要删除的数组元素下标,delete_num用来计算总的人数
	errno_t err = fopen_s(&fp, filename, "r+");
	if (err != 0)
	{
		printf("error.");
	}
	while (!feof(fp))
	{
		if (fread(&student1[delete_num], sizeof(struct Student), 1, fp) == 1)
			delete_num++;
	}
	fclose(fp);
	for (int i = 0; i < delete_num; i++)
	{
		printf("%d\t%s\t%d\n", student1[i].iNum, student1[i].cName, student1[i].iScore);
	}
	printf("please input the number of the student you want to delete:\n");
	scanf_s("%d", &delete_n);
	if (delete_n < 0 || delete_n == 0||delete_n>delete_num)
	{
		printf("Sorry,I can't help!Cause you input the wrong number!\n");
		return 0;
	}
	for(int i=delete_n;i< delete_num;i++)
	{
		student1[i-1] = student1[i];
	}//删除的不是对应学号的学生
	err = fopen_s(&fp, filename, "w+");
	if (err != 0)
	{
		printf("error.");
	}
	for (int i = 0; i < delete_num-1; i++)
	{
		fwrite(&student1[i], sizeof(struct Student), 1, fp);
	}
	fclose(fp);
	return 0;
}

注:代码中已经说过,删除的不是对应学号的学生,这里再强调一遍!

执行后控制台中会一行行列出学生的信息,注意,你如果要删除某个同学的信息,直接输入它所在的行数即可

 例如,如果我要删除上图中luog同学的信息,我只需输入2,可如果我输入了他的学号,控制台输出为


 Fifth.Lookup()

第五个函数则是Lookup(),用来查询某个学生的信息,上代码:

#include<stdio.h>
extern struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10], student1[10];
int Lookup(char *filename)
{
	FILE *fp;
	int lookup_n=0,lookup_num=0;
	//lookup_n用来计算有多少个学生,lookup_num用来储存要查询的学生学号
	errno_t err = fopen_s(&fp, filename, "r+");
	if (err != 0)
	{
		printf("error!");
	}

	while (!feof(fp))
	{
		if(fread(&student1[lookup_n],sizeof(struct Student),1,fp)==1)
			lookup_n++;
	}
	fclose(fp);
	for (int i = 0; i < lookup_n; i++)
	{
		printf("%d\t%s\t%d\n", student1[i].iNum, student1[i].cName, student1[i].iScore);
	}
	printf("please input the homologous number of the student:\n");
	scanf_s("%d", &lookup_num);
	for (int i = 0; i < lookup_n; i++)
	{
		if (student1[i].iNum== lookup_num)
		{
			printf("\t\tnumber     name     score\n");
			printf("\t\t%*d%*s%*d\n",6,student1[i].iNum,9, student1[i].cName,10, student1[i].iScore);
			return 0;
		}
	}
	if (lookup_num<0 || lookup_num>lookup_n)
		printf("Sorry,but I don't have the information of the student.\n");
	return 0;
}

这个函数的大部分代码功能前文已经提到,小伙伴们主要的疑问可能是

printf("\t\t%*d%*s%*d\n",6,student1[i].iNum,9, student1[i].cName,10, student1[i].iScore);

为什么会有%*d和%*s中的*呢?这个是为了让输出的代码对齐,如图

并且要注意,这里输入的是学号,不是行数,与Delete()函数刚好相反


Sixth.Modify()

接下来介绍Modify()函数,通过这个函数,我们只要输入对应的学生学号,即可修改对应学生的信息:

#include<stdio.h>
extern struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10], student1[10];
int Modify(char *filename)
{
	FILE *fp;
	int modify_n=0, modify_num=0;
	int iTemp=0;
	//modify_n用来计算学生个数,modify_num用来保存要更改信息的学生的号码,iTemp用来保存对应学生的下标
	errno_t err = fopen_s(&fp, filename, "r+");
	if (err != 0)
	{
		printf("error!");
	}

	while (!feof(fp))
	{
		if (fread(&student1[modify_n], sizeof(struct Student), 1, fp) == 1)
			modify_n++;
	}
	fclose(fp);
	for (int i = 0; i < modify_n; i++)
	{
		printf("%d\t%s\t%d\n", student1[i].iNum, student1[i].cName, student1[i].iScore);
	}
	printf("please input the homologous number of the student:\n");
	scanf_s("%d", &modify_num);
	for (int i = 0; i < modify_n; i++)
	{
		if (student1[i].iNum == modify_num)
		
			iTemp = i;
		
	}
	if (iTemp == 0)
	{
		printf("Not have this student!\n");
		return 0;
	}
	printf("student%d.Num:", iTemp+1);
	scanf_s("%d", &student1[iTemp].iNum);
	printf("student%d.Name:", iTemp+1);
	scanf_s("%s", student1[iTemp].cName,sizeof(student1[iTemp].cName));
	printf("student%d.Score:", iTemp+1);
	scanf_s("%d", &student1[iTemp].iScore);
	putchar('\n');
	err = fopen_s(&fp, filename, "w+");
	if (err != 0)
	{
		printf("error!");
		return 0;
	}
	for (int i = 0; i < modify_n; i++)
	{
		fwrite(&student1[i], sizeof(struct Student), 1, fp);
	}
	fclose(fp);
	return 0;
}

控制台输出为:

在功能菜单下输入4后,控制台自动打印出已储存的学生信息,这时你只要对照学生信息输入对应的学号即可 。利用这个函数,你不仅可以行使修改功能,也可以全部修改达到替换目的。

细心的读者可以发现,本函数的一个变量modify_n、上一个函数的lookup_n、上上个函数的delete_num,以及接下来要讲解的Append()函数的append_n和Sort()函数的sort_n,与我上文说的那样,都与count_n行使着一样的功能,那就是计算人数。


Seventh.Append()

#include<stdio.h>
extern struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10], student1[10];
int Append(char *filename)
{
	FILE *fp;
	int append_n=0;
	//append_n用来保存学生总人数
	errno_t err = fopen_s(&fp, filename, "r+");
	if(err!=0)
	{
		printf("error!");
		return 0;
	}
	while (!feof(fp))
	{
		fread(&student[append_n], sizeof(struct Student), 1, fp);
		append_n++;
	}
	fclose(fp);
	append_n--;
	printf("There are %d students.\n", append_n);
	printf("So student%d.num:", append_n + 1);
	scanf_s("%d", &student[append_n].iNum);
	printf("And student%d.name:", append_n + 1);
	scanf_s("%s", student[append_n].cName,sizeof(student[append_n].cName));
	printf("Then student%d.score:", append_n + 1);
	scanf_s("%d", &student[append_n].iScore);
	err = fopen_s(&fp, filename, "w+");
	if (err != 0)
	{
		printf("error!");
		return 0;
	}
	for (int i = 0; i < append_n + 1; i++)
	{
		fwrite(&student[i], sizeof(struct Student), 1, fp);
	}
	fclose(fp);
	
	return 0;
}

函数Append()有着与Enter()函数类似的功能,不同的是,Append()函数一次只能输入一个学生的信息,控制台输出如下:

 在显示菜单后按5,会显示出“There are X students"的字样,接着会需要你输入新添加的学生的信息,它会自动连接上结构体数组的末尾,即连接上一位同学lu,样式如图:


 Eighth.Sort()

接下来介绍最后一个函数Sort(),先上代码:

#include<stdio.h>
#include<stdlib.h>
extern struct Student
{
	int iNum;
	char cName[10];
	int iScore;
}student[10],student1[10];

int Sort(char *filename)
{
	FILE *fp;
	int sort_n = 0;
	//sort_n用来计算学生个数
	struct Student t;
	errno_t err = fopen_s(&fp, filename, "r+");
	if (err != 0)
	{
		printf("error!");
		return 0;
	}
	while (!feof(fp))
	{
		if (fread(&student[sort_n], sizeof(struct Student), 1, fp)==1)
			sort_n++;
	}

	fclose(fp);
	/*for (int i = 0; i < sort_n - 1; i++)
	{
		for (int j = i; j < sort_n - 1; j++)
		{
			if (student[i].iScore < student[j + 1].iScore)//若将iScore改成iNum,则按照学号排序
			{
				t = student[i];
				student[i] = student[j + 1];
				student[j + 1] = t;
			}
		}
	}		//交换排序*/
	/*for (int i = 0; i < sort_n-1; i++)
	{
		t = student[i];
		int iTemp = i;
		//iTemp用来保存对应学生的下标
		for (int j = i + 1; j < sort_n; j++)
		{
			if (t.iScore < student[j].iScore)
			{
				t = student[j];
				iTemp = j;
			}
		}
		student[iTemp] = student[i];
		student[i] = t;
	}		//选择排序*/
	/*for (int i = 0; i < 10; i++)
	{
		int iTemp=i;//保存特定学生的下标
		t = student[i]; 
		while ((iTemp-1 >= 0) && (t.iScore > student[iTemp - 1].iScore))
		{
			student[iTemp] = student[iTemp - 1];
			iTemp--;
		}
		student[iTemp] = t;
	}		//插入排序*/
	/*for (int i = 0; i < sort_n ; i++)
	{
		for (int j = sort_n-1; j > i; j--)
		{
			if (student[j].iScore > student[j - 1].iScore)
			{
				t = student[j];
				student[j] = student[j-1];
				student[j - 1] = t;
			}
		}
	}		//冒泡排序*/
	
	err = fopen_s(&fp, filename, "w+");
	if (err != 0)
	{
		printf("error!");
		return 0;
	}
	for (int i = 0; i < sort_n; i++)
	{
		fwrite(&student[i], sizeof(struct Student), 1, fp);
	}
	fclose(fp);
	printf("I have order the array!\n");
	for (int i = 0; i < sort_n; i++)
	{
		printf("%d\t%s\t%d\n", student[i].iNum, student[i].cName, student[i].iScore);
	}
	return 0;
}

用/**/括起来的那四段代码,你可以随意选一段去掉/**/后进行使用,这些排序均是按照学生的成绩进行排列的,如果要按照学号排列,只需将iScore改成iNum.

需要注意:

图右下角显示“不能将'struct Student'类型的值分配到'struct Student'类型的实体”,但实际上可以强

制进行使用。

好了,本篇内容到此结束,愿对君有益。


我的下一篇博客:一题多解×1

我的上一篇博客:无

  • 19
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔走的月光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值