使用c语言链表简单实现学生账户管理系统

目录

 

代码总览

 定义学生信息结构体

查询所有账户信息的void函数

查询账户余额的void函数

对余额进行充值

创建一个账户

注销账户

主函数部分


代码总览

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>

// 定义学生信息结构体
typedef struct StudentMessage {
    char name[20];
    int ID;
    int accountbalance;
    struct StudentMessage* next;
} STU;

// 查询所有账户信息
void SearchAllTheAccounts(STU* phead) {
    STU* pb = phead;
    while (pb != NULL) {
        printf("姓名:%20s   ||   ID账号:%20d\n", pb->name, pb->ID);
        pb = pb->next;
    }
    printf("NULL\n");
}

// 创建账户
void CreateAccount(STU** phead) {
    int count = 0;
    STU* pb = *phead;
    while (pb != NULL) {
        count++;
        pb = pb->next;
    }

    pb = *phead;
    STU* newp = (STU*)malloc(sizeof(STU)); // 分配新节点的内存
    printf("\n输入您的名字:");
    scanf("%s", newp->name);
    newp->ID = 10001 + count; // 在已有的id序列后添加
    printf("\n输入你想充值的金额:");
    scanf("%d",&newp->accountbalance);
    newp->next = NULL;

    while (pb->next != NULL) {
        pb = pb->next;
    }

    pb->next = newp;
    printf("您的id号码为%d",newp->ID);
}

void DeleteAccount(STU** phead)//注销账户
{
    int count = 0;
    STU* pb = *phead;
    STU* pf = *phead;
    int id;
        printf("\n输入您的ID:");
        scanf("%d", &id);
        while (pb->ID != id && pb->next != NULL)
        {
            pf = pb;
            pb = pb->next;
        }
        if (pb->ID == id)
        {
            if (pb == *phead)
            {
                *phead = pb->next;
            }else{
                pf->next = pb->next;
            }
            free(pb);
            pb = NULL;
        }else{
            printf("没有找到您要注销的账户\n");
        }
}

void AddAccount(STU* phead)//充值余额
{
    int addation;
    STU* pb = phead;
    int count = 0;
        int id;
        printf("\n输入您的ID:");
        scanf("%d", &id);
        printf("\n输入你要充值的金额:");
        scanf("%d", &addation);
        while (pb != NULL) {
            if (pb->ID == id) {
                pb->accountbalance += addation;
                count++;
                break;
            }
            else {
                pb = pb->next;
            }
        }
        if (count == 0) {
            printf("\n没有查找到您的信息");
        }
}

void SerchAccountbanlance(STU* phead)//查找账户余额
{
    STU* pb = phead;
    int count = 0;
        int id;
        printf("\n输入您的ID:");
        scanf("%d", &id);
        while (pb != NULL) {
            if (pb->ID ==id) {
                printf("\n您的余额为%d", pb->accountbalance);
                count++;
                break;
            }else{
                pb = pb->next;
            }
        }
        if (count == 0) {
            printf("\n没有查找到您的信息");
        }
}


int main()
{
    //创建一个随机数用于给不同学生不同的余额
    srand(time(NULL));
    // 初始化链表头
    STU* head = NULL;
    char names[][20] = { "lvzhongyu", "john", "arthon", "majinchao", "jack", "alien", "david", "lucy", "kevin", "adam","xiaohu", "weiwei", "jiejie", "knight", "mlxg", "theshy", "faker", "zues", "guma", "droan" };
    for (int i = 0; i < 20; ++i) {
        STU* newStudent = (STU*)malloc(sizeof(STU));
        // 设置每个学生的信息
        snprintf(newStudent->name, sizeof(newStudent->name), "%s", names[i]);
        newStudent->ID = 10001 + i;  // 起始ID为10001
        newStudent->accountbalance = rand()%201;  //初始余额为200元中的任意数
        newStudent->next = head;  // 在链表头插入
        head = newStudent;  // 更新链表头
    }
    char c = ' ';
    printf("输入下列几个选项来表示您需要的操作\n"
        "A.查询现有的账户ID\n"
        "B.查询账户余额\n"
        "C.对余额进行充值\n"
        "D.创建新的账户\n"
        "E.注销您的账户\n");

    while (c != '#') {
        printf("\n输入您要进行的操作(当您输入#时会结束程序): ");
        scanf_s(" %c", &c);

        switch (c) {
        case 'A':
            SearchAllTheAccounts(head);
            break;
        case 'B':
            SerchAccountbanlance(head);
            break;
        case 'C':
            AddAccount(head);
            break;
        case 'D':
            CreateAccount(&head);
            break;
        case 'E':
            DeleteAccount(&head);
            break;
        }
    }

    printf("\n感谢您的使用");

    STU* cur = head;
    while (cur != NULL) {
        STU* temp = cur;
        cur = cur->next;
        free(temp);
    }

    return 0;
}

 定义学生信息结构体

typedef struct StudentMessage {
    char name[20];
    int ID;
    int accountbalance;
    struct StudentMessage* next;
} STU;

使用typedef的作用是使得你可以使用STU作为struct StudentMessage的别名。这样,在定义变量或使用结构体类型时,可以使用STU而不是完整的struct StudentMessage。这有助于简化代码,提高可读性,以及使得代码更加灵活,因为可以随时修改struct StudentMessage的定义而不需要修改所有使用到该结构体的地方。

查询所有账户信息的void函数

void SearchAllTheAccounts(STU* phead) {
    STU* pb = phead;
    while (pb != NULL) {
        printf("姓名:%20s   ||   ID账号:%20d\n", pb->name, pb->ID);
        pb = pb->next;
    }
    printf("NULL\n");
}

首先定义一个SearchAllTheAccounts(STU* phead)。其中phead传递的是当前所有账户构成的链表。在函数内,定义一个pb链表,将其赋值为传入的phead链表。随后使用while函数打印出所有账户的信息(条件为pb!=NULL即意为循环遍历一直直到最后一个节点)。printf("NULL\n");语句的目的是在遍历完链表后输出一个提示信息,表示链表已经结束。这是一种常见的做法,特别是当你使用循环遍历链表时,用于指示当前节点为空(即NULL),因此已经到达链表的末尾。

查询账户余额的void函数

void SerchAccountbanlance(STU* phead)//查找账户余额
{
    STU* pb = phead;
    int count = 0;
        int id;
        printf("\n输入您的ID:");
        scanf("%d", &id);
        while (pb != NULL) {
            if (pb->ID ==id) {
                printf("\n您的余额为%d", pb->accountbalance);
                count++;
                break;
            }else{
                pb = pb->next;
            }
        }
        if (count == 0) {
            printf("\n没有查找到您的信息");
        }
}

定义部分与上面的内容同理。这里需要定义一个计数器count,并且要将其初始化为0。随后定义个一将有用户输入的id账户,用于检查他是否与现有链表中的id相符(这里的检查办法是使用一个计数器,当有相等的时候对计数器count进行自增)。随后利用循环进行查找是否库中存在这样一个id,当查找到时,break跳出循环,防止循环无法停止。

对余额进行充值

void AddAccount(STU* phead)//充值余额
{
    int addation;
    STU* pb = phead;
    int count = 0;
        int id;
        printf("\n输入您的ID:");
        scanf("%d", &id);
        printf("\n输入你要充值的金额:");
        scanf("%d", &addation);
        while (pb != NULL) {
            if (pb->ID == id) {
                pb->accountbalance += addation;
                count++;
                break;
            }
            else {
                pb = pb->next;
            }
        }
        if (count == 0) {
            printf("\n没有查找到您的信息");
        }
}

 函数定义部分依旧与上面的类似。这部分函数大部分与上面的函数相同,只是需要用户输入一个他想充值的金额。并且在原有的基础上加上这么一个数字即可。

创建一个账户

void CreateAccount(STU** phead) {
    int count = 0;
    STU* pb = *phead;
    while (pb != NULL) {
        count++;
        pb = pb->next;
    }

    pb = *phead;
    STU* newp = (STU*)malloc(sizeof(STU)); // 分配新节点的内存
    printf("\n输入您的名字:");
    scanf("%s", newp->name);
    newp->ID = 10001 + count; // 在已有的id序列后添加
    printf("\n输入你想充值的金额:");
    scanf("%d",&newp->accountbalance);
    newp->next = NULL;

    while (pb->next != NULL) {
        pb = pb->next;
    }

    pb->next = newp;
    printf("您的id号码为%d",newp->ID);
}

传递STU** phead的参数通常用于在函数内部修改调用者传递的指针的值。这是因为C语言中的函数参数传递是按值传递的,这意味着函数内部对参数的修改不会影响到调用者。当你传递一个指针给函数时,函数获得了指针的拷贝,因此它可以修改指针所指向的内容,但不能修改指针本身。如果你想在函数内部修改指针本身,你需要传递指针的指针,即STU** phead

同样的,我们需要一个计数器,但是功能与上一个不相同,这个count是用于查看当前列表中有多少人,这样可以在新创办一个用户时按照既定好的顺序安排id卡号。值得注意的是,当我们遍历完这个链表中的所有部分后,还需要重新将pb赋值为phead。

之后我们正式开始加入一个新的账户。使用STU* newp = (STU*)malloc(sizeof(STU));

  1. malloc(sizeof(STU)): sizeof(STU)返回STU类型的大小(即结构体的大小),malloc函数用于动态分配内存。这段代码请求分配足够的内存,以存储一个STU类型的结构体。

  2. (STU*): malloc返回一个void*类型的指针,因为它不知道分配的内存将被用于什么类型的数据。在这里,我们将void*强制类型转换为STU*,以便将其赋给newp,这样我们就能够通过newp指针来操作这段分配的内存。

整个过程的目的是在堆内存中创建一个新的STU类型的节点,该节点包含了一个名字、ID、账户余额以及一个指向下一个节点的指针。这个新节点的地址被存储在newp指针中,以便后续的操作可以使用这个节点。

最后就是由用户输入ta的姓名以及想往账户里面存储的款项。最后的最后就是将链表遍历至当前的的后一项,并且把最后一项赋值为我们加入的新的节点。

注销账户

void DeleteAccount(STU** phead)//注销账户
{
    STU* pb = *phead;
    STU* pf = *phead;
    int id;
        printf("\n输入您的ID:");
        scanf("%d", &id);
        while (pb->ID != id && pb->next != NULL)
        {
            pf = pb;
            pb = pb->next;
        }
        if (pb->ID == id)
        {
            if (pb == *phead)
            {
                *phead = pb->next;
            }else{
                pf->next = pb->next;
            }
            free(pb);
            pb = NULL;
        }else{
            printf("没有找到您要注销的账户\n");
        }
}

这次采用的方法时快慢指针类似方法,定义两个链表,分别都赋值为phead。

首先要做的是遍历pb,在遍历pb的同时将pf赋值为pb的上一个节点。这样可以保证能够同时处理对当前节点和下一个节点的修改。

而后找到我们要注销的账户后,进行分情况讨论(第一个就是我们要删除的或者节点不在第一个)。当第一个就是目标节点是我们直接把phead的地址改为pb的下一个。当不是第一个的情况下,我们直接将pt->next改为pb->next(相当于直接跳过了pb这个我们要删除的账户)。一定要记得释放我们删去的这个节点对应的内存。

主函数部分

int main()
{
    //创建一个随机数用于给不同学生不同的余额
    srand(time(NULL));
    // 初始化链表头
    STU* head = NULL;
    char names[][20] = { "lvzhongyu", "john", "arthon", "majinchao", "jack", "alien", "david", "lucy", "kevin", "adam","xiaohu", "weiwei", "jiejie", "knight", "mlxg", "theshy", "faker", "zues", "guma", "droan" };
    for (int i = 0; i < 20; ++i) {
        STU* newStudent = (STU*)malloc(sizeof(STU));
        // 设置每个学生的信息
        snprintf(newStudent->name, sizeof(newStudent->name), "%s", names[i]);
        newStudent->ID = 10001 + i;  // 起始ID为10001
        newStudent->accountbalance = rand()%201;  //初始余额为200元中的任意数
        newStudent->next = head;  // 在链表头插入
        head = newStudent;  // 更新链表头
    }
    char c = ' ';
    printf("输入下列几个选项来表示您需要的操作\n"
        "A.查询现有的账户ID\n"
        "B.查询账户余额\n"
        "C.对余额进行充值\n"
        "D.创建新的账户\n"
        "E.注销您的账户\n");

    while (c != '#') {
        printf("\n输入您要进行的操作(当您输入#时会结束程序): ");
        scanf_s(" %c", &c);

        switch (c) {
        case 'A':
            SearchAllTheAccounts(head);
            break;
        case 'B':
            SerchAccountbanlance(head);
            break;
        case 'C':
            AddAccount(head);
            break;
        case 'D':
            CreateAccount(&head);
            break;
        case 'E':
            DeleteAccount(&head);
            break;
        }
    }

    printf("\n感谢您的使用");

    STU* cur = head;
    while (cur != NULL) {
        STU* temp = cur;
        cur = cur->next;
        free(temp);
    }

    return 0;
}

因为我是预先留存了20个人的信息于这个head链表中。我们首先定义一个二维数组用于存储这20个人的名字,之后利用循环,逐个建立节点并且使用snprintf(newStudent->name, sizeof(newStudent->name), "%s", names[i]);将二维数组中的名字挨个赋给它们。同时利用随机数函数随机给这20个人分配账户余额。之后还需要更新链表头,随后就是询问用户需要的操作。在完成所有程序之后。我们需要释放链表中所有的节点即

STU* cur = head;
    while (cur != NULL) {
        STU* temp = cur;
        cur = cur->next;
        free(temp);
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值