• 【C语言】简易登录注册系统(登录、注册、改密、文件操作)


    概述:

            本登录注册系统通过使用C语言中的结构体、函数、文件操作以及指针等,设计与实现了一个小型用户登录注册系统的登录、注册、修改密码等基本功能。

            本系统全部功能基本运行良好、用户界面友好、操作简单、使用方便。但系统仍然有不完善之处。例如在隐藏用户输入密码时,如果用户要删除刚输入的密码,则不能将输入‘*’一并删除;修改密码时生成的验证码不应该直接显示,而是通用户留存的手机号将验证码发送至用户绑定的手机上;其实改密部分还可以再添加一个二次输入验证的功能。除此之外,还可以将程序中一些重复使用的代码段再行封装成函数,但考虑接口会变得更复杂,故并未操作。

    用户信息采用结构体:

    typedef struct The_users {
        char name[11];        
        char pwd[20];       
        char phone[11]; 
    } Users;  

    程序源码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. typedef struct The_users { //typedef 可以定义结构体别名
    8. char name[11]; //账号
    9. char pwd[20]; //密码
    10. char phone[11]; //手机号
    11. } Users; //该结构体别名
    12. void Options(int); //菜单导航
    13. void Registers(); //注册模块
    14. void Login(); //登录模块
    15. void Reback(); //密码找回模
    16. int i = 0,flag = 1,menu = 0;
    17. int main() {
    18. printf("\n\t\t\t++++++++++++++++++++++++\n\t\t\t+ 欢迎使用XX登录系统 +\n\t\t\t++++++++++++++++++++++++\n");
    19. // system ("color 1F"); //程序面板颜色
    20. while (flag) {
    21. do {
    22. printf("\n ******************菜单栏*****************\n");
    23. printf("\t\t*\t ①登录 *\n");
    24. printf("\t\t*\t ②没有账号?去注册 *\n");
    25. printf("\t\t*\t ③忘记密码?去找回 *\n");
    26. printf("\t\t*\t ④退出系统\t\t*\n");
    27. printf(" *****************************************\n");
    28. printf("\n");
    29. printf("\t\t请输入选项:[\t]\b\b\b");
    30. scanf("%d", &menu);
    31. } while (menu>5 || menu<1);
    32. Options(menu);
    33. }
    34. }
    35. /*
    36. 通过Option函数
    37. 接收代表功能对应的数字
    38. 来调用其他功能函数
    39. */
    40. void Options(int option) {
    41. switch (option) {
    42. case 1:
    43. Login();
    44. break;
    45. case 2:
    46. Registers();
    47. break;
    48. case 3:
    49. Reback();
    50. break;
    51. case 4:
    52. printf("\n\t\t谢谢使用(^V^)!\n");
    53. flag=0; //flag置0,结束主函数循环(也可以不要此句)
    54. exit(0);
    55. }
    56. }
    57. /*
    58. 注册账号模块
    59. */
    60. void Registers() {
    61. system("cls");
    62. Users a,b; //定义两个临时用结构体变量
    63. FILE *fp;
    64. char temp_pwd[20];
    65. int count = 0;
    66. printf("\n\t\t欢迎来到注册界面!\n");
    67. Sleep(500);
    68. fp = fopen("Users.txt","r");
    69. fread(&b, sizeof(Users), 1, fp); //读入一个用户信息,用于在下面查找注册的账号名是否存在
    70. printf("\n\t\t请设置账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
    71. scanf("%s",&a.name);
    72. while (1) {
    73. if (strcmp(a.name, b.name)) { //如果注册账号不存在
    74. if (!feof(fp)) { //如果未到文件尾
    75. fread(&b, sizeof(Users), 1, fp); //继续读入下一个用户信息
    76. }
    77. else {
    78. break; //检查完毕,跳出
    79. }
    80. }
    81. else { //如果此账号已存在,退出
    82. printf("\t\t此用户名已存在!请重新注册!\n");
    83. Sleep(1000);
    84. fclose(fp);
    85. return;
    86. }
    87. }
    88. printf("\t\t请输入您的手机号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
    89. scanf("%s",&a.phone);
    90. int time = 2;
    91. do {
    92. printf("\t\t请设置密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
    93. i = 0;
    94. /*
    95. 以下代码段用于将输入的明文替换为'*'
    96. 起到保护作用,但仍存一点bug
    97. */
    98. do {
    99. a.pwd[i]=getch();
    100. if(a.pwd[i]=='\r')
    101. break;
    102. if(a.pwd[i]=='\b') { //如果退格(删除键)
    103. if(i==0) { //依旧可以让输入的内容
    104. printf("\a"); //正确保存到密码中
    105. continue;
    106. }
    107. i=i-1;
    108. printf("\b");
    109. }
    110. else {
    111. i=i+1;
    112. printf("*"); //但已经打印出的'*'是不能消除的,此程序bug
    113. }
    114. } while(a.pwd[i]!='\n' && i<20); //当接收到回车符或者密码长度已够时完成密码接收
    115. a.pwd[i]='\0';
    116. printf("\n");
    117. printf("\t\t请确认密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
    118. /*
    119. 再接收一次密码
    120. 用于验证,防止用户设置密码出错
    121. */
    122. i= 0;
    123. do {
    124. temp_pwd[i]=getch();
    125. if(temp_pwd[i]=='\r')
    126. break;
    127. if(temp_pwd[i]=='\b') {
    128. if(i==0) {
    129. printf("\a");
    130. continue;
    131. }
    132. i=i-1;
    133. printf("\b");
    134. }
    135. else {
    136. i=i+1;
    137. printf("*");
    138. }
    139. } while(temp_pwd[i]!='\n' && i<20);
    140. temp_pwd[i]='\0';
    141. printf("\n");
    142. if(!strcmp(a.pwd,temp_pwd)) { //如果两次输入的密码相同就可以注册了
    143. fp = fopen("Users.txt","a"); // a-向文件尾部追加写入
    144. fwrite(&a, sizeof(Users), 1, fp);
    145. printf("\t\t账号注册成功!\n");
    146. fclose(fp);
    147. return;
    148. }
    149. else {
    150. if (time!=0) {
    151. printf("\n\t\t两次输入的密码不相同!\t请重新输入(剩余%d次机会)\n",time);
    152. time--;
    153. continue; //如果本次密码匹配不相同跳出,进入下一次输入
    154. }
    155. else {
    156. printf("\n\t\t多次输入错误,即将退出!");
    157. Sleep(1500);
    158. return ;
    159. }
    160. }
    161. } while(time >= 0);
    162. }
    163. /*
    164. 登录模块
    165. */
    166. void Login() {
    167. system("cls");
    168. Users a,b; //定义结构体The_users别名
    169. FILE *fp;
    170. printf("\t\t\n欢迎来到登录界面!\n\n");
    171. printf("\t\t请输入账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
    172. scanf("%s",&a.name);
    173. printf("\t\t请输入密码:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
    174. i= 0;
    175. /*
    176. 采用相同的方法掩盖明文密码
    177. */
    178. do {
    179. a.pwd[i]=getch();
    180. if(a.pwd[i]=='\r')
    181. break;
    182. if(a.pwd[i]=='\b') {
    183. if(i==0) {
    184. printf("\a");
    185. continue;
    186. }
    187. i=i-1;
    188. printf("\b");
    189. }
    190. else {
    191. i=i+1;
    192. printf("*");
    193. }
    194. } while(a.pwd[i]!='\n' && i<20);
    195. a.pwd[i]='\0';
    196. printf("\n");
    197. fp = fopen("Users.txt","r");
    198. while (1) {
    199. fread(&b, sizeof(Users), 1, fp); //读入一个结构体字符块 写入b
    200. if ((strcmp(a.name, b.name)==0)||(!feof(fp))) { //如果有此账号
    201. break; //此账号已经注册 可以登录
    202. }
    203. else {
    204. if (!feof(fp)) { //如果文件没有读完
    205. fread(&b, sizeof(Users), 1, fp);
    206. }
    207. else { //如果在变量用户表之后没有找到该账号,提示错误信息
    208. printf("\t\t账号或密码错误!\n");
    209. fclose(fp);
    210. Sleep(1000);
    211. system("cls");
    212. return ;
    213. }
    214. }
    215. }
    216. fclose(fp);
    217. if (strcmp(a.pwd, b.pwd)==0) { /*如果密码匹配*/
    218. printf("\t\t登录成功!欢迎使用!\n");
    219. return;
    220. }
    221. else {
    222. printf("\t\t账号或密码错误!……");
    223. Sleep(1000);
    224. system("cls");
    225. return;
    226. }
    227. }
    228. /*
    229. 找回密码模块
    230. */
    231. void Reback() {
    232. system("cls");
    233. Users a,b; //两个用于零时写入的结构体变量
    234. FILE *fp;
    235. printf("\t\t欢迎来到找回密码界面!\n\n");
    236. int num = 0; //用于记录改密用户在文件中的位置
    237. fp = fopen("Users.txt","r");
    238. fread(&b, sizeof(Users), 1, fp); //读入一个用户信息并写入b
    239. printf("\t\t请输入账号:[ \t\t ]\b\b\b\b\b\b\b\b\b\b\b\b\b");
    240. scanf("%s",&a.name);
    241. while (1) {
    242. if (strcmp(a.name, b.name)==0) { //如果有此用户名
    243. break; //就跳出完成查找
    244. }
    245. else {
    246. if (!feof(fp)) { //如果文件没有读完切没有找到该用户
    247. fread(&b, sizeof(Users), 1, fp); //继续查找用户
    248. num++;
    249. }
    250. else { //如果没有找到
    251. printf("\t\t此用户不存在!!!\n");
    252. fclose(fp);
    253. for(i=0; i<2; i++) {
    254. printf("\t\t%d秒后退出 ……",2-i);
    255. printf("\r");
    256. Sleep(1000);
    257. }
    258. system("cls");
    259. return;
    260. }
    261. }
    262. }
    263. //如果程序走到这 就可以开始修改密码了
    264. int ver_code = 0,user_ver_code = 0;
    265. //生成随机的验证码
    266. srand((unsigned)time(NULL));
    267. for (i = 0; i < 7; i++){
    268. ver_code += rand() % 1000;
    269. }
    270. char phone_tail[5] ; // 获取该用户的手机尾号
    271. strncpy(phone_tail,a.phone+7,4) ;
    272. printf("\t\t已向尾号为%s的手机号码发送验证码 %d ,请注意查收!\n\t\t请输入验证码:[\t\t]\b\b\b\b\b\b\b\b\b\b", phone_tail,ver_code);
    273. scanf("%d", &user_ver_code);
    274. int sign = 0;
    275. //给用户提供三次验证输入的机会
    276. for(i=0; i<3; i++) {
    277. if (ver_code != user_ver_code) {
    278. 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);
    279. scanf("%d", &user_ver_code);
    280. continue;
    281. }
    282. else if (i<=3) { //如果验证次数内正确输入验证码
    283. sign =1; //就可以退出循环
    284. break; //向下一步改密
    285. }
    286. else {
    287. for(i=0; i<2; i++) {
    288. printf("\t\t多次输入错误!!%d秒后退出 ……",2-i);
    289. printf("\r");
    290. Sleep(1000);
    291. }
    292. }
    293. }
    294. if(sign == 1) { //如果验证手机正确开始改密
    295. FILE*fp;
    296. int N = 0; //用于记录当前用户总数
    297. if((fp=fopen("Users.txt","r"))==NULL) { // 判断文件是否能打开
    298. printf ("\t\tCannot open file\n");
    299. exit(0);
    300. }
    301. else {
    302. while (feof(fp)==0) {
    303. fread(&b, sizeof(Users), 1, fp); //依次读取用户并记录用户总数
    304. N++;
    305. }
    306. }
    307. N = N-1; //实际用是完成上面循环的 N-1
    308. fclose(fp);
    309. Users user[N]; //定义结构体数组
    310. if((fp=fopen("Users.txt","r"))==NULL) { // 判断文件是否能打开
    311. printf ("\t\tCannot open file\n");
    312. exit(-1);
    313. }
    314. else {
    315. i=0;
    316. do {
    317. fread(&user[i],sizeof(Users),1,fp); //将用户表中的数据都读入以便修改指定用户的密码
    318. } while(feof(fp)==0); //直到读到文件尾结束
    319. }
    320. printf("\t\t设置您的新密码:[ \t\t]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
    321. i= 0;
    322. /*
    323. 让输入的密码不可见
    324. */
    325. do {
    326. user[num].pwd[i]=getch();
    327. if(user[num].pwd[i]=='\r')
    328. break;
    329. if(user[num].pwd[i]=='\b') {
    330. if(i==0) {
    331. printf("\a");
    332. continue;
    333. }
    334. i=i-1;
    335. printf("\b");
    336. }
    337. else {
    338. i=i+1;
    339. printf("*");
    340. }
    341. } while(user[num].pwd[i]!='\n' && i<20);
    342. user[num].pwd[i]= '\0';
    343. printf("\n");
    344. if ((fp=fopen("Users.txt","w"))==NULL) { /*判断文件是否能打开*/
    345. printf ("\t\tCannot open file\n");
    346. exit(0);
    347. }
    348. for (i=0; i/*将内存中的用户信息输出到磁盘文件中去*/
    349. if (fwrite(&user[i],sizeof(Users),1,fp)!=1)
    350. printf("File write error\n");
    351. fclose(fp);
    352. printf("\t\t密码修改成功!\n");
    353. return ;
    354. }
    355. else {
    356. for(i=0; i<3; i++) {
    357. printf("\t\t多次输入错误!!%d秒后退出 ……",3-i);
    358. printf("\r");
    359. Sleep(1000);
    360. }
    361. }
    362. }

    运行测试:

    注意:运行前需要在程序目录新建一个.txt的用户信息表

      1.注册用户:

    (1)正常注册(账号未被注册)

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

     2.用户登录:

    (1)用户未注册

     (2)用户已注册

            ①密码正确

             ②密码错误

     3.用户修改密码:

    (1)无当前用户:

     (2)用户存在

            ①正确输入验证码:

             ③错误输入验证码        

      (3) 修改后登录 

  • 相关阅读:
    微服务拆分
    邮件功能-python中的SMTP协议邮件发送
    Python——案例
    SpringBoot中的异常处理
    Goby 漏洞发布|Honeywell PM43 loadfile.lp 文件命令执行漏洞(CVE-2023-3710)
    IO示例练习
    【蓝桥杯国赛真题23】Scratch恐龙跑酷 第十三届蓝桥杯 图形化编程scratch国赛真题和答案讲解
    vscode使用git
    el-table动态表头与模拟请求数据
    关于在网上拉取项目,yarn后使用不了的,解决办法
  • 原文地址:https://blog.csdn.net/weixin_64811333/article/details/126108201