C语言实现学生信息管理系统(详细注释)

学习B站up主C3程序猿的视频后总结分享【学生管理系统】_哔哩哔哩_bilibili【学生管理系统】https://www.bilibili.com/video/BV1uW411Q7Cf?spm_id_from=333.999.0.0

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


//学生结点
typedef struct _STU
{
    char arrStuName[20];
    char arrStuNum[100];
    int iStuScore;
    struct _STU* pNext;
}STUNODE;

//声明链表的头和尾
STUNODE* g_pHead = NULL;//全局变量用g_
STUNODE* g_pEnd = NULL;

void menu();//主菜单
void AddStuMSG(char* arrStuNum, char* arrStuName, int iStuScore);//添加一个学生的信息(尾添加)
void FreeLinkData();//清空链表
void ShowStuData();//打印数据
void AddStuMSGToLinkHead();//链表头添加一个结点(头添加)
STUNODE* FindStuByNum(char* arrStuNum);//查找指定学生信息
void InsertNode(STUNODE* pTemp, char* arrStuNum, char* arrStuName, int iStuScore);//特定位置插入结点                               先连接再断开
void DeleteStuNode(STUNODE* pNode);//删除指定学生信息
void SaveStuToFile();//保存学生信息到文件中
void ReadStuFromFile();//读取文件中的文件信息
void FixStuByNum(STUNODE* pTemp,int target,char* strFixedData);//修改指定学生信息(学号,目标修改数据,用于替换的数)

int main()
{
    int iOrder = -1;
    char arrStuNum[20] = { '\0' };
    char arrStuName[20] = { '\0' };
    int iStuScore = -1;
    int flag = 1;


    //打印菜单
    menu();
    while(flag) {
    printf("请输入指令\n");
    scanf("%d", &iOrder);
        switch (iOrder)
        {
        case 0:
            //todo退出程序
            flag = 0;
            break;
        case 1:
            //todo 尾添加一个学生信息
            printf("请输入学生姓名:");
            scanf("%s", arrStuName);
            printf("请输入学号:");
            scanf("%s", arrStuNum);
            printf("请输入学生分数:");
            scanf("%d", &iStuScore);
            AddStuMSG(arrStuNum, arrStuName, iStuScore);
            fflush(stdin);
            break;
        case 2:
            //todo 头添加一个学生信息
            printf("请输入学生姓名:");
            scanf("%s", arrStuName);
            printf("请输入学号:");
            scanf("%s", arrStuNum);
            printf("请输入学生分数:");
            scanf("%d", &iStuScore);
            AddStuMSGToLinkHead(arrStuNum, arrStuName, iStuScore);
            fflush(stdin);
            break;
        case 3:
        {                                   //在switch中添加临时变量需要加花括号
            //todo 指定位置添加学生信息
            STUNODE* pTemp = NULL;
            printf("请输入所插入位置之前的学号:");
            scanf("%s", arrStuNum);
            pTemp = FindStuByNum(arrStuNum);
            fflush(stdin);
            if (NULL != FindStuByNum(arrStuNum))
            {
                //todo 插入新学生信息结点
                printf("请输入学生姓名:");
                scanf("%s", arrStuName);
                printf("请输入学号:");
                scanf("%s", arrStuNum);
                printf("请输入学生分数:");
                scanf("%d", &iStuScore);
                InsertNode(pTemp, arrStuNum, arrStuName, iStuScore);


            }
            fflush(stdin);
            break;
        }
        case 4:
        {
            //todo 打印指定学生的信息
            STUNODE* pTemp = NULL;
            //输入一个学号
            printf("请输入需要查找学生的学号:");
            scanf("%s", arrStuNum);
            //查找
            pTemp = FindStuByNum(arrStuNum);
            //打印
            if (NULL != pTemp)
            {
                printf("姓名:%s,学号:%s,分数:%d\n", pTemp->arrStuName, pTemp->arrStuNum, pTemp -> iStuScore);
            }
            break;
        }
        case 5:
            //todo 修改指定学生的信息
        {
            int target = -1; //学号:1, 姓名 : 2,成绩:3.
            char strStuNum[20] = { 0 };
            char strFixedData[20] = {0};
            STUNODE* pTemp = NULL;
            printf("请输入想要修改学生的学号:");
            scanf("%s", strStuNum);
            pTemp = FindStuByNum(strStuNum);
            if (pTemp == NULL)
            {
                break;
            }
            else {
                printf("请输入你想要修改的数据(1:学生学号,2:学生姓名,3:学生成绩):");
                scanf("%d", &target);
                printf("请输入你想要修改后的数据:");
                scanf("%s", strFixedData);
                FixStuByNum(pTemp, target,strFixedData);
                printf("修改成功\n");
            }
        }
            break;
        case 6:
            //todo 保存学生信息到文件中
            SaveStuToFile();
            break;
        case 7:
            //todo 读取文件中的文件信息
            ReadStuFromFile();

            break;
        case 8:
        {
            //todo 删除指定学生信息
            STUNODE* pTemp=NULL;
            //输入一个学号
            printf("请输入要删除学生的学号:");
            scanf("%s", arrStuNum);
            //查找
            pTemp = FindStuByNum(arrStuNum);
            //删除这个节点
            if (NULL != pTemp)
            {
                //调用删除函数
                DeleteStuNode(pTemp);
            }
            
            break;
        }
        case 9:
            //todo 恢复删除学生的信息
            //清空链表
            FreeLinkData();
            g_pHead = NULL;
            g_pEnd = NULL;
            //恢复结点
            ReadStuFromFile();//从文件中恢复结点
            printf("恢复成功\n");
            break;
        case 10:
            //打印学生数据
            ShowStuData();
            break;
        case 11:
            //再次打印菜单
            menu();
            break;
        default:
            printf("无效指令!\n");
        }
    }
    //释放链表

    FreeLinkData();
    return 0;
}




void menu()
{
    printf("********************学生信息管理系统**********************\n");
    printf("*********************本系统操作如下***********************\n");
    printf("***           1.增加一个学生信息(尾添加)               ***\n");
    printf("***           2.增加一个学生信息(头添加)               ***\n");
    printf("***           3.指定位置添加学生信息                   ***\n");
    printf("***           4.打印指定学生信息(姓名,学号)         ***\n");
    printf("***           5.修改指定学生的信息                     ***\n");
    printf("***           6.保存学生的信息到文件中                 ***\n");
    printf("***           7.读取文件中的学生信息                   ***\n");
    printf("***           8.删除指定学生的信息                     ***\n");
    printf("***           9.恢复删除的学生的信息                   ***\n");
    printf("***           10.显示所有学生的信息                    ***\n");
    printf("***           11.再次打印菜单                          ***\n");
    printf("***           0.退出系统                               ***\n");
    printf("**********************************************************\n");
}


//do添加一个学生的信息
void AddStuMSG(char* arrStuNum, char* arrStuName, int iStuScore) //分数,学生名,学号 **数组做参数,其实是一个指针
{
    //第一步 检验参数的合法性
    if (NULL == arrStuNum || NULL == arrStuName || iStuScore < 0)
    {
        printf("学生信息输入错误\n");
        return;
    }

    //第二步 逻辑处理
    //1.创建一个结点
    STUNODE* pTemp = malloc(sizeof(STUNODE));
    //2.对结点内成员赋值
    //pTemp->arrStuNum=arrStuNum; 这种写法是错误的,因为传进来的参数是地址。
    strcpy(pTemp->arrStuNum, arrStuNum);
    strcpy(pTemp->arrStuName, arrStuName);
    pTemp->iStuScore = iStuScore;
    pTemp->pNext = NULL;
    //赋值完成

    //3.将结点接在链表上(**使用尾连接)
    if (NULL == g_pHead || NULL == g_pEnd) //添加的第一个结点
    {
        g_pHead = pTemp;
        g_pEnd = pTemp;
    }
    else //直接在尾巴添加
    {
        g_pEnd->pNext = pTemp; //链接结点
        g_pEnd = pTemp; //尾巴向后移动
    }
}

//do清空链表
void FreeLinkData()
{
    STUNODE* pTemp = g_pHead;
    while (g_pHead != NULL)
    {
        pTemp = g_pHead; //记录结点
        g_pHead = g_pHead->pNext; //头结点后移
        free(pTemp); //删除结点
    }
}

//do打印数据
void ShowStuData()
{
    STUNODE* pTemp = g_pHead;
    printf("学生姓名        学号        分数\n");
    while (pTemp != NULL) {
        printf("%-15s%-12s%-10d\n", pTemp->arrStuName, pTemp->arrStuNum, pTemp->iStuScore);
        pTemp = pTemp->pNext;
    }
}

//do链表头添加一个结点(头添加)
void AddStuMSGToLinkHead(char* arrStuNum, char* arrStuName, int iStuScore)
{
    STUNODE* pTemp = malloc(sizeof(STUNODE));
    //检测参数的合法性
    if (NULL == arrStuName || NULL==arrStuName || iStuScore < 0)
    {
        printf("学生信息输入错误\n");
        return;
    }

    strcpy(pTemp->arrStuNum, arrStuNum);
    strcpy(pTemp->arrStuName, arrStuName);
    pTemp->iStuScore = iStuScore;
    pTemp->pNext = NULL;

    
    if (NULL == g_pHead || NULL == g_pEnd)//链表为空的时候
    {
        g_pHead = pTemp;
        g_pEnd = pTemp;
    }
    else {
        pTemp->pNext = g_pHead;//新结点的下一个指向头
        g_pHead = pTemp;
    }
}


//do 查找指定学生信息
STUNODE* FindStuByNum(char* arrStuNum) 
{
    STUNODE* pTemp = g_pHead;
    if (NULL == arrStuNum)//检测输入
    {
        printf("学号输入错误\n");
        return NULL;
    }
    if (NULL == g_pHead || NULL == g_pEnd)//链表为空
    {
        printf("学号输入错误\n");
        return NULL;
    }
    else {//遍历链表
        while (pTemp != NULL)
        {
            if (0==strcmp(pTemp->arrStuNum, arrStuNum))
            {
                return pTemp;
            }
            pTemp = pTemp->pNext;
        }
    }
    printf("未查找到该生信息\n");
    return NULL;
}

//do 特定位置插入结点 
void InsertNode(STUNODE* pTemp, char* arrStuNum, char* arrStuName, int iStuScore)
{
    //创建结点
    STUNODE* pNewTemp = malloc(sizeof(STUNODE));
    //成员赋值
    strcpy(pNewTemp->arrStuNum, arrStuNum);
    strcpy(pNewTemp->arrStuName, arrStuName);
    pNewTemp->iStuScore = iStuScore;
    pNewTemp->pNext = NULL;    //赋值完成


    if (pTemp = g_pEnd)//判断是不是尾结点
    {
        g_pEnd->pNext = pNewTemp;
        g_pEnd = pNewTemp;
    }
    else
    {
        pNewTemp->pNext = pTemp->pNext;
        pTemp->pNext = pNewTemp;
    }

}

//do 删除指定学生信息
void DeleteStuNode(STUNODE* pNode)
{
    //只有一个结点
    if (g_pHead == g_pEnd)
    {
        free(g_pHead);
        g_pEnd = NULL;
        g_pHead = NULL;
        printf("信息删除成功!\n");
        return;
    }
    else if(g_pHead->pNext==g_pEnd)//两个结点
    {
        if (g_pHead == pNode)
        {
            free(g_pHead);
            g_pHead = g_pEnd;
            printf("信息删除成功!\n");
            return;
        }
        else {
            free(g_pEnd);
            g_pEnd = g_pHead;
            g_pHead->pNext = NULL;//防止指针仍指向原地址导致错误
            printf("信息删除成功!\n");
            return;
        }
    }
    else//常规情况(结点数>=3) 
    {
        STUNODE* pTemp = g_pHead;
        if (g_pHead == pNode)//判断头
        {
            pTemp = g_pHead;//记录头
            g_pHead = g_pHead->pNext;
            free(pTemp);
            pTemp=NULL;
            printf("信息删除成功!\n");
            return;
        }
        while(pTemp != NULL)
        {
            if (pTemp->pNext == pNode)//头结点为目标结点的情况在之前已经判断过,此处从第二个结点开始判断
            {
                //删除
                if (g_pEnd == pNode)//判断尾
                {
                    free(pNode);
                    pNode = NULL;
                    g_pEnd = pTemp;
                    printf("信息删除成功!\n");
                    return;
                }
                else {
                    //记录要删除的节点
                    STUNODE* p = pTemp->pNext;
                    //
                    pTemp->pNext = pNode->pNext;//连接
                    free(p);
                    p=NULL;
                    printf("信息删除成功!\n");
                    return;
                }
            }
            pTemp = pTemp->pNext;
        }
    }
}

//do 保存学生信息到文件中
void SaveStuToFile()
{
    STUNODE* pTemp = g_pHead;
    FILE* pFile = NULL;
    char strBuf[60] = { 0 };
    char strScore[10] = { 0 };

    //判断链表是否为空
    if (NULL == g_pHead)
    {
        printf("链表为空,未录入学生信息!\n");
        return;
    }
    //打开文件
    pFile = fopen("dat.dat", "wb+");//打开的文件地址,打开方式(此处为可读可写)
    if (NULL == pFile)
    {
        printf("文件打开失败\n");
        return;
    }
    //操作文件指针
    while (pTemp)//遍历链表
    {
        //学号赋值
        strcpy(strBuf, pTemp->arrStuNum);
        strcat(strBuf, ".");//分隔文件中的元素,便于查看和读取
        //姓名赋值
        strcat(strBuf, pTemp->arrStuName);//在字符串末尾连接
        strcat(strBuf, "."); 
        //分数赋值
        _itoa(pTemp->iStuScore, strScore,10);
        //组合字符串
        strcat(strBuf, strScore);

        fwrite(strBuf,1,strlen(strBuf),pFile);//程序中的字符串,目标数量,单个目标所占字节,指针
        fwrite("\r\n", 1, strlen("\r\n"), pFile);
        pTemp = pTemp->pNext;
    }
    //关闭文件
    fclose(pFile);

}

//do 读取文件中的文件信息
void ReadStuFromFile()
{
    FILE* pFile = fopen("dat.dat", "rb+");
    char strBuf[60] = { 0 };
    char strStuNum[20] = { 0 };
    char strStuName[20] = { 0 };
    char strStuScore[10] = { 0 };//不要忘记读入以后转化为整形

    if (NULL == pFile)
    {
        printf("文件打开失败\n");
        return;
    }
    //操作指针,读取文件
    while (NULL != fgets(strBuf, 60, pFile))//一次读取一行,参数:文件中内容存放的地方,字符数组大小,文件地址      注意EOF返回值
    {
        int i = 0;
        int iCount = 0;
        int j = 0;
        for (i = 0; strBuf[i] != '\r'; i++)//行写入
        {
            if (0 == iCount)//没有读到'.'
            {
                strStuNum[i] = strBuf[i];
                if('.'==strBuf[i])
                {
                    strStuNum[i] = '\0';
                    iCount++;
                }
            }
            else if (1 == iCount)//读到第一个'.'
            {
                strStuName[j] = strBuf[i];
                if('.' == strBuf[i])
                {
                    strStuName[j] = '\0';
                    iCount++;
                    j = 0;
                    continue;//跳过循环,防止运行下面的j++
                }
                j++;
            }
            else//读到第二个'.'
            {
                strStuScore[j] = strBuf[i];
                j++;
            }
        }
        //插入到链表
        AddStuMSG(strStuNum, strStuName, atoi(strStuScore));
    }

    fclose(pFile);
}

//do 修改指定学生信息(目标结点,目标修改数据,用于替换的数)
void FixStuByNum(STUNODE* pTemp, int target, char* strFixedData)
{
    if (target == 3) {
       pTemp->iStuScore = atoi(strFixedData);
    }
    else if (target == 2) {
        strcpy(pTemp->arrStuName, strFixedData);
    }
    else {
        strcpy(pTemp->arrStuNum, strFixedData);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值