概述
需求来源:
在一些没有前台的那种公寓酒店订房的时候,就会有一个人加我微信,之后给我发一个房间号,和密码。这需要一种用户的功能来控制门锁的密码。同时也有一个房间好几个人合租的情况,它们都是多个用户共享一把锁,当用户退房后,这个用户在系统中就被删除。
设计这个用户功能,可以更加方便的管理用户的密码、修改相应权限等。
设置整体思路:
该用户管理功能的实现基于链表。一切基于C语言链表的增删改查。结构框图如下:
首先我们需要把用户的信息用结构体的形式抽象出来,之后每一个结构体就代表一个用户。
然后需要创建一个不可被删除的头结点,这个用户称为root用户,就是整个用户系统的管理员。
之后每添加一个用户,就在root用户之后进行链接即可。
相关函数功能:
- 初始化用户系统:pUsr init_user(void);
- 创建新用户:pUsr create_user(char* name,char* phone);
- 添加用户:int add_user(pUsr newUser);
- 删除用户:int del_user(char* name);
- 查询用户:pUsr search_user(char* name);
- 检查用户密码:int check_passwd(char* name,char* oldPasswd);
程序实现
0、定义用户结构体
一个用户具有用户名、密码、绑定的手机这三种属性,将其定义为一个结构体进行管理。定义如下
typedef struct user{
char* name; //用户名
char passwd[7]; //正确密码
char phone[12]; //绑定手机号
struct user* pNext;
}Usr,*pUsr;
在这个结构体中,规定了密码为6位,绑定的电话号码为11位。
这个用户定义的框架是链表形式,之后将以链表的增删改查为基础对其进行管理。
同时,在.c文件中定义了两个静态全局变量,用于存放用户系统的头结点和尾结点位置:
static pUsr gpUserTail = NULL;//尾结点指针
static pUsr gpUserHead = NULL;//头结点指针
1、初始化用户系统
代码需求:
- 初始化用户系统就是创建root用户作为头结点,这个root用户名称为root,密码为123456。
- root用户是禁止删除的用户,代表整个用户系统的存在,之后创建的新用户会链接到root之后。
代码实现步骤:
- 使用malloc开辟用户空间和用户名空间。
- 使用strcpy对用户名、密码进行赋值,即:初始化用户信息。
具体代码实现如下:
/*
* pUsr init_user:初始化用户列表,创建root用户
* root用户名为root,密码为000000
* @ret NULL--err other--success
* */
pUsr init_user(void){
//1.开辟空间,创建root用户结点
//1.1 头指针,尾指针都指向这个结点
gpUserTail = (pUsr)malloc(sizeof(Usr));
gpUserHead = gpUserTail;
if(gpUserTail == NULL){
printf("init user err\n");
return NULL;
}
//1.2 开辟名字空间,用户名为root
gpUserHead->name = (char*)malloc(sizeof(char)*(strlen("root")+1));
if(gpUserHead->name == NULL){
printf("name malloc err\n");
return NULL;
}
//2.初始化用户
//2.1 清空
memset(gpUserHead->name,'0',sizeof(strlen("root")+1));
memset(gpUserHead->passwd,'0',sizeof(gpUserHead->passwd));
memset(gpUserHead->phone,'0',sizeof(gpUserHead->phone));
//2.2 赋值
strcpy(gpUserHead->name,"root");
strcpy(gpUserHead->passwd,"123456");
gpUserHead->pNext = NULL;
return gpUserTail;
}
2、创建新用户
代码需求:
- 创建新用户,设置初始密码为000000,用户名和电话由函数外部传入。
代码实现步骤:
- 与初始化用户系统类似,只是初始化的用户信息不同。
- 需要对用户名重复进行判断,不允许出现用户名重复的情况。
- 需要对传入的电话进行判断,保证电话号码长度正确。
具体代码实现如下:
/*
* create_usr:创建一个用户,初始密码000000
* param name : 用户名
* param phone: 绑定手机号
* @ret NULL--err other--用户结构体的指针
* */
pUsr create_user(char* name,char* phone){
pUsr pUser = NULL;
//1.参数有效性判断
//1.1 用户名重复判断
if(search_user(name) != NULL){
printf("user name exsit\n");
return NULL;
}
//1.2 电话长度判断
if(strlen(phone) != 11){
printf("phone length err\n");
return NULL;
}
//2.申请空间
//2.1 开辟用户空间
pUser = (pUsr)malloc(sizeof(Usr));
if(pUser == NULL){
printf("pUser malloc err\n");
return NULL;
}
//2.2 开辟名字空间
pUser->name = (char*)malloc(sizeof(char)*(strlen(name)+1));
if(pUser->name == NULL){
printf("name malloc err\n");
return NULL;
}
//3.初始化
//3.1 清空
memset(pUser->name,'0',sizeof(strlen(name)+1));
memset(pUser->passwd,'0',sizeof(pUser->passwd));
memset(pUser->phone,'0',sizeof(pUser->phone));
//3.2 赋值
strcpy(pUser->name,name);
strcpy(pUser->passwd,"000000");
strcpy(pUser->phone,phone);
pUser->pNext = NULL;
return pUser;
}
3、添加用户
添加用户在这里设计的就是在尾部插入用户即可。
注意:在尾部插入后,尾部全局变量指针需要去更新。
具体代码实现如下:
/*
* add_user:添加用户
* param newUser:新用户结点
* @ret -1--err 0--success
* */
int add_user(pUsr newUser){
pUsr point = gpUserTail;//尾部结点
//1.判断结点非空
if(newUser == NULL){
printf("newUser is NULL\n");
return -1;
}
//2.开始插入
point->pNext = newUser;
gpUserTail = newUser;//尾插后更新尾部的指针指向
return 0;
}
4、删除用户
代码需求:
- 删除用户就是链表的删除,这里规定头部不能被删除。
代码实现分析:
- 首先找到链表位置并保存链表前驱的位置,之后开始删除链表
- 这里需要分三种情况:删除的是头、删除的是尾、删除的是中间 头结点禁止删除、尾结点删除后尾部指针需要更新,中间删除就是正常的链表删除。
具体代码实现如下:
/*
* del_user:删除指定的用户
* param name:要删除的用户名
* @ret -1--err 0--success
* */
int del_user(char* name){
pUsr point = gpUserHead;
pUsr pTmp = NULL;//pTmp存储上一个结点,头结点的上一个结点为NULL
//1.判断结点非空
if(name == NULL){
printf("name is NULL\n");
return -1;
}
//2.找到用户所在的结点
while(point!=NULL){
if(strcmp(point->name,name) == 0){
break;
}
pTmp = point;//上一个结点
point = point->pNext;
}
//3.开始删除
//3.1 找不到,代表以及删除了
if(point == NULL){
printf("user has del\n");
return 0;
}
//3.2 找到了,开始删除
if(strcmp(point->name,"root") == 0){//头禁止删除
printf("root cannot del\n");
return 0;
}
if(point->pNext == NULL){//尾巴删除后指针改变
gpUserTail = pTmp;
}
pTmp->pNext = point->pNext;
free(point);
point = NULL;
return 0;
}
5、查询用户
查询用户就是遍历整个链表,查找到名称相同的用户。
具体代码实现如下:
/*
* search_user:按名字寻找用户结点
* param name:要寻找的用户的名字
* @ret NULL--not find other--第一个结点首地址
* */
pUsr search_user(char* name){
pUsr point = gpUserHead;
//1.参数有效性判断
if(name == NULL){
printf("name is NULL\n");
return NULL;
}
//2.遍历寻找
while(point!=NULL){
//printf("Debug:point->name = %s\n",point->name);
if(strcmp(point->name,name) == 0){
break;
}
point = point->pNext;
}
if(point == NULL){
//printf("not find\n");
}
return point;
}
6、检查用户密码
检查用户密码,就是找到指定的用户,比较一下它的密码和传入的密码是否相同。
具体代码实现如下:
/*
* check_passwd:验证原密码正确性
* param name:用户名
* param oldPasswd:原密码
* @ret -1--err 0--passwd right
* */
int check_passwd(char* name,char* oldPasswd){
pUsr pUser = NULL;
//1.判断参数有效性
//1.1 指针非空判断
if(name == NULL || oldPasswd == NULL){
printf("param err\n");
return -1;
}
//1.2 密码长度合法判断
if(strlen(oldPasswd) != 6){
printf("passwd len err\n");
return -1;
}
//2.找到用户所在的结点
pUser = search_user(name);
if(pUser == NULL){
printf("user not exsit\n");
return -1;
}
//3.验证原密码正确性
if(strcmp(pUser->passwd,oldPasswd) != 0){
printf("oldPasswd err\n");
return -1;
}else{
printf("oldPasswd right\n");
return 0;
}
}