账号登录系统在很多系统设计时都时必不可少的,今天这个登录系统功能较全,可以注册,登录,找回密码,修改密码,以及在输入密码时会有*将密码掩盖,还有完善地登录选择界面,废话不多,上代码!
目录
1.头文件&结构体&大概函数实现
2.主函数&登录界面
3.注册系统
4.登录系统
5.找回密码(更改密码)
6.密码输入获取&密码掩盖
7.完整代码!!!!!
!!!!首先需要在和.c文件同个目录下新建一个文件储存数据,命名users.dat 如图!!
img
!!!!!!!!!!!!!!!!!!!!
也可以命名别的,后缀dat是我自己随便取的,喜欢就行!但是记得在代码中将文件名改过来!
1.头文件&结构体&大概函数实现
//引头文件 #include#include #include #include //用于反应意外情况的,下面会讲到 #include //定义宏常量 #define MAX_ID 11//ID的最大长度 #define MAX_PWD 20//密码的最大长度 #define MAX_NAME 15//名字的最大长度 #define MAX_SEX 5//性别的最大长度 #define MAX_PHONE 12//电话的最大长度 //创建用户的结构体 typedef struct Users { char id[MAX_ID];//id 即登录的账号 char pwd[MAX_PWD];//密码 char name[MAX_NAME];//姓名 char sex[MAX_SEX];//性别 char phone[MAX_PHONE];//电话 }Users; //声明函数 //打印菜单 void menu(); //用户注册 void Register(); //登录 void Login(); //找回密码 void Reback(); //定位光标 void gotoxy(); //获取x的位置 int posx(); //获取y的位置 int posy(); //密码输入(含掩盖功能) void Getpwd(char* pwd);
这里定义了很多宏常量,可以看情况修改合适的数值,比较快捷方便,不用到代码里一个个改
2.主函数&登录界面
void menu() { printf("************************************ "); printf("************************************ "); printf("*****1.Register 2.Login***** "); printf("*****3.Reback 0.exit ***** "); printf("************************************ "); printf("************************************ "); } int main() { char input; do { menu(); setbuf(stdin, NULL);//清空输入缓冲区,避免下面getchar读到上一次输入缓冲区剩下的东西 input = getchar(); switch (input) { case '1': Register(); break; case '2': Login(); break; case '3': Reback(); break; case '0': printf("退出成功! "); break; default: printf("选择错误,请重新选择! "); break; } } while (input!='0');//如果输入了0,就exit退出咯 }
这里用到字符去当作switch的判断依据,是因为如果用整形去做判断依据的话,若向input中输入的东西不是整形而是字符或者字符串,switch在循环中就会陷入死循环,具体情况大家去试试就知道,这里不多讲解,用单个字符判断到现在是没试出什么bug。
3.注册系统
void Register() { Users a, b;//创建用户结构体临时变量,a是用来接收用户输入的,b是用来从文件中读取的,来和a作比较 char tmp[20]="";//用着下面判断的 printf("欢迎来到注册界面! "); FILE* pf = fopen("users.dat", "rb");//"rb"是以二进制只读方式打开文件的意思 fread(&b, sizeof(Users), 1, pf);//将数据读入b中 if (!pf)//如果打开失败 { printf("%s", strerror(errno));//errno可以理解是报的错误对应的编号,strerror可以把这个编号翻译出来,输出在屏幕上 return; } Sleep(800); printf("请输入您的账号>>"); scanf("%s", a.id); while (1) { if (strcmp(a.id, b.id))//两个用户名不相等 { if (!feof(pf))//没读到文件末尾 { fread(&b, sizeof(Users), 1, pf);//继续读取文件中的用户到b中 } else//读到文件末尾了,确认没有重复的id { break; } } else//有两个用户名相等 { printf("此用户名已存在在,请重新输入! "); Sleep(1000); fclose(pf);//关闭文件 pf = NULL;//pf置空,避免野指针 return; } } printf("请输入您的姓名>>"); scanf("%s", a.name); printf("请输入您的性别>>"); scanf("%s", a.sex); printf("请输入您的电话号码>>"); scanf("%s", a.phone); printf("请输入您的密码>>"); Getpwd(a.pwd);//输入密码的函数,有掩盖功能,下面会介绍 printf(" 请再次确认您的密码>>"); Getpwd(tmp); do { if (!strcmp(a.pwd, tmp))//两次密码相等 { pf = fopen("users.dat", "ab"); fwrite(&a, sizeof(Users), 1, pf); printf(" 账号注册成功,请登录! "); Sleep(500); fclose(pf); pf = NULL; return; } else { printf(" 两次密码不匹配!请重新输入>>"); Getpwd(a.pwd); printf(" 请再次确认>>"); Getpwd(tmp); } } while (1); }
文件都是以二进制打开以二进制写入的,没别的原因,就是觉得帅!
4.登录系统
void Login() { Users a, b;//同理,a是用来给用户输入的,b是用来是水的(从文件中读取到b中,用b和a匹配比较) FILE* pf = fopen("users.dat", "rb");//以只读的方式打开文件 if (!pf)//如果读取失败 { printf("%s ", strerror(errno));//上面有讲过~ return; } printf("欢迎来到登录界面! "); Sleep(1000); fread(&b, sizeof(Users), 1, pf);//先从文件中读取一个用户试试水 printf("请输入账号>>"); scanf("%s", a.id); while (1) { if (!strcmp(a.id, b.id))//在文件中找到了与用户输入相同的id { break; } else { if (!feof(pf))//没读到文件末尾,继续读取文件中的id到b中 { fread(&b, sizeof(Users), 1, pf);//继续从文件中读取用户信息进b,直到在文件中找到一个和a的信息相同的 } else//读到文件末尾了,没有找到与用户输入相同的账号 { printf("此账号不存在!请重新输入! "); Sleep(500); fclose(pf); pf = NULL; return; } } } do { printf("请输入密码>>"); Getpwd(a.pwd);//获取密码,在下面会讲 if (!strcmp(a.pwd, b.pwd))//输入的密码与文件中的相同 { printf(" 登录成功!欢迎使用! "); Sleep(500); fclose(pf);//用完当然要把文件关啦 pf = NULL;//置空,避免野指针 return; } else { printf(" 密码输入错误,请重新输入 "); } } while (strcmp(a.pwd, b.pwd)); }
大概思路就是用户先输入账号(id),接着b从文件中读取用户,直到找到与用户输入id相同的,然后就是输入密码判断密码对不对咯。 里面用到了一个库函数strcmp,判断字符串是不是一样的,如果一样则返回0,不一样则返回一个非0值。
5.找回密码(更改密码)
void Reback() { char tmp[20] = "";//密码匹配用的 Users a, b; FILE* pf = fopen("users.dat", "rb+");//"rb+"是为了读和写以二进制打开文件的意思 if (!pf)//老样子,先判断能不能顺利打开 { printf("%s", strerror(errno)); return; } fread(&b, sizeof(Users), 1, pf);//照样,读一个试试水 printf("请输入您的账号>>"); Sleep(800); scanf("%s", a.id); while (1)//在文件中找到与用户输入相同的id { if (!strcmp(a.id, b.id))//如果读取到了相同的id(在文件中找到了和用户输入一样的) { break; } else { if (!feof(pf))//没读到文件尾,继续读 { fread(&b, sizeof(Users), 1, pf); } else { printf("您输入的账号不存在!请重新输入! "); Sleep(500); fclose(pf); pf = NULL; break; } } } //下面是信息匹配验证 do//匹配姓名 { printf("请输入您的姓名>>"); scanf("%s", a.name); if (!strcmp(a.name, b.name)) { break; } else { printf("输入错误,请重新输入! "); } } while (strcmp(a.name, b.name)); do//匹配性别 { printf("请输入您的性别>>"); scanf("%s", a.sex); if (!strcmp(a.sex, b.sex)) { break; } else { printf("输入错误,请重新输入! "); } } while (strcmp(a.sex, b.sex)); do//匹配电话号码 { printf("请输入您的电话号码>>"); scanf("%s", a.phone); if (!strcmp(a.phone, b.phone)) { break; } else { printf("输入错误,请重新输入! "); } } while (strcmp(a.phone, b.phone)); //更改密码 printf("验证成功!请修改您的密码! "); printf("请输入您的密码>>"); Getpwd(a.id); printf("请再次确认您的密码>>"); Getpwd(tmp); if (!pf) { printf("%s", strerror(errno)); return; } //将原来的密码覆盖掉 do { if (!strcmp(a.pwd, tmp))//两次密码相等 { fseek(pf,-((int)(sizeof(Users)-MAX_ID)), SEEK_CUR);//将文件流调回到要修改的密码的位置 fprintf(pf, "%s", a.pwd);//覆盖原来的密码 printf("密码修改成功,请登录! "); Sleep(500); fclose(pf); pf = NULL; return; } else { printf("两次密码不匹配!请重新输入>>"); scanf("%s", a.pwd); printf("请再次确认>>"); scanf("%s", tmp); } } while (1); }
大概思路是输入账号->匹配信息->修改密码,修改密码时要将文件流调回要修改的密码的前面,这里用到了fseek,-((int)(sizeof(Users)-MAX_ID))是要调回的范围。
6.密码输入获取&密码掩盖
void gotoxy(int x, int y) { //更新光标位置 COORD pos; HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//GetStdHandle是一个Windows API函数。 pos.X = x; pos.Y = y; SetConsoleCursorPosition(hOutput, pos); } int posx() { CONSOLE_SCREEN_BUFFER_INFO ptr; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr); return (ptr.dwCursorPosition.X); } int posy() { CONSOLE_SCREEN_BUFFER_INFO ptr; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr); return (ptr.dwCursorPosition.Y); } void Getpwd(char* pwd) { int i = 0; int x, y; while (1) { pwd[i] = getch();//获取单个密码(字符) if (pwd[i] == VK_BACK && i >= 0)//如果输入的是回退键,VK_BACK是键盘的键值,ASCII码值为8 { if (i > 0)//i>0说明有输入东西了,则回退前一格 { i--; x = posx() - 1;//定位x并回退一格 y = posy();//定位y gotoxy(x, y);//定位光标 printf(" ");//将*用空格掩盖 x = posx() - 1;//再次回退,下次输入时光标才会显示在正确的位置 y = posy();//定位y gotoxy(x, y); continue;//然后跳过此次循环 } else if (i == 0)//i==0说明没输入东西,直接跳过此次循环即可 { continue; } } if (i >= 0 && pwd[i] != VK_RETURN && pwd[i] != VK_BACK)//输入东西了 { x = posx(); y = posy(); gotoxy(x, y); printf("*"); } if (i == 0 && pwd[i] == VK_RETURN)//如果没输入东西直接按回车,直接跳过此次循环,避免程序把回车当密码了 { continue; } if (pwd[i] == VK_RETURN||i==MAX_PWD-2)//输入回车了或者到上限了 { i++; pwd[i] = '';//结尾放'' break; } i++; } }
那几个长长的都是windows控制台的API函数,这里不多讲解
7.完整代码!!!!!
//引头文件 #include#include #include #include #include //定义宏常量 #define MAX_ID 11 #define MAX_PWD 20 #define MAX_NAME 15 #define MAX_SEX 5 #define MAX_PHONE 12 //创建用户的结构体 typedef struct Users { char id[MAX_ID]; char pwd[MAX_PWD]; char name[MAX_NAME]; char sex[MAX_SEX]; char phone[MAX_PHONE]; }Users; //声明函数 //打印菜单 void menu(); //用户注册 void Register(); //登录 void Login(); //找回密码 void Reback(); //定位光标 void gotoxy(); //获取x的位置 int posx(); //获取y的位置 int posy(); //密码输入(含掩盖功能) void Getpwd(char* pwd); int main()//主函数 关注公众号:C语言中文社区,免费领取300G编程资料 { char input; do { menu(); setbuf(stdin, NULL); input = getchar(); switch (input) { case '1': Register(); break; case '2': Login(); break; case '3': Reback(); break; case '0': printf("退出成功! "); break; default: printf("选择错误,请重新选择! "); break; } } while (input!='0'); } //打印菜单 void menu() { printf("************************************ "); printf("************************************ "); printf("*****1.Register 2.Login***** "); printf("*****3.Reback 0.exit ***** "); printf("************************************ "); printf("************************************ "); } //注册系统 void Register() { Users a, b;//创建用户结构体临时变量,a是用来接收用户输入的,b是用来从文件中读取的,来和a作比较 char tmp[20]="";//用着下面判断的 printf("欢迎来到注册界面! "); FILE* pf = fopen("users.dat", "rb");//"rb"是以二进制只读方式打开文件的意思 fread(&b, sizeof(Users), 1, pf);//将数据读入b中 if (!pf)//如果打开失败 { printf("%s", strerror(errno));//errno可以理解是报的错误对应的编号,strerror可以把这个编号翻译出来,输出在屏幕上 return; } Sleep(800); printf("请输入您的账号>>"); scanf("%s", a.id); while (1) { if (strcmp(a.id, b.id))//两个用户名不相等 { if (!feof(pf))//没读到文件末尾 { fread(&b, sizeof(Users), 1, pf);//继续读取文件中的用户到b中 } else//读到文件末尾了,确认没有重复的id { break; } } else//有两个用户名相等 { printf("此用户名已存在在,请重新输入! "); Sleep(1000); fclose(pf);//关闭文件 pf = NULL;//pf置空,避免野指针 return; } } printf("请输入您的姓名>>"); scanf("%s", a.name); printf("请输入您的性别>>"); scanf("%s", a.sex); printf("请输入您的电话号码>>"); scanf("%s", a.phone); printf("请输入您的密码>>"); Getpwd(a.pwd);//输入密码的函数,有掩盖功能,下面会介绍 printf(" 请再次确认您的密码>>"); Getpwd(tmp); do { if (!strcmp(a.pwd, tmp))//两次密码相等 { pf = fopen("users.dat", "ab"); fwrite(&a, sizeof(Users), 1, pf); printf(" 账号注册成功,请登录! "); Sleep(500); fclose(pf); pf = NULL; return; } else { printf(" 两次密码不匹配!请重新输入>>"); Getpwd(a.pwd); printf(" 请再次确认>>"); Getpwd(tmp); } } while (1); } //登录系统 void Login() { Users a, b;//同理,a是用来给用户输入的,b是用来是水的(从文件中读取到b中,用b和a匹配比较) FILE* pf = fopen("users.dat", "rb");//以只读的方式打开文件 if (!pf)//如果读取失败 { printf("%s ", strerror(errno));//上面有讲过~ return; } printf("欢迎来到登录界面! "); Sleep(1000); fread(&b, sizeof(Users), 1, pf);//先从文件中读取一个用户试试水 printf("请输入账号>>"); scanf("%s", a.id); while (1) { if (!strcmp(a.id, b.id))//在文件中找到了与用户输入相同的id { break; } else { if (!feof(pf))//没读到文件末尾,继续读取文件中的id到b中 { fread(&b, sizeof(Users), 1, pf);//继续从文件中读取用户信息进b,直到在文件中找到一个和a的信息相同的 } else//读到文件末尾了,没有找到与用户输入相同的账号 { printf("此账号不存在!请重新输入! "); Sleep(500); fclose(pf); pf = NULL; return; } } } do { printf("请输入密码>>"); Getpwd(a.pwd);//获取密码,在下面会讲 if (!strcmp(a.pwd, b.pwd))//输入的密码与文件中的相同 { printf(" 登录成功!欢迎使用! "); Sleep(500); fclose(pf);//用完当然要把文件关啦 pf = NULL;//置空,避免野指针 return; } else { printf(" 密码输入错误,请重新输入 "); } } while (strcmp(a.pwd, b.pwd)); } //找回密码 void Reback() { char tmp[20] = "";//密码匹配用的 Users a, b; FILE* pf = fopen("users.dat", "rb+");//"rb+"是为了读和写以二进制打开文件的意思 if (!pf)//老样子,先判断能不能顺利打开 { printf("%s", strerror(errno)); return; } fread(&b, sizeof(Users), 1, pf);//照样,读一个试试水 printf("请输入您的账号>>"); Sleep(800); scanf("%s", a.id); while (1)//在文件中找到与用户输入相同的id { if (!strcmp(a.id, b.id))//如果读取到了相同的id(在文件中找到了和用户输入一样的) { break; } else { if (!feof(pf))//没读到文件尾,继续读 { fread(&b, sizeof(Users), 1, pf); } else { printf("您输入的账号不存在!请重新输入! "); Sleep(500); fclose(pf); pf = NULL; break; } } } //下面是信息匹配验证 do//匹配姓名 { printf("请输入您的姓名>>"); scanf("%s", a.name); if (!strcmp(a.name, b.name)) { break; } else { printf("输入错误,请重新输入! "); } } while (strcmp(a.name, b.name)); do//匹配性别 { printf("请输入您的性别>>"); scanf("%s", a.sex); if (!strcmp(a.sex, b.sex)) { break; } else { printf("输入错误,请重新输入! "); } } while (strcmp(a.sex, b.sex)); do//匹配电话号码 { printf("请输入您的电话号码>>"); scanf("%s", a.phone); if (!strcmp(a.phone, b.phone)) { break; } else { printf("输入错误,请重新输入! "); } } while (strcmp(a.phone, b.phone)); //更改密码 printf("验证成功!请修改您的密码! "); printf("请输入您的密码>>"); Getpwd(a.id); printf("请再次确认您的密码>>"); Getpwd(tmp); if (!pf) { printf("%s", strerror(errno)); return; } //将原来的密码覆盖掉 do { if (!strcmp(a.pwd, tmp))//两次密码相等 { fseek(pf,-((int)(sizeof(Users)-MAX_ID)), SEEK_CUR);//将文件流调回到要修改的密码的位置 fprintf(pf, "%s", a.pwd);//覆盖原来的密码 printf("密码修改成功,请登录! "); Sleep(500); fclose(pf); pf = NULL; return; } else { printf("两次密码不匹配!请重新输入>>"); scanf("%s", a.pwd); printf("请再次确认>>"); scanf("%s", tmp); } } while (1); } //定位光标 void gotoxy(int x, int y) { //更新光标位置 COORD pos; HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//GetStdHandle是一个Windows API函数。 pos.X = x; pos.Y = y; SetConsoleCursorPosition(hOutput, pos); } //获取光标x坐标 int posx() { CONSOLE_SCREEN_BUFFER_INFO ptr; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr); return (ptr.dwCursorPosition.X); } //获取光标y坐标 int posy() { CONSOLE_SCREEN_BUFFER_INFO ptr; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ptr); return (ptr.dwCursorPosition.Y); } //输入密码 void Getpwd(char* pwd) { int i = 0; int x, y; while (1) { pwd[i] = getch();//获取单个密码(字符) if (pwd[i] == VK_BACK && i >= 0)//如果输入的是回退键,VK_BACK是键盘的键值,ASCII码值为8 { if (i > 0)//i>0说明有输入东西了,则回退前一格 { i--; x = posx() - 1;//定位x并回退一格 y = posy();//定位y gotoxy(x, y);//定位光标 printf(" ");//将*用空格掩盖 x = posx() - 1;//再次回退,下次输入时光标才会显示在正确的位置 y = posy();//定位y gotoxy(x, y); continue;//然后跳过此次循环 } else if (i == 0)//i==0说明没输入东西,直接跳过此次循环即可 { continue; } } if (i >= 0 && pwd[i] != VK_RETURN && pwd[i] != VK_BACK)//输入东西了 { x = posx(); y = posy(); gotoxy(x, y); printf("*"); } if (i == 0 && pwd[i] == VK_RETURN)//如果没输入东西直接按回车,直接跳过此次循环,避免程序把回车当密码了 { continue; } if (pwd[i] == VK_RETURN||i==MAX_PWD-2)//输入回车了或者到上限了 { i++; pwd[i] = '';//结尾放'' break; } i++; } }
审核编辑:汤梓红
评论
查看更多