C项目实践--图书管理系统(3)

接下来将要实现用户管理模块的相关功能,用户管理模块的主要功能包括增加用户,查找用户以及保存用户等功能,查找用户时,如果查找成功,充许对查找到用户进行更新或删除操作。如果查找不成功,则给出相应的提示信息。

打开user.c文件, 首先包含要用到的头文件,同时还需要定义一个常量用来表示存储用户信息的文件,定义一个单链表的头节点,并初试化为空。具体实现如下:

#pragma warning(disable:4996)
 
//Header Info
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //使用memset函数 memset是字符串处理函数
#include <conio.h> //使用kbhit()函数 来星号显示密码
#include "user.h"
#include <assert.h>
 
#define USER_FILE "user.dat" //表示用来存储用户信息的文件
user* first_user = NULL;  //定义一个头节点, 初始化为NULL

下面来实现主要的处理函数:

1.新增用户

函数名称:add_user

函数功能:新增一个用户信息,在管理员操作菜单中,选择6调用本函数,由于用户名不充许重复,所以用户输入用户名和密码后,需要在用户链表中查询用户名是否重复。

处理流程:1创建一个用户节点new_user. 2初始化new_user. 3.调用函数input_user(), 提示用户输入用户信息,为new_user赋值。4.调用函数find_user(),查找用户名是否存在,如果新增用户名不存在,则增加该用户,否则提示相应的信息。具体实现如下:

//新增用户信息
void add_user()
{
    char try_again = 'Y';
    user* p = NULL;
    user* new_user= (user*)malloc(sizeof(user));
    assert(new_user != NULL);
    while(try_again == 'Y' || try_again == 'y')
    {
        memset(new_user,0,sizeof(user));
        printf(">增加用户信息...\n");
        input_user(&(new_user->ui));
        //对比用户名是否已存在
        p = find_user(new_user->ui.username);
        if(NULL == p)
        {
            p = get_last_user();
            p->next = new_user;
            break;
        }
 
        printf(">用户[ %s ]已存在.重新输入?(y or n ):",new_user->ui.username);
        fflush(stdin);
        try_again = getchar();
        if(try_again !='y' && try_again !='Y')
        {
            free(new_user);
        }
    }
}

2.查找用户

函数名称:search_user

函数功能:查找用户信息,在管理员操作菜单中选择7调用本函数,提示用户输入要查询的用户名,在用户链表中进行查找,如果查找成功,显示该用户信息,并提示按d/D键删除该用户信息,按u/U键更新该用户信息。如果查找不成功,则给出提示信息。

处理流程:1提示用户输入要查询的用户名,根据用户名进行查找。2调用函数find_user()查找输入的用户名信息,若存在,则将用户信息赋值给节点p。3如果没有找到,则给出提示信息,如果找到了则调用show_user()函数,显示该用户信息,并提示用户可以对该用户信息进行删除或更新操作。具体实现如下:

void search_user()
{
    char input_char = 'Y';
    char username[MAX_USERNAME] = {0};
    user* p = NULL;
    while(input_char == 'Y' || input_char == 'y')
    {
        printf(">查找用户信息...\n");
        printf(">请输入用户名(最大长度为 %d):",MAX_USERNAME);
        fflush(stdin);
        scanf("%s",username);
        p = find_user(username);
        if(p == NULL)
        {
            printf(">未找到用户:%s的信息.继续查找?(y or n)",username);
            fflush(stdin);
            input_char = getchar();
            continue;
        }
        show_user(&(p->ui));
        printf(">查找成功!按d/D键删除该用户,按u/U键更新该用户信息,按其它键返回!");
        fflush(stdin);
        input_char = getchar();
        if(input_char == 'd'||input_char == 'D')
        {
            delete_user(p);
        }else if(input_char =='U' || input_char == 'u')
        {
            update_user(p);
        }
        printf(">继续查找其它用户吗?(y or n):");
        fflush(stdin);
        input_char = getchar();
    }
}

3.删除用户信息

函数名称:delete_user

函数功能:管理员在查找到用户成功时,充许对其找到的用户信息进行删除操作。

处理流程:提示用户是否确认要删除该用户信息,如果输入"y"或"Y", 则删除该用户信息,否则继续查找。具体实现如下:

void delete_user(user* p)
{
    char input_char = 'N';
    user* previous = NULL;
    printf(">确认要删除用户 [%s] 吗?(y or n):",p->ui.username);
    fflush(stdin);
    input_char = getchar();
    if(input_char == 'y' || input_char == 'Y')
    {
        previous = get_previous_user(p);
        previous->next = p->next;
        free(p);
        p = NULL;
    }
}

4.更新用户信息

函数名称:update_user

函数功能:管理员在查找到用户成功时,充许对找到的用户信息进行更新操作。

处理流程:1创建一个用户信息new_p, 2调用函数input_user()往new_p中输入用户信息。3在用户链表中查找该用户是否存在,如果输入的用户名已存在,并且这个用户名不是原来的p,系统给出相关提示信息,等待下一步操作,否则进行更新操作。具体实现如下:

//更新用户信息
void update_user(user* p)
{
    char input = 'y';
    user* exist_p = NULL;
    user_info* new_p = (user_info*)malloc(sizeof(user_info));
    assert(new_p != NULL);
    while(input == 'y'|| input == 'Y')
    {
        memset(new_p,0,sizeof(user_info));
        input_user(new_p);
        //查找当前更新时输入的用户名是否已经存在
        exist_p = find_user(new_p->username);
        //如果单链表中存在这个用户名,且新更新的用户名和刚才被更新的用户名不相等
        //则表示不能进行更新
        if(exist_p != NULL && exist_p != p)
        {
            printf(">用户[%s] 已存在.请选用其它用户名.\n",exist_p->ui.username);
            printf(">重新输入?(y or n):");
            fflush(stdin);
            input = getchar();
        }else{
            strcpy(p->ui.username,new_p->username);
            strcpy(p->ui.password,new_p->password);
            p->ui.user_type = new_p->user_type;
            break;
        }
    }
    free(new_p);
}

5.保存用户信息

1.函数名称:save_users

函数功能:管理员操作菜单中选择8调用本函数,用来保存用户信息,函数中通过调用save_users_to_file()函数将用户信息保存到文件中,并给出提示信息,具体实现如下:

void save_users()
{
    save_users_to_file();
    printf(">保存成功!按任意键返回...");
    fflush(stdin);
    getchar();
}
2.保存用户信息到文件
函数名称:save_users_to_file
函数功能:将用户信息保存到文件。具体实现如下:
void save_users_to_file()
{
    FILE* fp = fopen(USER_FILE,"wb");
    user* p = first_user;
    while(p != NULL)
    {
        fwrite(&(p->ui),sizeof(user_info),1,fp);
        fseek(fp,0,SEEK_END);
        p = p->next;
    }
 
    fclose(fp);
}

上面完成了用户管理模块的主要功能函数,但是还需要一些辅助函数才能完整的实现用户管理模块的功能,这些辅助函数实现如下:

1.用户模块初始化

函数名称:init_user

函数功能:设定默认的用户名为admin, 密码为123,权限为管理员,如果存储用户信息的文件不存在则创建一个,如果创建失败则给出提示信息。具体实现如下:

void init_user()
{
    FILE* fp = NULL;
    user_info default_admin;
    strcpy(default_admin.username,"admin");
    strcpy(default_admin.password,"123");
    default_admin.user_type = ADMIN;
    fp = fopen(USER_FILE,"r");
    if(NULL == fp)
    {
        fp = fopen(USER_FILE, "wb");
        fwrite(&default_admin,sizeof(user_info),1,fp);
    }
    fclose(fp);
}

2.加载用户信息

函数名称:load_users

函数功能:从用户文件中将用户信息加载到用户链表中。具体实现如下:

void load_users()
{
    user* u = NULL;
    user* last = NULL;
    FILE* fp = NULL;
    int count = 0; 
    u = (user*)malloc(sizeof(user));
    memset(u,0,sizeof(user));
    u->next = NULL;
    //以只读方式打开二进制文件USER_FILE
    fp = fopen(USER_FILE , "rb");
    //将文件指针置为文件开始处
    fseek(fp,0,SEEK_SET);
    //从文件中逐个读取用户信息,并把它们存放到用户链表中
    while(fread(&(u->ui),sizeof(user_info),1,fp) == 1)
    {
        if(first_user == NULL)
        {
            first_user = u;
        }else{
            last = get_last_user();
            last->next = u;
        }
        count++;
        //以user_info长度为单位相对文件开始位置
        //偏移文件指针的位置
        fseek(fp,count*sizeof(user_info),SEEK_SET);
        u = (user*)malloc(sizeof(user));
        memset(u,0,sizeof(user));
        u->next = NULL;
    }
    free(u);
    u = NULL;
    fclose(fp);
}

3.判断用户类型

函数名称:login

函数功能:用户登录功能,如果输入正确,返回用户类型。

处理流程:1.提示输入登录名和密码,2.在用户链表中查找是否存在该登录名,若不存在,则给出提示信息,否则继续判断密码是否匹配,如果匹配成功,则返回用户权限类型,否则给出提示信息。具体实现如下:

USER_TYPE login()
{
    char username[MAX_USERNAME] = {0};
    char password[MAX_PASSWORD] = {0};
    int j = 0;
    char try_again = 'Y';
    user* p = NULL;
    while(try_again == 'y' || try_again == 'Y')
    {
        printf("请输入用户名:");
        fflush(stdin);
        scanf("%s",username);
        printf("  请输入密码:");
        fflush(stdin);
        //scanf("%s",password);
        //密码输入处理:输入一个字符,回显一个星号
        getLine(password,MAX_PASSWORD);
        //printf("\n");
        p = find_user(username);
        if(p == NULL)
        {
            printf("\n用户名输入有误.请重试!\n");
        }else if(strcmp(p->ui.password,password) != 0)
        {
            printf("\n密码输入有误.请重试!按任意键继续...\n");
        }else{
            return p->ui.user_type;
        }
        printf(">重新输入吗?按其它键退出系统(y or Y 继续):");
        fflush(stdin);
        try_again = getchar();
    }
    exit(0);
}
 
//密码输入处理,输入一个字符就回显一个星号
char *getLine(char *buf,int len)
{
    int i = 0;
    char ch;
    
    fflush(stdin);
    /*while(i<len-1 && '\n' !=(ch = kbhit()))*/
    while(i<len-1)
    {
        //ch 第一次接收到一个字符之后, 以后一直存在这个字符,所以输入失效
        /*if('\0' != ch){*/
        if(0 != kbhit()){
            //kbhit()只能检测到键盘是否有键位按下,如果有则返回非零值,否则返回零
            //返回的这个非零值并非代码键位的ASCII值,所以返回值不能用
            //getchar()用来接收输入的字符串,输入一个就回显一个直到遇到空格或回车
            //才停止接收输入
            //ch = getchar();
            ch = getch();
            //c中 \r 才是代表 回车符
            if(ch == '\r') break;
            putchar('*');
            buf[i] = ch;
            ++i;
        }
    }
    buf[i] = '\0';
    return buf;
}

4.清除用户链表

函数名称:clear_users

函数功能:从内存中清除用户链表中的内容。具体实现如下:

void clear_users()
{
    user* p = NULL;
    //从头节点往后一个个清空
    while(first_user != NULL)
    {    
        if(first_user->next != NULL)
        {
            p = first_user;
            first_user = first_user->next;
            free(p);
            p = NULL;
        }else{
            free(first_user);
            first_user = NULL;
        }
    }
}

5.取用户链表中的最后一个节点

函数名称:get_last_user

函数功能:取得用户链表中的最后一个节点并返回该节点指针。具体实现如下:

user* get_last_user()
{
    user* p = first_user;
    while((NULL != p) &&(p->next != NULL))
    {
        p = p->next;
    }
    return p;
}

6.取某节点的前驱节点

函数名称:get_previous_user

函数功能:取得节点p的前驱节点并返回该节点的指针。具体实现如下:

user* get_previous_user(user* p)
{
    user* previous = first_user;
    while(previous != NULL)
    {
        if(previous->next == p)
        {
            break;
        }
        previous = previous->next;
    }
    return previous;
}

7.显示用户信息

函数名称:show_user

函数功能:显示用户信息。具体实现如下:

void show_user(user_info* info)
{
    printf("------------------------------------------\n");
    printf("  用户名:%s\n",info->username);
    printf("    密码:%s\n",info->password);
    printf("用户类型:%s\n",info->user_type == ADMIN ? "admin" : "user");
    printf("\n");
}

8.输入用户信息

函数名称:input_user

函数功能:提示用户输入用户相关信息,具体实现如下:

void input_user(user_info* info)
{
    printf(">请输入用户名(最大长度为 %d):",MAX_USERNAME);
    fflush(stdin);
    scanf("%s",info->username);
    printf(">请输入密码(最大长度为 %d):",MAX_PASSWORD);
    fflush(stdin);
    scanf("%s",info->password);
    printf(">请输入用户类型(%d 是管理员,%d 是普通用户):",ADMIN,USER);
    fflush(stdin);
    scanf("%d",&(info->user_type));
}

9查找一个用户

函数名称:find_user

函数功能:从用户链表中查找指定的用户名是否存在,若存在则返回该用户节点指针,否则返回NULL。具体实现如下:

user* find_user(char* name)
{
    user* p = first_user;
    int is_found = 0;
    while(p != NULL)
    {
        //字段比对,如果相同则strcmp返回0
        if(strcmp(p->ui.username,name) == 0)
        {
            is_found = 1;
            break;
        }
        p = p->next;
    }
    if(is_found)
    {
        return p;
    }
    return NULL;
}

到此为止,图书管理系统的三大功能模块:登录管理模块,图书信息管理模块和用户信息管理模块已基本实现完毕,接下来是系统操作过程分析,具体情况请转入:<< C项目实践--图书管理系统(4)>>

posted @ 2013-10-29 23:27  AI Algorithms  阅读(782)  评论(0编辑  收藏  举报