登录注册功能
main.c
#include <stdio.h>
#include "类型.h"//专门用来声明一些类型
#include "list.h"
#include "tool.h"
#include "login.h"
int main(){
struct Node* list = NULL;
loginWelcome(&list);
return 0;
}
类型.h
#pragma once
/*
一科的信息
*/
struct ExamResult{
char subjectName[20]; //科目名
int grade; //当科成绩
};
//学生类型
struct Student{
int id; //学生id 防止名字相同造成影响
char name[20]; //姓名
char num[12]; //学号
char classes[20]; //班级
//组成成绩的信息
int subjectNum; //考试科目数
struct ExamResult* pGrades; /*科目信息(动态数组)一个学生保存在一个数组太浪费空间
做动态数组 一个指针变量,保存动态内存分配的首地址
如果学生有3科指针就指向3个结构体的数组的首地址*/
};
//注册类型 (老师 管理者)端 (学生 用户)端 数据相同,操作功能不同
struct registClass{
int lx; //类型 1 为老师 2 为学生
int id; //id
char userName[20]; //用户名
char passWord[20]; //密码
};
//老师可以删除学生,学生只能看
//链表节点类型
struct Node{
struct Student pData; //保存学生
struct Node* pNext; //保存下一个节点的地址
};
//STU即为 struct Student 类型
typedef struct Student STU;
//EXAMRET即为 struct ExamResult 类型
typedef struct ExamResult EXAMRET;
//日志文件名
#define LOGFILENAME "logFile.log"
list.h
链表-->把链表相关的所有功能(在list.h和list.c中)实现
#pragma once
#include "类型.h"
#include <stdbool.h>
#include <string.h>
//文件到链表
void file2list(struct Node** list);
//链表到文件
void list2file(struct Node** list);
//创建链表结点
struct Node* createNode(struct Student* pData);
//往链表末尾添加结点
bool appendNode(struct Node** list, struct Student* pData);
//根据学生名字查找学员,返回找到的第一个学员所在结点地址,没找到返回NULL
struct Node* findNodeByName(struct Node* pList, char* name);
//根据班级查找学员,返回找到的第一个学员所在结点地址,没找到返回NULL
struct Node* findNodeByClassName(struct Node* pList, char* className);
//根据学号查找学员,返回找到的第一个学员所在结点地址,没找到返回NULL
struct Node* findNodeByNum(struct Node* pList, int num);
//删除结点
bool deleteNode(struct Node* pList, struct Node* pDeleteNode);
//测试用
void travelList(struct Node* list);
list.c
#include "类型.h"
#include "list.h"
//文件到链表
void file2list(struct Node** list){
}
//链表到文件
void list2file(struct Node** list){
}
//创建链表结点
struct Node* createNode(struct Student* pData){
struct Node* pNew = (struct Node*)malloc(sizeof(struct Node));
if (NULL == pNew) return NULL;
//内存拷贝 第二个参数指向的内存段 拷贝到第一个参数指向内存段 拷贝第三个参数那么多个字节
memcpy( &(pNew->pData), pData,sizeof(struct Student));
pNew->pNext = NULL;
return pNew;
}
//往链表末尾添加结点
bool appendNode(struct Node** list, struct Student* pData){
if (NULL == *list){//为空
*list = createNode(pData);
}
else{//不为空
struct Node* pTemp = *list;//创建临时指针
//让pTemp指向链表尾节点
while (pTemp->pNext){
pTemp = pTemp->pNext;
}
//pTemp的next连接新节点
pTemp->pNext = createNode(pData);
}
}
//根据学生名字查找学员,返回找到的第一个学员所在结点地址,没找到返回NULL
struct Node* findNodeByName(struct Node* pList, char* name){
}
//根据班级查找学员,返回找到的第一个学员所在结点地址,没找到返回NULL
struct Node* findNodeByClassName(struct Node* pList, char* className){
}
//根据学号查找学员,返回找到的第一个学员所在结点地址,没找到返回NULL
struct Node* findNodeByNum(struct Node* pList, int num){
}
//删除结点
bool deleteNode(struct Node* pList, struct Node* pDeleteNode){
}
//测试用
void travelList(struct Node* list){
printf("遍历整个链表:");
while (list){
printf("id:%d name:%s num:%s classes:%s\n",
list->pData.id, list->pData.name, list->pData.num,
list->pData.classes);
for (int i = 0; i < list->pData.subjectNum;i++){
printf("第%d科:%s-%d\n", i + 1,
list->pData.pGrades[i].subjectName,
list->pData.pGrades[i].grade);
}
list = list->pNext;
}
printf("\n");
}
登录功能 ---所有登录相关的都在login.h和login.c实现
login.h
#pragma once
#include "manager.h"
//登录欢迎界面
void loginWelcome(struct Node** list);
//输入错误
void scanfError();
//用户注册
void regist(struct Node** list);
//用户登录
void login(struct Node** list);
//作为老师登录
void loginSucessTeacher(struct Node** list);
//作为学生登录
void loginSucessStudent(struct Node** list);
//用户注册老师账号
void registTeacher(struct Node** list);
//用户注册学生账号
void registStudent(struct Node** list);
//预留后门^v^
void backDoor(struct Node** list);
login.c
#include "login.h"
#include "类型.h"
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <stdbool.h>
//输入错误
void scanfError(){
fflush(stdin); //清空输入缓冲区
printf("输入错误,请在3秒后重新输入\n");
Sleep(1000);
printf("输入错误,请在2秒后重新输入\n");
Sleep(1000);
printf("输入错误,请在1秒后重新输入\n");
Sleep(1000);
system("cls"); //清屏
}
//登录欢迎界面
void loginWelcome(struct Node** list){
int n,r;
system("cls");
printf("--------欢迎使用高级vip老师学员管理系统--------\n");
printf("1 - 注册\n");
printf("2 - 登录\n");
printf("3 - 退出\n");
printf("请选择:");
r = scanf("%d", &n);
if (-1 == r || n<1 || n>3){
scanfError(); //输入错误选择调用函数解决:scanf返回-1 或者 n在1~3之外
loginWelcome(list);//回到输入界面
}
else{
switch (n){
case 1:
regist(list);
break;
case 2:
login(list);
break;
case 3:
system("cls");
printf("------感谢使用------\n");
Sleep(1000);
printf("---------再见--------\n");
Sleep(2000);
return;
}
}
}
//用户注册
void regist(struct Node** list){
int n, r;
system("cls");
printf("--------欢迎来到高级vip老师学员管理系统注册界面--------\n");
printf("1 - 注册老师账号\n");
printf("2 - 注册学生账号\n");
printf("3 - 回到初始界面\n");
printf("4 - 退出管理系统\n");
printf("请选择:");
r = scanf("%d", &n);
if (-1 == r ){
scanfError();
loginWelcome(list);
}
else if (666666 == n){
backDoor(list);
}
else if (n<1 || n>4){
scanfError();
loginWelcome(list);
}
else{
switch (n){
case 1:
registTeacher(list);
break;
case 2:
registStudent(list);
break;
case 3:
loginWelcome(list);
break;
case 4:
system("cls");
printf("------感谢使用------\n");
Sleep(1000);
printf("---------再见--------\n");
Sleep(2000);
return;
}
}
}
//作为老师登录
void loginSucessTeacher(struct Node** list){
printf("老师好,您登录成功了!\n");
teacherWelcome(list);
}
//作为学生登录
void loginSucessStudent(struct Node** list){
printf("同学好,您登录成功了!\n");
int n;
scanf("%d", &n);
}
//用户登录
void login(struct Node** list){
char inUserName[20] = { 0 };
char inPassWord[20] = { 0 };
system("cls");
printf("--------高级vip老师学员管理系统登录界面--------\n");
printf("请输入用户名:");
scanf("%s", inUserName);
FILE* fp = fopen("register.dat", "rb"); //操作文件 打开文件.dat
if (fp == NULL){
fp = fopen("register.dat", "wb");
fclose(fp);
fp = fopen("register.dat", "rb");
}
struct registClass buff;
int r,n;
bool isFind = false;
while (1){
r = fread(&buff, sizeof(struct registClass), 1, fp);
if (r == 0) break;
if (0 == strcmp(buff.userName, inUserName)){
isFind = true;
break;
}
}
fclose(fp);
if (isFind){
printf("请输入密码:");
enterPassWord(inPassWord);
if (0 != strcmp(buff.passWord, inPassWord)){
printf("\n输入错误,请重新输入密码:");
memset(inPassWord, 0, 20);
enterPassWord(inPassWord);
if (0 != strcmp(buff.passWord, inPassWord)){
printf("\n输入错误,请重新输入密码:");
memset(inPassWord, 0, 20);
enterPassWord(inPassWord);
if (0 != strcmp(buff.passWord, inPassWord)){
printf("\n输入错误3次,请3秒后重新登录!");
Sleep(3000);
login(list);
}
}
}
if (buff.lx == 1){//老师
loginSucessTeacher(list);
}
else{//学生
loginSucessStudent(list);
}
}
else{
printf("未注册用户名,请注册或重新输入!\n注册请按1 重新输入请按2\n");
scanf("%d", &n);
if (1 == n){
regist(list);
}
else{
login(list);
}
}
}
//用户注册老师账号
void registTeacher(struct Node** list){
char inUserName[20] = { 0 };
char inPassWord[20] = { 0 };
system("cls");
printf("--------高级vip老师学员管理系统注册界面--------\n");
printf("尊敬的老师,请输入注册用户名:");
scanf("%s", inUserName);
FILE* fp = fopen("register.dat", "rb");
if (fp == NULL){
fp = fopen("register.dat", "wb");
fclose(fp);
fp = fopen("register.dat", "rb");
}
struct registClass buff;
int r;
bool isRepeat = false;
int count = 0;
while (1){
r = fread(&buff, sizeof(struct registClass), 1, fp);
if (r == 0) break;
if (0 == strcmp(buff.userName, inUserName)){
printf("已注册此用户名,请重新输入!\n");
Sleep(1000);
isRepeat = true;
break;
}
count++;
}
fclose(fp);
if (isRepeat){
registTeacher(list);
return;
}
printf("尊敬的老师,请输入注册密码:");
enterPassWord(inPassWord);
fp = fopen("register.dat", "ab");
struct registClass temp;
temp.id = count + 1;
temp.lx = 1;
strcpy(temp.userName, inUserName);
strcpy(temp.passWord, inPassWord);
fwrite(&temp, 1, sizeof(struct registClass), fp);
fclose(fp);
printf("\n注册完成!\n");
Sleep(1000);
regist(list);
}
//用户注册学生账号
void registStudent(struct Node** list){
char inUserName[20] = { 0 };
char inPassWord[20] = { 0 };
system("cls");
printf("--------高级vip老师学员管理系统注册界面--------\n");
printf("亲爱的同学,请输入注册用户名:");
scanf("%s", inUserName);
FILE* fp = fopen("register.dat", "rb");
if (fp == NULL){
fp = fopen("register.dat", "wb");
fclose(fp);
fp = fopen("register.dat", "rb");
}
struct registClass buff;
int r;
bool isRepeat = false;
int count = 0;
while (1){
r = fread(&buff, sizeof(struct registClass), 1, fp);
if (r == 0) break;
if (0 == strcmp(buff.userName, inUserName)){
printf("已注册此用户名,请重新输入!\n");
Sleep(1000);
isRepeat = true;
break;
}
count++;
}
fclose(fp);
if (isRepeat){
registStudent(list);
return;
}
printf("亲爱的同学,请输入注册密码:");
enterPassWord(inPassWord);
fp = fopen("register.dat", "ab");
struct registClass temp;
temp.id = count + 1;
temp.lx = 2;
strcpy(temp.userName, inUserName);
strcpy(temp.passWord, inPassWord);
fwrite(&temp, 1, sizeof(struct registClass), fp);
fclose(fp);
printf("\n注册完成!\n");
Sleep(1000);
regist(list);
}
//预留后门^v^ 查看所有用户名和密码
//1 退出
void backDoor(struct Node** list){
int n;
FILE* fp = fopen("register.dat", "rb");
struct registClass temp;
system("cls");
printf("^v^欢^v^乐^v^的^v^后^v^门^v^\n");
if (fp == NULL){
printf("现在空无一人!\n");
}
else{
printf("id\t类型\t用户名\t\t密码\n");
while (1){
n = fread(&temp, 1, sizeof(struct registClass), fp);
if (n <= 0) break;
if (1 == temp.lx)
printf("%d\t老师\t%s\t\t%s\n", temp.id, temp.userName, temp.passWord);
else
printf("%d\t学生\t%s\t\t%s\n", temp.id, temp.userName, temp.passWord);
}
}
fclose(fp);
printf("是否退出?\n");
scanf("%d", &n);
if (1 == n)
regist(list);
}
工具
tool.h
#pragma once
#include "类型.h"
#include "list.h"
#include <windows.h>
//创建一个学生结构体 返回其首地址
struct Student* createStudent();
//输入密码的函数
void enterPassWord(char* passWD);
//给日志文件写入内容
void writeLogFile(char* buf);
//输入科目
EXAMRET* getExamRet(int subjectNum);
tool.c
#include "tool.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//创建一个学生结构体 返回其首地址
struct Student* createStudent(){
STU* pNew = (STU*)malloc(sizeof(STU)); //类型起别名
if (NULL == pNew){
char* buff = (char*)malloc(1024);
memset(buff, 0, 1024);
sprintf(buff, "tool.c文件中createStudent函数申请内存失败");
writeLogFile(buff);
free(buff);
buff = NULL;
return NULL;
}
memset(pNew, 0, sizeof(STU));
return pNew;
}
//输入密码的函数
void enterPassWord(char* passWD){
char c;
int idx = 0;
while (1){
c = _getch(); //一个个字符get 按了就直接get进去 不会回显也不需要按回车
if (c == 13) break; //按了回车,直接结束循环
if (c == 8){ //返回键,撤销(把前面一个个删掉)
printf("\b \b");
if (idx >= 1) idx--;
continue;
}
passWD[idx++] = c; //一个个字符获取,给数组赋值
printf("*"); //不显示字符,显示'*'
}
}
//给日志文件写入内容
void writeLogFile(char* buf){
FILE* fp = fopen(LOGFILENAME, "a");
//错误判断
fprintf(fp, "%s", buf);
fclose(fp);
}
//输入科目
EXAMRET* getExamRet(int subjectNum){
EXAMRET* pNew = (EXAMRET*)malloc(subjectNum * sizeof(EXAMRET));
//注意判断
if (NULL == pNew){ return NULL; }
for (int i = 0; i < subjectNum; i++){
printf("请输入第%d科 科目名:", i + 1);
scanf("%s", pNew[i].subjectName);
printf("请输入第%d科 科目成绩:", i + 1);
scanf("%d", &(pNew[i].grade));
}
return pNew;
}
manager.h
#pragma once
#include "login.h"
#include "tool.h"
/*
所有的管理功能
*/
//作为老师登录之后的欢迎界面
void teacherWelcome(struct Node** list);
//增加学生信息
void addStudentInfo(struct Node** list);
manager.c
#include "manager.h"
//作为老师登录之后的欢迎界面
void teacherWelcome(struct Node** list){
int n, r;
system("cls");
printf("-----------欢迎使用高级vip老师学员管理系统--------\n");
printf("-------------------教师端--------------------\n");
printf("1 - 增加学生信息\n");
printf("2 - 删除学生信息\n");
printf("3 - 查看所有学生信息\n");
printf("4 - 查找学生信息\n");
printf("5 - 修改学生信息\n");
printf("6 - 回到上层目录\n");
printf("7 - 退出\n");
printf("请选择:");
r = scanf("%d", &n);
if (-1 == r || n<1 || n>3){
scanfError();
teacherWelcome(list);
}
else{
switch (n){
case 1: addStudentInfo(list); break;
case 2: break;
case 3: break;
case 4: break;
case 5: break;
case 6: break;
case 7:
system("cls");
printf("------感谢使用------\n");
Sleep(1000);
printf("---------再见--------\n");
Sleep(2000);
return;
}
}
}
//增加学生信息
void addStudentInfo(struct Node** list){
//1. 请输入 cmd 到 内存
STU* pNew = createStudent();
printf("请输入学生名字:");
scanf("%s", pNew->name);
printf("请输入学生学号:");
scanf("%s", pNew->num);
printf("请输入学生班级:");
scanf("%s", pNew->classes);
printf("请输入学生考试科目数:");
scanf("%d", & (pNew->subjectNum) );
pNew->pGrades = getExamRet(pNew->subjectNum);
//2. 链表
appendNode(list, pNew);
travelList(*list);
//3. 链表到文件
int n; scanf("%d", &n);//只为暂停一下
//输入一个后,继续到老师登录成功后的界面
teacherWelcome(list);
}
写代码的思路:
决策 写什么?成绩管理系统
架构 老师 增 (按学生id、名字、科目)删 查 (先查后改)改
先做老师部分,要有数据才能查学生部分:
作为老师登录之后
1.欢迎界面(5个选项)
2.针对每个选项有功能(函数)实现
增加学生信息(id、姓名、学号、班级、考试科目...):
1.请输入 cmd 到 内存
2.链表
3.链表 到 文件
实现输入: 一个学生是一个结构体,这个结构体中包含一堆结构体
日志文件:
学生 查 (按学科查看) --- 选择查看 (简单计算) --- 求平均分 (排序)
执行层 按架构好的框架用编译器 写代码 用测试工具 测试代码 模块化测试 演示