本文将详细介绍如何实现基于Ubuntu22.04,Linux子系统环境下的C语言炫彩用户管理系统包括注册、登录、修改账号、注销账号、忘记密码和后台管理等功能。系统使用dat文件存储用户数据并支持终端颜色显示和密码掩码输入提供丰富的用户交互界面。注已附上效果核心代码目录一、系统概述二、功能概述1.终端颜色显示① 打印带颜色字体的内容② 打印带蓝色背景的标题栏③ 打印倒计时带颜色闪烁效果2.客户端①注册账号②登录账号③修改账号④注销账号⑤找回密码⑥设置安全问答⑦验证码3.管理端①后台管理主函数②后台管理员封用户账号③删除用户数据4.数据加载和保存5.输入密码显示星号一、系统概述系统包括客户端和管理端两部分为用户提供丰富的人机交互界面。系统采用结构体数组存储用户数据包含自动生成的顺序ID、账号、密码、登录/注册时间戳、自定义安全问题及答案。用户数据通过二进制文件持久化存储支持异常中断恢复防止因系统异常退出、电脑断电、CtrlC或CtrlZ中断程序操作等问题导致数据丢失。客户端提供✍️注册账号设置用户名、密码密码输入时隐藏保护及安全问题登录账号验证身份后进入系统记录登录时间✏️修改信息可以更改用户ID用户名或密码需验证码般的保护❌注销账号彻底删除自己的账号需二次确认找回密码通过预设的安全问题及答案如:你的宠物名字重置密码设置新密码需二次确认管理端提供️管理员查看用户信息用户账号名、最近登录时间、注册时间及用户ID⚠️数据清空功能三重验证① 当前日期 ② 确认码 ③ 管理员密码❗违规惩罚三重验证失败触发后台管理功能锁定锁定时长按指数增长代码架构*------------------------用户管理系统相关函数-------------------*/ // 注册函数 void Register(void); // 验证码函数 bool VerificationCode(void); // 登录函数 bool login(void); // 修改账号函数 bool ModifyUser(void); // 判断用户是否存在 bool isUserExist(const char *username); // 查找指定用户设置的安全认证的问题 bool IsUserQuestion(const char *username); // 查找指定用户设置的安全认证的答案 bool IsUserAnswer(const char *, const char *); // 注销账号 bool AccountCancellation(void); // 清空缓存区 void clearInputBuffer(void); // 查找要删除的账号 bool IsDeleteExistUser(const char *password, const char *); // 修改用户账号、密码、编号 bool IsUpdateExistUserCode(int *, const void *, const void *, const char *); // 移动编号 void remove_user(User users[], int *count, int index); // 清空用户数据 bool wipe_alluserdata(void); // 忘记密码 bool UserForgetPassword(void); // 设置安全问答 bool SetUserSecurityQuestion(User *); /*---------------------------UI界面显示--------------------------*/ // 打印倒计时 void countdown(int n); // 打印标题 void printHeader(const char *title, int offest); /*---------------------------密码核心算法-----------------------*/ // 获取密码 int get_password(char *buf, size_t buf_len); // 设置终端 void set_terminal(int echo); /*---------------------------管理后台数据------------------------*/ // 后台管理函数 void houtai(); // 保存后台数据 void save_usersdata(); // 清空后台数据 void clear_usersdata(); // 加载后台数据 void load_usersdata(); // 信号处理函数保存数据并退出 void EXIT_SIGNAL_Handler(int sig); /*---------------------------时间相关函数------------------------*/ // 获取当前时间 char *nowtime(); // 获取当前毫秒级时间戳 long long get_timestamp(); /*-------------------------------------------------------------*/ int main() { char choice 0; char buf[100] {0}; // 终端关闭信号 signal(SIGHUP, EXIT_SIGNAL_Handler); // Ctrl C 信号 signal(SIGINT, EXIT_SIGNAL_Handler); // 终止信号 signal(SIGTERM, EXIT_SIGNAL_Handler); load_usersdata(); // 加载保存的用户数据 while (1) { printHeader(用户管理系统, 6); printf(\n1. 注册账号\n2. 登录账号\n3. 注销账号\n4. 修改账号\n5. 忘记密码\n6. 后台管理\n7. 退出系统\n); printf(\n请输入数字选择操作: ); scanf(%s, buf); for (char *p buf; *p ! \0; p) { if (!isdigit(*p)) { choice 0; break; } else { choice atoi(buf); } } printf(choice:%d\n, choice); clearInputBuffer(); switch (choice) { case 1: Register(); break; case 2: login(); break; case 3: AccountCancellation(); break; case 4: ModifyUser(); break; case 5: UserForgetPassword(); break; case 6: houtai(); break; case 7: save_usersdata(); // 保存数据到文件 exit(0); default: printf(无效选择\n); break; } countdown(COUNTDOWN_TIME); system(clear); } return 0; }二、功能概述1.终端颜色显示温馨提示本项目是在window terminal终端下实现颜色显示的包括倒计时颜色闪烁效果、彩色标题显示等功能可能有一些终端不支持ANSI编码导致颜色打印在终端显示乱码可删掉颜色转义字符或者下载用window terminal终端。在C语言中printf()函数可用在终端中输出内容该函数定义于头文件stdio.h。printf 函数的一般调用格式为printf(格式化字符串, 参量表)。如果要输出带颜色的内容需要添加颜色转义字符。相关代码及效果如下所示。① 打印带颜色字体的内容printf(\033[94m请输入要注册的用户名:\033[0m\n);//蓝色字体黑色背景实际效果如下② 打印带蓝色背景的标题栏printHeader(用户管理系统, 6);/* * brief:在终端输出带蓝色背景的标题栏 * param: title: 要显示的标题文本 * offest: 用于微调标题水平位置的偏移量 * return None * */ void printHeader(const char *title, int offest) { const int WIDTH 40; // 背景宽度 // 标题左侧空格数 int padding (WIDTH - strlen(title)) / 2; // 上边框 printf(\033[1;44m%*s\033[0m\n, WIDTH, ); // 标题行带左右填充 //%*s动态宽度字符串格式第一个对应padding值第二个对应剩余宽度计算 printf(\033[1;44m%*s%s%*s\033[0m\n, padding, , title, WIDTH - padding - (int)strlen(title) offest, ); // 下边框 printf(\033[1;44m%*s\033[0m\n\n, WIDTH, ); }实际效果如下③ 打印倒计时带颜色闪烁效果// 倒计时 #define COUNTDOWN_TIME 3 countdown(COUNTDOWN_TIME);// 打印倒计时带颜色闪烁效果 void countdown(int n) { while (n) { if (IsLock false) printf(\033[5;93m%d秒后自动返回。。。\033[0m\r, n); else printf(\033[5;93m已上锁 %d秒后解锁返回主菜单。。。\033[0m\r, n); fflush(stdout); sleep(1); n--; } }实际效果如下2.客户端①注册账号代码实现void Register() { char checkPassword[MAX_PASSWORD_LENGTH] {0}; char FirstPassword[MAX_PASSWORD_LENGTH] {0}; char username[MAX_USERNAME_LENGTH] {0}; printHeader(注册账号, 4); if (usercount 1 MAX_USERS) { printf(已超过最大用户数\n); return; } printf(\033[94m请输入要注册的用户名:\033[0m\n);//蓝色字体黑色背景 scanf(%s, username); if (isUserExist(username)) { printf(\033[33m该账号已存在 请重新注册\033[0m\n); return; } printf(\033[94m请输入要注册的密码\033[0m\n); get_password(FirstPassword, sizeof(FirstPassword)); // scanf(%s, FirstPassword); printf(\033[94m请再次输入密码:\033[0m\n); // scanf(%s, checkPassword); get_password(checkPassword, sizeof(checkPassword)); if (!strcmp(FirstPassword, checkPassword)) { if (VerificationCode()) { SetUserSecurityQuestion(user[usercount]); strcpy(user[usercount].username, username); strcpy(user[usercount].password, FirstPassword); user[usercount].userNumber usercount; strcpy(user[usercount].UserRegisterTime, nowtime()); printf(\033[31m用户%s注册成功 编号为%02d\033[0m\n, user[usercount].username, user[usercount].userNumber); printf(注册时间:%s\n, user[usercount].UserRegisterTime); usercount; save_usersdata(); // 保存数据到文件 } else { printf(\033[33m注册失败\033[0m\n); } } else { printf(\033[33m密码错误 注册失败\033[0m\n); } }实现效果②登录账号代码实现bool login() { char username[MAX_USERNAME_LENGTH] {0}; char password[MAX_USERNAME_LENGTH] {0}; printHeader(登录账号, 4); printf(\033[94m请输入账号:\033[0m\n); scanf(%s, username); if (!isUserExist(username)) { printf(\033[33m没有该账号 请重新注册\033[0m\n); return false; } printf(\033[94m请输入密码:\033[0m\n); // scanf(%s, password); get_password(password, sizeof(password)); for (int i 0; i usercount; i) { if (!strcmp(user[i].password, password)) { if (VerificationCode()) { strcpy(user[i].UserRecentLoginTime, nowtime()); printf(\033[31m登录成功\033[0m\n); return true; } else { printf(\033[31m登录失败\033[0m\n); return false; } } else if (strcmp(user[i].username, username) || strcmp(user[i].password, password)) { printf(\033[31m账号或密码错误 登录失败\033[0\n); return false; } } }效果实现③修改账号代码实现/** * brief 修改用户信息编号/账号/密码 * return true 修改成功false 修改失败 */ bool ModifyUser() { char OldUsername[MAX_USERNAME_LENGTH] {0}; char OldPassword[MAX_USERNAME_LENGTH] {0}; char NewUsername[MAX_USERNAME_LENGTH] {0}; char NewPassword[MAX_USERNAME_LENGTH] {0}; int userNum 0, userNumPre 0; int input 0; printHeader(修改账号, 4); printf(按a修改用户编号\n按b修改用户账号\n按c修改用户密码\n); scanf(%lc, input); clearInputBuffer(); switch (input) { case a: printf(\033[94m请输入原用户账号编号:\033[0m\n); scanf(%d, userNumPre); if (!isUserNumberExist(userNumPre)) { printf(\033[33m不存在该账户编号\033[0m\n); return false; } printf(\033[94m请输入新编号:\033[0m\n); scanf(%d, userNum); IsUpdateExistUserCode(input, userNumPre, userNum, NULL); printf(\033[33m修改成功\033[0m\n); save_usersdata(); // 保存数据到文件 break; case b: printf(\033[94m请输入原账号:\033[0m\n); scanf(%s, OldUsername); if (!isUserExist(OldUsername)) { printf(\033[33m没有该账号 请重新注册\033[0m\n); return false; } printf(\033[94m请输入新修改的账号\033[0m\n); scanf(%s, NewUsername); if (VerificationCode()) { IsUpdateExistUserCode(input, OldUsername, NewUsername, NULL); printf(\033[33m账号修改成功\033[0m\n); save_usersdata(); // 保存数据到文件 } else { printf(\033[33m账号修改失败\033[0m\n); return false; } break; case c: printf(\033[94m请输入账号:\033[0m\n); scanf(%s, OldUsername); if (!isUserExist(OldUsername)) { printf(\033[33m没有该账号 请重新注册\033[0m\n); return false; } printf(\033[94m请输入原密码:\033[0m\n); // scanf(%s, OldPassword); get_password(OldPassword, sizeof(OldPassword)); if (!isUserPasswordExist(OldPassword, OldUsername)) { printf(密码错误\n); return false; } printf(\033[94m请输入新密码:\033[0m\n); get_password(NewPassword, sizeof(NewPassword)); // scanf(%s, NewPassword); if (VerificationCode()) { IsUpdateExistUserCode(input, OldPassword, NewPassword, OldUsername); printf(\033[33m账号修改成功\033[0m\n); save_usersdata(); // 保存数据到文件 } else { printf(\033[33m账号修改失败\033[0m\n); return false; } break; default: printf(\033[33m无效点击\033[0m\n); break; } }效果实现④注销账号代码实现/** * brief 注销当前账号 * return true 注销成功false 注销失败或取消 */ bool AccountCancellation() { char username[MAX_USERNAME_LENGTH] {0}; char password[MAX_USERNAME_LENGTH] {0}; char buf[20] {0}; printf(\033[94m请输入要注销的账号:\033[0m\n); scanf(%s, username); if (!isUserExist(username)) { printf(\033[33m没有该账号 请重新注册\033[0m\n); return false; } printf(\033[94m请输入注销账号的密码:\033[0m\n); // scanf(%s, password); get_password(password, sizeof(password)); printf(请输入 \YES\ 或 \NO\: \n); scanf(%s, buf); clearInputBuffer(); if (!strcmp(YES, buf)) { if ((IsDeleteExistUser(password, username))) { printf(\033[33m注销成功\033[0m\n); save_usersdata(); // 保存数据到文件 } else { printf(\033[33m密码错误 用户%s注销失败\033[0m\n, user[usercount].username); } } else if (!strcmp(NO, buf)) { printf(\033[33m账户注销已取消\033[0m\n); return false; } else { printf(无效输入\n); return false; } }效果实现⑤找回密码/** * brief 忘记密码流程通过安全问题重置密码 * return true 重置成功false 重置失败 */ bool UserForgetPassword() { char FirstPassword[100] {0}; char checkPassword[100] {0}; char usrans[1000] {0}; char username[100] {0}; printHeader(忘记密码, 4); printf(请输入账号:\n); scanf(%s, username); if (isUserExist(username)) { IsUserQuestion(username); printf(请回答你设置的问题:\n); scanf(%s, usrans); if (IsUserAnswer(username, usrans)) { printf(回答正确\n); printf(\033[94m请输入新密码\033[0m\n); get_password(FirstPassword, sizeof(FirstPassword)); // scanf(%s, FirstPassword); printf(\033[94m请再次输入密码:\033[0m\n); // scanf(%s, checkPassword); get_password(checkPassword, sizeof(checkPassword)); if (!strcmp(FirstPassword, checkPassword)) { if (VerificationCode()) { for (int i 0; i usercount; i) { if (!strcmp(user[i].username, username)) { strcpy(user[i].password, checkPassword); } } } else { return false; } } else { printf(密码错误 验证失败\n); return false; } } else { printf(回答错误 验证失败\n); return false; } } else { printf(账号不存在\n); return false; } return true; }⑥设置安全问答/** * brief 设置用户的安全问题与答案 * param currentuser 指向当前注册用户的指针 * return true 设置成功函数实际无返回但根据逻辑应成功 */ bool SetUserSecurityQuestion(User *currentuser) { // 设置安全问题 printf(\n\033[94m请设置安全问题,如:兴趣 生日 工作等问题(用于找回账号和密码):\033[0m\n); char ans[1024] {0}; scanf(%s, currentuser-UserSecurityQuestion); // 设置安全答案 printf(\033[94m请设置安全问题的答案: \033[0m\n); scanf(%s, currentuser-UserSecueityAnswer); printf(\n\033[32m安全问题设置成功\033[0m\n); // printf(问题: %s\n, currentuser-UserSecurityQuestion); // printf(答案: %s\n, currentuser-UserSecueityAnswer); }⑦验证码/** * brief 生成并验证验证码不区分大小写 * return true 验证通过false 验证失败 */ bool VerificationCode() { char j 0; char buf[VERIF_CODE_LENGTH] {0}; char str[VERIF_CODE_LENGTH] {0}; char temp 0; if (!buf || !str) { perror(内存分配失败\n); return -1; } srand((unsigned)time(NULL)); do { temp rand() % 127; if (isalpha(temp) || isdigit(temp)) { *(buf j) temp; j; } } while (j 6); buf[j] \0; printf(\033[93m验证码:%s\033[0m\n, buf); printf(\033[94m请输入验证码\033[0m\n); scanf(%s, str); int buf_len strlen(buf); int str_len strlen(str); if (!my_strncasecmp(buf, str, buf_len)) { printf(\033[33m验证码正确\033[0m\n); return true; } else { printf(\033[33m验证码错误\033[0m\n); return false; } } int my_strncasecmp(const char *s1, const char *s2, size_t n) { int d 0; while (n--) { d tolower(*s1) - tolower(*s2); if (d ! 0 || n 0) { break; } s2; s1; } return d; }3.管理端①后台管理主函数void houtai() { printHeader(后台管理, 4); int superchoice 0; char buf[100] {0}; printf(\033[33m用户注册数%d\033[0m\n\n, usercount); printf(用户编号\t用户名\t注册时间\t\t 最近登录时间\t\n); for (int i 0; i usercount; i) { printf(%02d\t\t%s\t%s %s\n, user[i].userNumber, user[i].username, user[i].UserRegisterTime, user[i].UserRecentLoginTime); } printf(\n--------------------------\n操作选项:\n); printf(1.返回主菜单\n); printf(2.清空用户数据(需管理员认证)\n); scanf(%d, superchoice); clearInputBuffer(); switch (superchoice) { case 1: break; case 2: if (wipe_alluserdata()) { IsLock false; clear_usersdata(); printf(已清空用户数据\n); clearInputBuffer(); printf(\n\033[5;93m按回车键退出。。。\033[0m\r); getchar(); printf(\033[2J\033[H); } else { static int count 3; static int sec 1; printf(你还有%d次机会\n, --count); if (count 0) { countdown(COUNTDOWN_TIME - 1); } else if (count 0) { IsLock true; count 2; countdown(10 * sec); sec * 2; printf(\033[2J\033[H); } } IsLock false; break; default: printf(\033[33m无效点击\033[0m\n); break; } }②后台管理员封用户账号bool wipe_alluserdata() { time_t now time(NULL); struct tm *tm localtime(now); char real_date[11]; char current_date[11] {0}; char confirm_code[50] {0}; snprintf(real_date, sizeof(real_date), %04d-%02d-%02d, tm-tm_year 1900, tm-tm_mon 1, tm-tm_mday); // 步骤1明确警告 printf(\n\033[1;31m!!! 警告 !!!\033[0m\n); printf(此操作将:\n); printf(1. 永久删除所有用户数据%d个账户\n, usercount); printf(2. 无法恢复任何数据\n); printf(3. 系统将恢复到初始状态\n\n); // 步骤2三重验证 printf(\033[33m第一步输入当前日期(YYYY-MM-DD):\033[0m\n); scanf(%s, current_date); if (strcmp(current_date, real_date)) { printf(\033[31m日期验证失败\033[0m\n); return false; } else { printf(\033[31m日期验证通过\033[0m\n); } printf(\033[33m第二步输入确认码CONFIRM-WIPE-ALL-DATA:\033[0m\n); scanf(%49s, confirm_code); if (strcmp(confirm_code, CONFIRM-WIPE-ALL-DATA) ! 0) { printf(\033[31m确认码错误\033[0m\n); countdown(COUNTDOWN_TIME); return false; } else { printf(\033[31m确认码通过\033[0m\n); } printf(\033[33m请输入超级管理员权限密码\033[0m\n); get_password(confirm_code, sizeof(confirm_code)); if (strcmp(confirm_code, 2021144112)) { printf(\033[31m管理员密码错误\033[0m\n); countdown(COUNTDOWN_TIME); return false; // printf(\n\033[5;93m按回车键退出。。。\033[0m\r); // getchar(); } else { printf(\033[31m管理员密码正确\033[0m\n); } return true; }③删除用户数据void clear_usersdata() { FILE *file fopen(USER_DATA_FILE, wb); // 关键使用wb模式 if (file) { memset(user, usercount, sizeof(user)); usercount 0; // 可选重置用户计数器 fflush(file); fsync(fileno(file)); fclose(file); } }效果实现4.数据加载和保存添加数据保存函数 开始执行代码时确保数据立即写入磁盘数据通过二进制文件持久化存储支持异常中断恢复防止因系统异常退出、电脑断电、CtrlC或CtrlZ中断程序操作等问题导致数据丢失// 信号处理函数保存数据并退出 void EXIT_SIGNAL_Handler(int sig) { save_usersdata(); exit(0); } // 添加数据保存函数 确保数据立即写入磁盘 void save_usersdata() { FILE *file fopen(USER_DATA_FILE, wb); if (file) { fwrite(usercount, sizeof(int), 1, file); fwrite(user, sizeof(User), usercount, file); fflush(file); fsync(fileno(file)); // 写入磁盘 fclose(file); } else { perror(保存用户数据失败); } } // 添加数据加载函数 void load_usersdata() { FILE *file fopen(USER_DATA_FILE, rb); if (file) { fread(usercount, sizeof(int), 1, file); fread(user, sizeof(User), usercount, file); fclose(file); } }5.输入密码显示星号/** * brief 设置终端模式规范模式/回显 * param echo 1 恢复规范模式并开启回显0 关闭规范模式和回显非阻塞读取 */ void set_terminal(int echo) { static struct termios oldt, newt; if (!echo) { tcgetattr(STDIN_FILENO, oldt); newt oldt; newt.c_lflag ~(ICANON | ECHO); // 关闭规范模式和回显 newt.c_cc[VMIN] 0; // 非阻塞读取 newt.c_cc[VTIME] 0; tcsetattr(STDIN_FILENO, TCSANOW, newt); } else { tcsetattr(STDIN_FILENO, TCSANOW, oldt); } } /** * brief 密码输入函数带字符回显延迟掩码 * param buf 存放密码的缓冲区 * param buf_len 缓冲区大小 * return 成功返回输入的密码长度失败返回-1 */ int get_password(char *buf, size_t buf_len) { set_terminal(0); // 设置非阻塞终端模式 size_t idx 0; // 密码索引 long long last_input_time 0; // 最后输入时间戳 int display_state 0; // 0显示字符, 1已转星号 // printf(Enter password: ); fflush(stdout); while (1) { char c; if (read(STDIN_FILENO, c, 1) 0) { // 非阻塞读取 // 处理回车确认 if (c \n || c \r) { buf[idx] \0; break; } // 处理退格删除 else if (c 127 || c \b) { if (idx 0) { idx--; printf(\b \b); // 删除屏幕字符 fflush(stdout); } } // 处理可打印字符 else if (idx buf_len - 1 isprint(c)) { buf[idx] c; putchar(c); // 立即显示字符 fflush(stdout); last_input_time get_timestamp(); display_state 0; // 标记需要后续掩码 } // 处理CtrlC中断 else if (c 3) { set_terminal(1); return -1; } } // 字符显示超时检查 if (!display_state last_input_time 0) { long long now get_timestamp(); if (now - last_input_time MASK_DELAY) { printf(\b*); // 退格替换为星号 fflush(stdout); display_state 1; // 标记已转换 } } usleep(INPUT_TIMEOUT * 1000); // 避免CPU过高占用 } set_terminal(1); // 恢复终端设置 printf(\n); return idx; }