学生管理系统总结

一、文件的读取、写入和保存

1.1 文件的读取和写入

        首先先给出我的结构体变量。

typedef struct node {
	char name[20];//姓名
	char number[20];//学号
	char iclass[20];//班级
	int chinese;//语文成绩
	int math;//数学成绩
	int english;//英语成绩
	char keyword[20];//密码

	struct node* next;
}node;

        因为所给的文件是有五个文件,且文件名有规律递增,因此想要将五个文件一次性全部读取并存在链表中,应该通过字符串转换,字符串连接等方式将其依次打开并读取。

        在此之前,先创建一个全局变量的链表头节点,在读取数据的同时,将其存放在新节点中,然后将新节点从末尾插入链表,最后关闭文件。

        因为我将学生信息和账号密码以及教师的账号密码是分开文件存储的,因此我分别写了读取信息和账号文件的函数。

  * 读取和写入学生信息

void getinfo() {
	for (int i = 0; i < 5; i++) {
		char* file[200] = { 0 };
		sprintf(file, "C:\\student\\class%d.txt", i + 1);//文件名是class1,class2...class5
		FILE* fp = fopen(file, "r");//以只读的方式打开
		if (fp == NULL) {//当文件中无数据时结束函数
			return;
		}

		node* head = NULL;//head为链表头节点,是全局变量
		char name[20], iclass[20],number[20];//学号也要定义为字符串
		int chinese, math, english;
		while (fscanf(fp, "%s %s %s %d %d %d", name, number, iclass, &chinese, &math, &english) != EOF) { //当文件没读取到末尾时循环
            //将读到的数据放入新节点,并将新节点插入链表
			node* newnode = createnode(name, number, iclass, chinese, math, english);
			
			if (newnode == EOF) {
				return;
			}
			addnode(newnode);
		}
		fclose(fp);
		fp = NULL;
	}

        因为我将学生和教师信息是放入两个文件的,因此教师信息的读取也是类似操作。

1.2 文件的保存

        在学生管理系统中需要将修改过的文件数据再重新存入文件,因此,需要一个保存数据进文件的函数。我的思路仍然是,以只写的方式打开文件,然后定义一个指针p指向头节点,并且开始遍历链表,每当遍历一个节点,就用fprintf将节点的数据写入文件,因为文件是按班级分的,因此遍历时还需要对班级作判断。最后关闭文件,完成保存。

*保存学生信息

void saveinfo1() {
	FILE* fp = fopen("C:\\student\\class1.txt", "w");//以只写打开文件
	node* p = head;//定义指针p指向头节点
	while (p) {//遍历链表
		if (strcmp(p->iclass, "网络1班") == 0) { //要对每个节点的结构体中的班级进行判断
			fprintf(fp, "%s %s %s %d %d %d\n", p->name, p->number, p->iclass, p->chinese, p->math, p->english); //写入文件
		}
		p = p->next;
	}
	fclose(fp);
}

二、寻找节点的函数

        在学生管理系统中,因为是使用链表,所以一定少不了一些链表的基本的函数和遍历链表去寻找节点的函数等。

2.1 寻找节点

        链表的一些基本函数如创建节点,初始化,插入等就不多赘述了。在整个程序中,遍历链表去寻找节点的函数用的很多,这就是链表基本功能的查询。我在后续代码中会有通过姓名、学号、班级等信息进行寻找节点的操作。就是通过传入要查找的数据进这个函数,然后遍历链表,比对各节点结构体中相应的数据,当找到要找的那个节点时,就返回那个节点。

*寻找对应姓名的节点

node* findname(char *name) {
	node* p = head;
	while (p) { //遍历链表
		if (strcmp(p->name, name) == 0) { //当遍历到的节点的姓名和所找的姓名相同时返回对应节点
			return p;
		}
		p = p->next;
	}
	return NULL; //若没有找到则返回空
}

2.2 打印链表

        同样定义一个指针指向头节点,然后依次遍历链表中的节点,再将每一个遍历到的节点的数据打印出来。

void printflist(struct node* head) {//打印
	printf("姓名\t学号\t班级\t语文\t数学\t英语\n");
	struct node* tamp = head;
	while (tamp != NULL) {
		printf("%s\t%s\t%s\t%d\t%d\t%d\n", tamp->name, tamp->number, tamp->iclass, tamp->chinese, tamp->math, tamp->english);
		tamp = tamp->next;
	}
	printf("\n");
	system("pause");
}

2.3 打印节点

        输出相应节点的数据

void printfnode(struct node* anode) {
	if (anode) {
		printf("%s\t%s\t%s\t%d\t%d\t%d\n", anode->name, anode->number, anode->iclass, anode->chinese, anode->math, anode->english);
	}
	else {
		return;
	}
}

2.4 输入信息并加入链表

void peoplein() {
	struct node* p = head;
	struct node a;
	int b;
	while (1) {
		printf("请输入姓名 学号 班级 语文 数学 英语:\n");
		scanf("%s%s%s%d%d%d", a.name, a.number, a.iclass, &a.chinese, &a.math, &a.english);
		struct node* r = findnumber(a.number);
		if (r) {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                         学号已存在                           *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			getchar();
			return;
		}
		if ((strcmp(a.iclass, "网络1班") != 0) && (strcmp(a.iclass, "网络2班") != 0) && (strcmp(a.iclass, "网络3班") != 0) && (strcmp(a.iclass, "网络4班") != 0) && (strcmp(a.iclass, "网络5班") != 0)) {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                        班级输入错误                          *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			getchar();
			return;
		}
		else {
			struct node* q = findclass(a.iclass);
			while (strcmp(q->next->iclass, a.iclass) == 0) {
				q = q->next;
			}
			struct node* w = createnode(a.name, a.number, a.iclass, a.chinese, a.math, a.english);
			w->next = q->next;
			q->next = w;
			printf("是否继续输入?(是:1,否:0)\n");
			scanf("%d", &b);
			if (b == 0) {
				break;
			}
		}
	}
	saveinfo1();
	saveinfo2();
	saveinfo3();
	saveinfo4();
	saveinfo5();
	system("cls");
	int add = 0;
	while ((add = getchar()) != '\n') {
		;
	}
	return;
}

三、学生管理系统功能

3.1 主界面功能

        我本次学生管理系统功能分为了账户设置和登录两部分以及退出系统,其中账户设置分别可以注册密码修改密码找回密码;登录分别可以学生登录教师登录管理员登录。在学生中,注册、修改和登录账户可以使用学号也可以使用姓名

*主界面学生管理系统总结_第1张图片

 3.2 注册,修改,找回账户

        注册:输入要注册的学生姓名或学号(此处只有存在于文件中的学生才能注册,陌生人无法注册)。然后遍历链表寻找对应的节点,首先要检查该节点中结构体的密码是否存在(即长度是否大于0),若存在,则说明账号已经注册过了,无法重复注册。若没有注册,就可以输入密码来设置,输入完成后将密码strcpy进结构体的密码中,最后保存进相应文件。完成账户的注册。

*按姓名注册

void nameenroll(char* name) { 
	while (1) {
		system("cls");
		struct node* p = findname(name); //查询输入的姓名的相应节点
		if (p) {
			if (strlen(p->keyword) > 0) { //当密码长度大于0,即该账户已经注册过时
				printf("----------------------------------------------------------------\n");
				printf("*                  账户已存在,无法重复注册                    *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				system("cls");
				nameenrollx();
			}
			else {
				while (1) {
					printf("----------------------------------------------------------------\n");
					printf("*                         请输入密码                           *\n");
					printf("----------------------------------------------------------------\n");
					char xkeyword[20];
					int i = 0;
					while (xkeyword[i] != '\n' && xkeyword[i] != '\r') { //此处是隐式输入密码
						xkeyword[i] = _getch();
						if (xkeyword[i] < 33 || xkeyword[i] > 126) {
							printf("\b");
							_putch(' ');
							printf("\b");
							continue;
						}
						else if (xkeyword[i] != '\r' && xkeyword[i] != '\b') {
							if (!isdigit(xkeyword[i]) && !isalpha(xkeyword[i])) {
								continue;
							}
							printf("*");
							i++;
							if (i > 20) {
								system("cls");
								printf("----------------------------------------------------------------\n");
								printf("*                         密码设置太长                         *\n");
								printf("----------------------------------------------------------------\n");
								system("pause");
								nameenroll(name);
							}
						}
						else if (xkeyword[i] == '\b' && i > 0) {
							printf("\b");
							_putch(' ');
							printf("\b");
							--i;
							continue;
						}
					}
					xkeyword[i] = '\0';
					strcpy(p->keyword, xkeyword); //将新输入的密码放进结构体中
					system("cls");
					printf("----------------------------------------------------------------\n");
					printf("*                         注册成功!                           *\n");
					printf("----------------------------------------------------------------\n");
					save(); //此函数是我写的用来保存进文件的
					getchar();
					system("pause");
					system("cls");
					directory();
				}
			}
		}
		else {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                         姓名不存在                           *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			enroll();
		}
	}

}

        修改:和注册差不多,同样是遍历链表找出相应名字或学号的节点,不过要判断是否注册过,并且要判断第一次输入的密码是否和原密码相同。

*按姓名修改

void NameChang() {
	printf("----------------------------------------------------------------\n");
	printf("*                         请输入姓名                           *\n");
	printf("----------------------------------------------------------------\n");
	char namein[20];
	scanf("%s", namein);
	node* p = findname(namein); //寻找相应节点
	if (p) {
		if (strlen(p->keyword) == 0) { //对节点结构体的密码进行判断,看有没有注册

			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                        此学生还未注册                        *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			NameChang();
		}
		else {
			int n = 5;
			while (n > 0) {
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                         请输入原密码                         *\n");
				printf("----------------------------------------------------------------\n");
				char okey[20];
				int i = 0;
				while (okey[i] != '\n' && okey[i] != '\r') {
					okey[i] = _getch();
					if (okey[i] < 33 || okey[i] > 126) {
							printf("\b");
							_putch(' ');
							printf("\b");
							continue;
						}
						else if (okey[i] != '\r' && okey[i] != '\b') {
						if (!isdigit(okey[i]) && !isalpha(okey[i])) {
							continue;
						}
						printf("*");
						i++;
						if (i > 20) {
							system("cls");
							printf("----------------------------------------------------------------\n");
							printf("*                         密码输入太长                         *\n");
							printf("----------------------------------------------------------------\n");
							system("pause");
							NameChang();
						}
					}
					else if (okey[i] == '\b' && i > 0) {
						printf("\b");
						_putch(' ');
						printf("\b");
						--i;
						continue;
					}
				}
				okey[i] = '\0';

				if (strcmp(p->keyword, okey) == 0) {
					system("cls");
					printf("----------------------------------------------------------------\n");
					printf("*                         请输入新密码                         *\n");
					printf("----------------------------------------------------------------\n");
					char changekey[20];
					int i = 0;
					while (changekey[i] != '\n' && changekey[i] != '\r') {
						changekey[i] = _getch();
						if (changekey[i] < 33 || changekey[i] > 126) {
							printf("\b");
							_putch(' ');
							printf("\b");
							continue;
						}
						if (changekey[i] != '\r' && changekey[i] != '\b') {
							if (!isdigit(changekey[i]) && !isalpha(changekey[i])) {
								continue;
							}
							printf("*");
							i++;
							if (i > 20) {
								system("cls");
								printf("----------------------------------------------------------------\n");
								printf("*                         密码设置太长                         *\n");
								printf("----------------------------------------------------------------\n");
								system("pause");
								NameChang();
							}
						}
						else if (changekey[i] == '\b' && i > 0) {
							printf("\b");
							_putch(' ');
							printf("\b");
							--i;
							continue;
						}
					}
					changekey[i] = '\0';
					if (strcmp(okey, changekey) == 0) {
						system("cls");
						printf("----------------------------------------------------------------\n");
						printf("*                   新密码不能与原密码相同                     *\n");
						printf("----------------------------------------------------------------\n");
						system("pause");
						system("cls");
						NameChang();
					}
					else {
						strcpy(p->keyword, changekey);
						save();
						system("cls");
						printf("----------------------------------------------------------------\n");
						printf("*                         修改成功!                           *\n");
						printf("----------------------------------------------------------------\n");
						system("pause");
						system("cls");
						getchar();
						directory();
					}
				}
				else {
					system("cls");
					n--;
					printf("----------------------------------------------------------------\n");
					printf("*               (╯▔皿▔)╯密码错误!还可输入%d次             *\n",n);
					printf("----------------------------------------------------------------\n");
					system("pause");
					int add = 0;
					while ((add = getchar()) != '\n') {
						;
					}
					system("cls");
				}
			}
		}
	}
	else {
	system("cls");
		printf("----------------------------------------------------------------\n");
		printf("*                (╯▔皿▔)╯姓名错误!!!!                  *\n");
		printf("----------------------------------------------------------------\n");
		system("pause");
		system("cls");
		ChangKey();
	}
}

        找回密码:这一块我的思路是,分别输入姓名、学号、班级,若能和文件中对应的学生信息一一对上,就输出密码。即对姓名、学号、班级分别在链表中遍历,若遍历到的姓名学号节点相同且班级和前两个节点结构体中信息相同,则输出密码。当然,同样是要对其密码长度进行判断,即判断该生是否注册。

*找回密码

void findkey() {
	system("cls");
	printf("----------------------------------------------------------------\n");
	printf("*                         请输入姓名                           *\n");
	printf("----------------------------------------------------------------\n");
	char name_q[20];
	scanf("%s", name_q);
	system("cls");
	printf("----------------------------------------------------------------\n");
	printf("*                         请输入学号                           *\n");
	printf("----------------------------------------------------------------\n");
	char num[20];
	scanf("%s", num);
	system("cls");
	printf("----------------------------------------------------------------\n");
	printf("*                         请输入班级                           *\n");
	printf("----------------------------------------------------------------\n");
	char fclass[20];
	scanf("%s", fclass);
	struct node* p = findname(name_q);
	struct node* q = findnumber(num);
	if (p && q && p == q && strcmp(p->iclass,fclass) == 0) {
		if (strlen(p->keyword) > 0) {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("            你的密码是:%s                           \n", p->keyword);
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			getchar();
			directory();
		}
		else {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                       该学生未注册                           *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			getchar();
			directory();
		}
	}
	else {
		system("cls");
		printf("----------------------------------------------------------------\n");
		printf("*                  信息输入错误,无法找回密码                  *\n");
		printf("----------------------------------------------------------------\n");
		system("pause");
		system("cls");
		getchar();
		directory();
	}
}

3.3 登录操作

        登录操作即输入姓名或学号,然后在链表中遍历,判断相应的节点是否存在,若存在,还要判断密码长度即判断是否注册。然后判断输入的密码和相应节点的结构体中密码是否相等。教师的登录也是相应操作。

*学生按姓名登录

void namelogin() {
	printf("----------------------------------------------------------------\n");
	printf("*                         请输入姓名                           *\n");
	printf("----------------------------------------------------------------\n");
	char name_q[20];
	scanf("%s", name_q);
	node* q = findname(name_q);
	if (q == NULL) {
		system("cls");
		printf("----------------------------------------------------------------\n");
		printf("*                        该账号不存在                          *\n");
		printf("----------------------------------------------------------------\n");
		system("pause");
		system("cls");
		getchar();
		directory();
	}
	if (strlen(q->keyword) == 0) {
		system("cls");
		printf("----------------------------------------------------------------\n");
		printf("*                         该生还未注册                         *\n");
		printf("----------------------------------------------------------------\n");
		system("pause");
		system("cls");
		getchar();
		directory();
	} else {
	int n = 0;
	while (n < 5)
	{
		if (q) {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                         请输入密码                           *\n");
			printf("----------------------------------------------------------------\n");
			char keywordx[20];
			int i = 0;
			while (keywordx[i] != '\n' && keywordx[i] != '\r') {
				keywordx[i] = _getch();
				if (keywordx[i] < 33 || keywordx[i] > 126) {
					printf("\b");
					_putch(' ');
					printf("\b");
					continue;
				}
				else if (keywordx[i] != '\r' && keywordx[i] != '\b') {
					if (!isdigit(keywordx[i]) && !isalpha(keywordx[i])) {
						continue;
					}
					printf("*");
					i++;
					if (i > 20) {
						system("cls");
						printf("----------------------------------------------------------------\n");
						printf("*                         密码输入太长                         *\n");
						printf("----------------------------------------------------------------\n");
						system("pause");
						namelogin();
					}
				}
				else if (keywordx[i] == '\b' && i > 0) {
					printf("\b");
					_putch(' ');
					printf("\b");
					--i;
					continue;
				}
			}
			keywordx[i] = '\0';
			if (strcmp(keywordx, q->keyword) == 0) {
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                         登录成功!                           *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				system("cls");
				getchar();
				studirectory(q);  
			}
			else {
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                   登录失败!还可尝试%d次                     *\n", 5 - n);
				printf("----------------------------------------------------------------\n");
				system("pause");
				
				n++;
				int add = 0;
				while ((add = getchar()) != '\n') {
					;
				}
				system("cls");
			}
		}
	}
	}

	system("cls");
	printf("----------------------------------------------------------------\n");
	printf("*                         登录失败!                           *\n");
	printf("----------------------------------------------------------------\n");
	system("pause");
	system("cls");
	getchar();
	directory();
}

        而管理员登录和学生教师不同,我是给管理员了一个内测码,通过输入管理员内测码来进行登录。

void admlogin() {
	system("cls");
	printf("----------------------------------------------------------------\n");
	printf("*                     请输入管理员内测码                       *\n");
	printf("----------------------------------------------------------------\n");
	char arr[20];
	int i = 0;
	while (arr[i] != '\n' && arr[i] != '\r') {
		arr[i] = _getch();
		if (arr[i] < 33 || arr[i] > 126) {
			printf("\b");
			_putch(' ');
			printf("\b");
			continue;
		}
		if (arr[i] != '\r' && arr[i] != '\b') {
			if (!isdigit(arr[i]) && !isalpha(arr[i])) {
				continue;
			}
			printf("*");
			i++;
			if (i > 20) {
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                        内测码输入太长                        *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				namelogin();
			}
		}
		else if (arr[i] == '\b' && i > 0) {
			printf("\b");
			_putch(' ');
			printf("\b");
			--i;
			continue;
		}
	}
	arr[i] = '\0';
	if (strcmp(arr, "woshiguanliyuan") == 0) {
		system("cls");
		printf("----------------------------------------------------------------\n");
		printf("*                        内测码正确                            *\n");
		printf("----------------------------------------------------------------\n");
		system("pause");
		system("cls");
		getchar();
		administrator();
	}
	else {
		system("cls");
		printf("----------------------------------------------------------------\n");
		printf("*                        内测码错误                            *\n");
		printf("----------------------------------------------------------------\n");
		system("pause");
		system("cls");
		getchar();
		directory();
	}
}

3.4 学生界面功能

        我的学生功能有查询自己的成绩,查询本班的成绩,查询排序后的成绩以及申诉成绩。学生管理系统总结_第2张图片

         我的学生界面函数是需要一个参数节点的,这个参数节点就是登录操作时通过姓名或学号遍历到的节点,该节点的结构体保存了登陆者的相关信息。因此在学生界面中可输出登录者个人信息。

        成绩查询:用打印节点的函数打印出相应的节点的数据。

        查询本班成绩:遍历链表,当遍历到的节点的班级和登录者的班级相同时,用打印节点的函数打印出该节点。

        成绩分析:首先对链表中的成绩进行排序,此处我用的是冒泡排序,返回排序后的链表的头节点,然后通过打印链表的函数将链表节点数据打印出来。

       此处排完序后原来的链表顺序会乱,因此最好新开一个链表将原链表复制过去再进行操作,这里我没这么写,所以我只能打印完后重新读取一遍文件的数据放进链表。我这样应该是不对的还是要新开链表好一点。

for (node* q = p; q->next != NULL; q = q->next) {
			for (node *m = q->next; m != NULL; m = m->next) {
				if (!cmpchinese(*q, *m)) {
					node t = *q;
					*q = *m;
					*m = t;
					t.next = q->next;
					q->next = m->next;
					m->next = t.next;
				}
			}
		}
		return p;
system("cls");
		node* g = stusort();
		printflist(g);
		head = NULL;
		getinfo();
		system("pause");
		system("cls");
		getchar();
		directory();

        成绩申诉:这里我是先定义一个全局变量的字符串,当登录者申诉成绩后将其学号放入字符串,在管理员待办中若该字符串长度大于0,则说明有学生在申诉,然后遍历链表找到该学号的节点,打印出来此节点的数据,使管理员进行检查,然后管理员选择是否进行修改。

3.5 教师界面操作

学生管理系统总结_第3张图片

         教师界面的功能可以对学生信息进行增删改查,保存文件以及对管理员进行更新提醒。教师界面同样是有一个参数节点,是登录时遍历到的节点。通过这个节点来判断教师班级,因此来判断是否可以对学生操作。

        增加学生信息:通过输入信息并加入链表的函数来实现。在二中已经贴过了代码。

        删除学生信息:同样有两种方式:姓名和学号。先寻找到姓名或学号相应的节点。但此处若输入的学生并非自己班的,则无法删除。若是自己班的,因为头节点head是也存储学生数据的,所以先开辟一个新节点指向head,作为它的哑节点。当要删除的学生信息就在头节点存放,则直接将头节点后移一位完成删除。若不是,则使哑节点向后遍历,直到哑节点的下一个节点是学号或姓名相对应的那个节点,然后将哑节点的下一个指向要删除节点的下一个,并且释放被删除的节点,完成删除操作。最后保存一下文件。

system("cls");
		printf("----------------------------------------------------------------\n");
		printf("*                     请输入要删除的姓名                       *\n");
		printf("----------------------------------------------------------------\n");
		char name_e[20];
		scanf("%s", name_e);
		struct node* p = findname(name_e);
		if (p && strcmp(p->iclass, teanode->tclass) == 0) {
			struct node* q = (struct node*)malloc(sizeof(struct node));
			q->next = head;
			if (p == head) {
				head = p->next;
			}
			if (p != head) {
				while (q->next != p) {
					q = q->next;
				}
				q->next = p->next;
				free(p);
			}
			saveinfo1();
				saveinfo();
				save();
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                        删除成功!                            *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				system("cls");
				getchar();
				teadirectory(teanode);
		}
		else if(p == NULL) {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                     要删除的姓名不存在                       *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			getchar();
			deletestu(teanode);
		}
		else if (p && strcmp(p->iclass, teanode->tclass) != 0) {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                        这不是你班学生                        *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			getchar();
			deletestu(teanode);
		}

        修改学生信息:输入相应的学生姓名或学号,遍历链表找到相应节点,然后判断学生和教师班级是否相同,最后对节点的结构体的数据进行修改。寻找和判断节点的操作和删除学生信息类似,修改的操作和修改密码的类似。

        查询学生信息:输入相应的学生姓名或学号,遍历链表找到相应节点,然后将该生信息通过打印节点的函数打印出来。

        输出本班成绩:遍历链表,将遍历到的节点的班级和登录的教师的参数节点的班级进行比较,若相同,则打印该节点,若不相同则不打印。

struct node* q = head;
		system("cls");
		printf("姓名\t学号\t班级\t语文\t数学\t英语\n");
		while (q) {
			if (strcmp(q->iclass, p->tclass) == 0) { //该处的p是教师的参数节点
				printfnode(q);
			}
			q = q->next;
		}
		system("pause");
		system("cls");
		getchar();
		teadirectory(p);

        下载到文件:我认为该操作就是手动保存数据到文件中,因此此功能就是运行一下保存文件的相关函数的代码。

        成绩分析:和学生界面的成绩分析一样,对各科成绩进行排序后打印链表。

        提醒管理员进行成绩分析:这里我和成绩申诉差不多,就是定义了一个整数全局变量,每当有教师进行提醒时,将该变量加一,在管理员待办中就可以看见有几个教师请求更新。

3.6 管理员界面功能

学生管理系统总结_第4张图片

        管理员进行的增删改查主要是对学生和教师的账号密码的,当然对学生信息是可以增加的。管理员待办处理的是学生发来的成绩申诉和教师的更新提醒。

        管理员待办:学生管理系统总结_第5张图片

         成绩申诉:定义的全局变量字符串存着学生学号,管理员这里先遍历链表找到对应学生学号的节点,然后将该节点打印出来,管理员对成绩进行查看,判断是否需要修改。

system("cls");
		if (strlen(todo1) > 0) { //todo1就是定义的字符串全局变量,判断其长度其实就是判断是否有学生申诉
			node* p = findnumber(todo1); //找到该学号的节点
			system("cls");
			printf("姓名\t学号\t班级\t语文\t数学\t英语\n");
			printfnode(p);
			getchar();
			system("pause");
			printf("----------------------------------------------------------------\n");
			printf("*                 是否进行修改(是:1 || 否:0)               *\n");
			printf("----------------------------------------------------------------\n");
			int choice;
			scanf("%d", &choice);
			if (choice == 1) {
				system("cls");
				int chinese_c, math_c, english_c;
				printf("----------------------------------------------------------------\n");
				printf("*                        请选择修改内容                        *\n");
				printf("*                         1. 修改语文成绩                      *\n");
				printf("*                         2. 修改数学成绩                      *\n");
				printf("*                         3. 修改英语成绩                      *\n");
				printf("----------------------------------------------------------------\n");
				int choice_2;
				scanf("%d", &choice_2);
				switch (choice_2) {
				case 1: system("cls");
					printf("----------------------------------------------------------------\n");
					printf("*                    请输入要修改的语文成绩                    *\n");
					printf("----------------------------------------------------------------\n");
					scanf("%d", &chinese_c);
					p->chinese = chinese_c;
					getchar();
					break;
				case 2: system("cls");
					printf("----------------------------------------------------------------\n");
					printf("*                    请输入要修改的数学成绩                    *\n");
					printf("----------------------------------------------------------------\n");
					scanf("%d", &math_c);
					p->math = math_c;
					break;
				case 3: system("cls");
					printf("----------------------------------------------------------------\n");
					printf("*                    请输入要修改的英语成绩                    *\n");
					printf("----------------------------------------------------------------\n");
					scanf("%d", &english_c);
					p->english = english_c;
					getchar();
					break;
				default:printf("----------------------------------------------------------------\n");
					printf("*                           输入错误                           *\n");
					printf("----------------------------------------------------------------\n");
					system("pause");
					system("cls");
					getchar();
					admtodo();
				}
				saveinfo1();
				saveinfo2();
				saveinfo3();
				saveinfo4();
				saveinfo5();
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                           修改完成                           *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				system("cls");
				getchar();
				administrator();
			}
			if (choice == 0) {
				system("cls");
				getchar();
				administrator();
			}
			else {
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                           输入错误                           *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				system("cls");
				getchar();
				administrator();
			}
		}
		else {
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                      没有学生申诉成绩哦                      *\n");
			printf("----------------------------------------------------------------\n");
			system("pause");
			system("cls");
			getchar();
			administrator();
		}

        更新成绩库:当整数全局变量大于0时,即说明有教师请求更新,此时管理员进行手动更新一遍数据并存入文件。我认为这里也是运行一遍保存文件的函数,只不过和教师不同的是这里是将所有班级的文件保存一遍,而教师是只保存自己班的。

        进入教师界面:跳转到教师界面的函数。

        增加账号和密码:首先要学生或教师输入学号或教师号,然后遍历链表找到相应的节点,然后要判断该节点的结构体中密码的长度,即判断该账号是否注册过。若没有注册过,则为其添加密码到结构体中。

        删除账号和密码:教师账号删除和删除学生信息的操作差不多,不过是在保存账号和密码的文件中进行操作的。但是因为学生的密码和其他个人信息是在一个结构体中存储的,所以学生的删除时只要将密码的长度置为0就行。然后再进行一遍保存进文件的操作,再保存进文件的操作中我是写的若密码长度大于0才写入文件,否则不写入。因此这样就将学生在账号密码文件中的信息删除了。

FILE* fp = fopen("C:\\student\\password.txt", "r");
			if (fp == NULL) {
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                      当前无学生账号                          *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				system("cls");
				getchar();
				administrator();
			}
			system("cls");
			printf("----------------------------------------------------------------\n");
			printf("*                      请输入学生学号                          *\n");
			printf("----------------------------------------------------------------\n");
			char num[20];
			scanf("%s", num);
			struct node* p = findnumber(num);
			if (p) {
				if (strlen(p->keyword) > 0) {
					strcpy(p->keyword, ""); //将学生密码长度置为0
					save();
					system("cls");
					printf("----------------------------------------------------------------\n");
					printf("*                         删除成功!                           *\n");
					printf("----------------------------------------------------------------\n");
					system("pause");
					system("cls");
					getchar();
					administrator();
				}
				else {
					system("cls");
					printf("----------------------------------------------------------------\n");
					printf("*                       该学生未注册                           *\n");
					printf("----------------------------------------------------------------\n");
					system("pause");
					system("cls");
					getchar();
					administrator();
				}
			}
			else {
				system("cls");
				printf("----------------------------------------------------------------\n");
				printf("*                         学生不存在                           *\n");
				printf("----------------------------------------------------------------\n");
				system("pause");
				system("cls");
				getchar();
				administrator();
			}

        修改账号和密码:也是先遍历找到相应节点再将该节点结构体中的数据进行修改并保存。和前面的所以修改操作类似。

        查找账号和密码:输入学号或教师号后进行遍历,找到相应节点后打印出账号和密码。

        录入所有账号和密码:将学生和教师的账号文件进行手动保存。

        输出所有账号及密码:定义指针指向学生或教师的账号密码文件的头节点,然后对链表进行遍历,将每一个账号密码存在的节点打印出来。

        手动重新录入学生信息:利用前面提到的输入信息并加入链表的函数来新增学生信息到链表中并保存文件。

四、写学生管理系统中学到的

4.1 system函数

        system函数已经被收录在标准c库中,可以直接调用。

system("cls");

        该函数在运行时可以将小黑框内的内容清空,使程序的界面更简洁美观

system("pause");

        该函数就是类似于“Press any key to continue . . .”,等待用户按任意键,然后返回。如果去掉 system(“pause”);控制台程序会一闪而过,来不及看结果。
 

4.2 getchar();

        getchar()函数实际上是int getchar(void),只要是ASCII码表里有的字符它都能读取出来。在调用getchar()函数时,编译器会依次读取用户键入缓存区的一个字符(注意这里只读取一个字符,如果缓存区有多个字符,那么将会读取上一次被读取字符的下一个字符),如果缓存区没有用户键入的字符,那么编译器会等待用户键入并回车后再执行下一步 (注意键入后的回车键也算一个字符,输出时直接换行)。

        通过getchar这样的特性,我们可以利用它来清空缓存区。

4.3 隐式输入密码

        隐式输入密码就是输入密码时,将输入的内容变为星号(*)来达到隐藏密码的效果。这里用到的函数是getch(),它可以接收键盘上输入的一个字符。因此这里需要定义一个字符串,然后使用循环来输入密码的每一个字符。因为用getch输入的字符并不会在界面上显示出来,所以在getch了以后,打印一个星号(*)。同时也要判断输入的字符是否为退格键或功能键,若是退格键,则打印退格并让数组下标减一。若为功能键则不进行显示。直到getch()接收到了回车或空格就跳出循环,并将数组的最后一位置为'\0'。

char xkeyword[20];
					int i = 0;
					while (xkeyword[i] != '\n' && xkeyword[i] != '\r') {
						xkeyword[i] = _getch();
						if (xkeyword[i] < 33 || xkeyword[i] > 126) {
							printf("\b");
							_putch(' ');
							printf("\b");
							continue;
						}
						else if (xkeyword[i] != '\r' && xkeyword[i] != '\b') {
							if (!isdigit(xkeyword[i]) && !isalpha(xkeyword[i])) {
								continue;
							}
							printf("*");
							i++;
							if (i > 20) {
								system("cls");
								printf("----------------------------------------------------------------\n");
								printf("*                         密码设置太长                         *\n");
								printf("----------------------------------------------------------------\n");
								system("pause");
								nameenroll(name);
							}
						}
						else if (xkeyword[i] == '\b' && i > 0) {
							printf("\b");
							_putch(' ');
							printf("\b");
							--i;
							continue;
						}
					}
					xkeyword[i] = '\0';

4.4 利用(while(getchar() != '\n');)消除回车

        除了getchar();也可以用一个while循环来消除回车。

int add = 0;
	while ((add = getchar()) != '\n') {
		;
	}

你可能感兴趣的:(链表)