本登录注册系统通过使用C语言中的结构体、函数、文件操作以及指针等,设计与实现了一个小型用户登录注册系统的登录、注册、修改密码等基本功能。
本系统全部功能基本运行良好、用户界面友好、操作简单、使用方便。但系统仍然有不完善之处。例如在隐藏用户输入密码时,如果用户要删除刚输入的密码,则不能将输入‘*’一并删除;修改密码时生成的验证码不应该直接显示,而是通用户留存的手机号将验证码发送至用户绑定的手机上;其实改密部分还可以再添加一个二次输入验证的功能。除此之外,还可以将程序中一些重复使用的代码段再行封装成函数,但考虑接口会变得更复杂,故并未操作。
typedef struct The_users {
char name[11];
char pwd[20];
char phone[11];
} Users;
- #include
- #include
- #include
- #include
- #include
- #include
-
- typedef struct The_users { //typedef 可以定义结构体别名
- char name[11]; //账号
- char pwd[20]; //密码
- char phone[11]; //手机号
- } Users; //该结构体别名
-
- void Options(int); //菜单导航
- void Registers(); //注册模块
- void Login(); //登录模块
- void Reback(); //密码找回模
-
- int i = 0,flag = 1,menu = 0;
- int main() {
- printf("\n\t\t\t++++++++++++++++++++++++\n\t\t\t+ 欢迎使用XX登录系统 +\n\t\t\t++++++++++++++++++++++++\n");
- // system ("color 1F"); //程序面板颜色
- while (flag) {
- do {
- printf("\n ******************菜单栏*****************\n");
- printf("\t\t*\t ①登录 *\n");
- printf("\t\t*\t ②没有账号?去注册 *\n");
- printf("\t\t*\t ③忘记密码?去找回 *\n");
- printf("\t\t*\t ④退出系统\t\t*\n");
- printf(" *****************************************\n");
- printf("\n");
- printf("\t\t请输入选项:[\t]\b\b\b");
- scanf("%d", &menu);
- } while (menu>5 || menu<1);
- Options(menu);
- }
- }
-
- /*
- 通过Option函数
- 接收代表功能对应的数字
- 来调用其他功能函数
- */
- void Options(int option) {
- switch (option) {
- case 1:
- Login();
- break;
- case 2:
- Registers();
- break;
- case 3:
- Reback();
- break;
- case 4:
- printf("\n\t\t谢谢使用(^V^)!\n");
- flag=0; //flag置0,结束主函数循环(也可以不要此句)
- exit(0);
- }
- }
-
- /*
- 注册账号模块
- */
- void Registers() {
- system("cls");
- Users a,b; //定义两个临时用结构体变量
- FILE *fp;
- char temp_pwd[20];
- int count = 0;
- printf("\n\t\t欢迎来到注册界面!\n");
- Sleep(500);
- fp = fopen("Users.txt","r");
- fread(&b, sizeof(Users), 1, fp); //读入一个用户信息,用于在下面查找注册的账号名是否存在
- printf("\n\t\t请设置账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
- scanf("%s",&a.name);
- while (1) {
- if (strcmp(a.name, b.name)) { //如果注册账号不存在
- if (!feof(fp)) { //如果未到文件尾
- fread(&b, sizeof(Users), 1, fp); //继续读入下一个用户信息
- }
- else {
- break; //检查完毕,跳出
- }
- }
- else { //如果此账号已存在,退出
- printf("\t\t此用户名已存在!请重新注册!\n");
- Sleep(1000);
- fclose(fp);
- return;
- }
- }
- printf("\t\t请输入您的手机号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
- scanf("%s",&a.phone);
- int time = 2;
- do {
- printf("\t\t请设置密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
- i = 0;
- /*
- 以下代码段用于将输入的明文替换为'*'
- 起到保护作用,但仍存一点bug
- */
- do {
- a.pwd[i]=getch();
- if(a.pwd[i]=='\r')
- break;
- if(a.pwd[i]=='\b') { //如果退格(删除键)
- if(i==0) { //依旧可以让输入的内容
- printf("\a"); //正确保存到密码中
- continue;
- }
- i=i-1;
- printf("\b");
- }
- else {
- i=i+1;
- printf("*"); //但已经打印出的'*'是不能消除的,此程序bug
- }
- } while(a.pwd[i]!='\n' && i<20); //当接收到回车符或者密码长度已够时完成密码接收
- a.pwd[i]='\0';
- printf("\n");
- printf("\t\t请确认密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
- /*
- 再接收一次密码
- 用于验证,防止用户设置密码出错
- */
- i= 0;
- do {
- temp_pwd[i]=getch();
- if(temp_pwd[i]=='\r')
- break;
- if(temp_pwd[i]=='\b') {
- if(i==0) {
- printf("\a");
- continue;
- }
- i=i-1;
- printf("\b");
- }
- else {
- i=i+1;
- printf("*");
- }
- } while(temp_pwd[i]!='\n' && i<20);
- temp_pwd[i]='\0';
- printf("\n");
- if(!strcmp(a.pwd,temp_pwd)) { //如果两次输入的密码相同就可以注册了
- fp = fopen("Users.txt","a"); // a-向文件尾部追加写入
- fwrite(&a, sizeof(Users), 1, fp);
- printf("\t\t账号注册成功!\n");
- fclose(fp);
- return;
- }
- else {
- if (time!=0) {
- printf("\n\t\t两次输入的密码不相同!\t请重新输入(剩余%d次机会)\n",time);
- time--;
- continue; //如果本次密码匹配不相同跳出,进入下一次输入
- }
- else {
- printf("\n\t\t多次输入错误,即将退出!");
- Sleep(1500);
- return ;
- }
- }
- } while(time >= 0);
- }
-
- /*
- 登录模块
- */
- void Login() {
- system("cls");
- Users a,b; //定义结构体The_users别名
- FILE *fp;
- printf("\t\t\n欢迎来到登录界面!\n\n");
- printf("\t\t请输入账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
- scanf("%s",&a.name);
- printf("\t\t请输入密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
- i= 0;
- /*
- 采用相同的方法掩盖明文密码
- */
- do {
- a.pwd[i]=getch();
- if(a.pwd[i]=='\r')
- break;
- if(a.pwd[i]=='\b') {
- if(i==0) {
- printf("\a");
- continue;
- }
- i=i-1;
- printf("\b");
- }
- else {
- i=i+1;
- printf("*");
- }
- } while(a.pwd[i]!='\n' && i<20);
- a.pwd[i]='\0';
- printf("\n");
- fp = fopen("Users.txt","r");
- while (1) {
- fread(&b, sizeof(Users), 1, fp); //读入一个结构体字符块 写入b
- if ((strcmp(a.name, b.name)==0)||(!feof(fp))) { //如果有此账号
- break; //此账号已经注册 可以登录
- }
- else {
- if (!feof(fp)) { //如果文件没有读完
- fread(&b, sizeof(Users), 1, fp);
- }
- else { //如果在变量用户表之后没有找到该账号,提示错误信息
- printf("\t\t账号或密码错误!\n");
- fclose(fp);
- Sleep(1000);
- system("cls");
- return ;
- }
- }
- }
- fclose(fp);
- if (strcmp(a.pwd, b.pwd)==0) { /*如果密码匹配*/
- printf("\t\t登录成功!欢迎使用!\n");
- return;
- }
- else {
- printf("\t\t账号或密码错误!……");
- Sleep(1000);
- system("cls");
- return;
- }
- }
-
- /*
- 找回密码模块
- */
- void Reback() {
- system("cls");
- Users a,b; //两个用于零时写入的结构体变量
- FILE *fp;
- printf("\t\t欢迎来到找回密码界面!\n\n");
- int num = 0; //用于记录改密用户在文件中的位置
- fp = fopen("Users.txt","r");
- fread(&b, sizeof(Users), 1, fp); //读入一个用户信息并写入b
- printf("\t\t请输入账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
- scanf("%s",&a.name);
- while (1) {
- if (strcmp(a.name, b.name)==0) { //如果有此用户名
- break; //就跳出完成查找
- }
- else {
- if (!feof(fp)) { //如果文件没有读完切没有找到该用户
- fread(&b, sizeof(Users), 1, fp); //继续查找用户
- num++;
- }
- else { //如果没有找到
- printf("\t\t此用户不存在!!!\n");
- fclose(fp);
- for(i=0; i<2; i++) {
- printf("\t\t%d秒后退出 ……",2-i);
- printf("\r");
- Sleep(1000);
- }
- system("cls");
- return;
- }
- }
- }
- //如果程序走到这 就可以开始修改密码了
- int ver_code = 0,user_ver_code = 0;
- //生成随机的验证码
- srand((unsigned)time(NULL));
- for (i = 0; i < 7; i++){
- ver_code += rand() % 1000;
- }
- char phone_tail[5] ; // 获取该用户的手机尾号
- strncpy(phone_tail,a.phone+7,4) ;
- printf("\t\t已向尾号为%s的手机号码发送验证码 %d ,请注意查收!\n\t\t请输入验证码:[\t\t]\b\b\b\b\b\b\b\b\b\b", phone_tail,ver_code);
- scanf("%d", &user_ver_code);
- int sign = 0;
- //给用户提供三次验证输入的机会
- for(i=0; i<3; i++) {
- if (ver_code != user_ver_code) {
- printf("\t\t验证码错误!请重新输入:[\t](剩%d次机会)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",2-i);
- scanf("%d", &user_ver_code);
- continue;
- }
- else if (i<=3) { //如果验证次数内正确输入验证码
- sign =1; //就可以退出循环
- break; //向下一步改密
- }
- else {
- for(i=0; i<2; i++) {
- printf("\t\t多次输入错误!!%d秒后退出 ……",2-i);
- printf("\r");
- Sleep(1000);
- }
- }
- }
- if(sign == 1) { //如果验证手机正确开始改密
- FILE*fp;
- int N = 0; //用于记录当前用户总数
- if((fp=fopen("Users.txt","r"))==NULL) { // 判断文件是否能打开
- printf ("\t\tCannot open file\n");
- exit(0);
- }
- else {
- while (feof(fp)==0) {
- fread(&b, sizeof(Users), 1, fp); //依次读取用户并记录用户总数
- N++;
- }
- }
- N = N-1; //实际用是完成上面循环的 N-1
- fclose(fp);
- Users user[N]; //定义结构体数组
- if((fp=fopen("Users.txt","r"))==NULL) { // 判断文件是否能打开
- printf ("\t\tCannot open file\n");
- exit(-1);
- }
- else {
- i=0;
- do {
- fread(&user[i],sizeof(Users),1,fp); //将用户表中的数据都读入以便修改指定用户的密码
- } while(feof(fp)==0); //直到读到文件尾结束
- }
- printf("\t\t设置您的新密码:[ \t\t]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
- i= 0;
- /*
- 让输入的密码不可见
- */
- do {
- user[num].pwd[i]=getch();
- if(user[num].pwd[i]=='\r')
- break;
- if(user[num].pwd[i]=='\b') {
- if(i==0) {
- printf("\a");
- continue;
- }
- i=i-1;
- printf("\b");
- }
- else {
- i=i+1;
- printf("*");
- }
- } while(user[num].pwd[i]!='\n' && i<20);
- user[num].pwd[i]= '\0';
- printf("\n");
- if ((fp=fopen("Users.txt","w"))==NULL) { /*判断文件是否能打开*/
- printf ("\t\tCannot open file\n");
- exit(0);
- }
- for (i=0; i
/*将内存中的用户信息输出到磁盘文件中去*/ - if (fwrite(&user[i],sizeof(Users),1,fp)!=1)
- printf("File write error\n");
- fclose(fp);
- printf("\t\t密码修改成功!\n");
- return ;
- }
- else {
- for(i=0; i<3; i++) {
- printf("\t\t多次输入错误!!%d秒后退出 ……",3-i);
- printf("\r");
- Sleep(1000);
- }
- }
- }
-
注意:运行前需要在程序目录新建一个.txt的用户信息表
![]()
1.注册用户:
(1)正常注册(账号未被注册)

(2)异常注册(账号已被注册)

2.用户登录:
(1)用户未注册

(2)用户已注册
①密码正确

②密码错误

3.用户修改密码:
(1)无当前用户:

(2)用户存在
①正确输入验证码:

③错误输入验证码

(3) 修改后登录
