学生管理系统(C 大一期末作业)

头文件

#ifndef __studentSystem_h__
#define __studentSystem_h__

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

//定义学生信息的结构体
typedef struct _student
{
    char name[20]; //姓名
    int age; // 年龄
    int ID; //学号
    int score; //分数

} Student;
//定义指向学生数据节点的指针结构体
typedef struct _node
{
    Student stu; //结构体中的结构体
    struct _node* pnext; // 指向下一个结构体的指针
} Node;

//定义头指针
Node* phead = NULL;

void welcome(void);
void inputStudent(void);
void printStudent(void);
void saveStudent(void);
void readStudent(void);
void countStudent(void);
Node* findStudent(void);
void modifyStudent(void);
void deleteStudent(void);


#endif

 

代码部分

 

#include"studentSystem.h"

int main(void)
{
    //做一个死循环
    while (1)
    {
        //调用了welcome函数
        welcome();
        //这里getch,只要输入一个字符就可以,并不需要按回车
        char ch = _getch();
        //根据不同的数字,来选则不同的程序
        switch (ch)
        {
            //录入学生信息
        case '1':
            inputStudent();
            break;
            //打印学生信息
        case '2':
            printStudent();
            break;
            //保存学生信息
        case '3':
            saveStudent();
            break;
            //读取学生信息
        case '4':
            readStudent();
            break;
            //统计所有学生人数
        case '5':
            countStudent();
            break;
            //查找学生人数
        case '6':
        {
            //函数的返回值是一个指针
            Node* p = findStudent();
            if (p == NULL)
            {
                printf("没有找到!\n");
            }
            else
            {
                system("cls"); // 清屏
                //如果返回值不为空,那么打印节点的信息
                printf("学号:\t%d\t姓名:\t%s\t年龄:\t%d\t成绩:\t%d\t\n", p->stu.ID, p->stu.name, p->stu.age, p->stu.score);
            }
            system("pause"); //暂停
            system("cls"); // 清屏

            break;
        }    //修改学生人数
        case '7':
            modifyStudent();
            break;
            //删除学生信息
        case '8':
            deleteStudent();
            break;
            //退出系统
        case '9':
        {
            printf("感谢适用本系统\n");
            system("pause"); //暂停
            system("cls"); // 清屏

            //这里就直接返回到了main函数
            return 0;
        }
        default:
            //如果用户输入的是乱七八糟的字符
        {
            printf("请重新输入\n");
            system("pause"); //暂停
            system("cls"); // 清屏
            break;
        }

        }
    }
    return 0;
}


void welcome()
{
    printf("************************************\n");
    printf("\t\t欢迎使用学生管理系统\t\t\n");
    printf("*************************************\n");
    printf("\t\t请选择功能列表\t\t\n");
    printf("***************************************\n");
    printf("*\t\t1、录入学生信息\t\t*\n");
    printf("*\t\t2、打印学生信息\t\t*\n");
    printf("*\t\t3、保存学生信息\t\t*\n");
    printf("*\t\t4、读取学生信息\t\t*\n");
    printf("*\t\t5、统计所有学生人数\t*\n");
    printf("*\t\t6、查找学生信息\t\t*\n");
    printf("*\t\t7、修改学生信息\t\t*\n");
    printf("*\t\t8、删除学生信息\t\t*\n");
    printf("*\t\t9、退出系统\t\t*\n");
    printf("***************************************\n");

}

void inputStudent()
{
    //创建一个新节点
    Node* pnewNode = (Node*)malloc(sizeof(Node));
    pnewNode->pnext = NULL; //将节点内部的指针设置为空

    //输入基本的信息,注意这里的scanf 是scanf_s,这是最新的表示方法。
    printf("请输入姓名:\n");
    scanf_s("%s", pnewNode->stu.name, 20); //输入姓名
    printf("请输入学生的年龄:\n");
    scanf_s("%d", &pnewNode->stu.age); //输入年龄,注意这里要输入&
    printf("请输入学生的学号:\n");
    scanf_s("%d", &pnewNode->stu.ID); //输入学生的序号
    printf("请输入学生的成绩:\n");
    scanf_s("%d", &pnewNode->stu.score); // 输入学生的成绩

    printf("学生信息录入成功\n");
    system("pause"); //暂停
    system("cls"); // 清屏





    //将头文件中的做为全局变量的头节点,连接到这个新创建的节点
    if (phead == NULL)
    {
        //将新节点连接到头结点
        phead = pnewNode;
    }
    else
    {
        //注意: 这里是不断的在头结点往前插入新的节点,同以前的方法不一样
        pnewNode->pnext = phead; //将新节点插在头结点的前面
        phead = pnewNode; //移动头结点到最前面

    }


}

//打印学生信息
void printStudent()
{
    //首先清楚前面的关于表格的基本信息
    system("cls");
    //打印头部的基本信息
    printf("***************************************\n");
    printf("*\t学号\t*\t姓名\t*\t年龄\t*\t成绩\t*\n");
    printf("***************************************\n");
    //遍历链表
    //首先定义一个新的指针,这个指针同头指针是一样的。
    Node* p = phead;
    //通过循环遍历链表
    while (p != NULL)
    {
        printf("*\t%d\t*\t%s\t*\t%d\t*\t%d\t*\n", p->stu.ID, p->stu.name, p->stu.age, p->stu.score);
        //将p指针往后挪一个位置,一直到最后一个指针位置,因为最后一个节点的包含的指针为空。
        p = p->pnext;

    }
    system("pause"); //暂停
    system("cls"); // 清屏


}

//保存学生信息
void saveStudent()
{

    //打开文件,注意当使用fopen_s时这么写
    FILE* fp;
    //定义了一个返回的int类型,当文件打开正确时,返回1,否则返回0
    int nu;
    //注意这里的fopen_s 里面的指正前面带有取地址符号,而在fopen函数中,则没有取地址符号
    nu = fopen_s(&fp, "C:\\users\\mike1\\desktop\\studentInformation.dat", "w");
    //在c语言中0代表成功,非0代表错误。
    if (nu == 1)
    {
        printf("打开文件失败!\n");
    }
    //创建一个与头结点一样的节点
    Node* pp = phead;
    //一直从头结点开始遍历,直到遍历完整个列表
    while (pp != NULL)
    {
        fwrite(&pp->stu, 1, sizeof(Student), fp);
        //向下移动头结点
        pp = pp->pnext;

    }

    //关闭文件
    fclose(fp);
    printf("保存文件成功!\n");
    system("pause"); //暂停
    system("cls"); // 清屏
}

void readStudent()
{
    //首先定义一个文件指针
    FILE* fp;
    int er;
    //这是打开文件的新的写法,er 返回0或者1
    //但是实际情况是,当文件打不开时,根本不会进行到if语句。
    er = fopen_s(&fp, "C:\\users\\mike1\\desktop\\studentInformation.dat", "rb");
    if (er == 1)
    {
        printf("打开文件失败!\n");
        return;
    }
    //读取文件,如果打开的没有到最后.
    //这是判断文件是否是空文件的另一种方式,先判断能不能正确读取所需要的字节,如果不可以,则不执行此循环
    //首先定义了一个节点
    Student stu1;
    //然后将内容先存放在前面的节点中,因为新节点是后定义的,所以如果直接将内容放在新节点,会出现,没有定义。
    while (fread(&stu1, 1, sizeof(Student), fp)) //里面的函数会返回读取的字节数
    {
        //   int c;
           //c = fgetc(fp);
           ////注意此时,当feof返回1时,表示错误,即文件是空文件,这和while的逻辑正好相反。
           //if (feof(fp))
           //{
           //    break;
           //}

           //创建一个新的节点,并且将读到的数据保存在新节点中,并由此创建一个链表
        Node* pp = (Node*)malloc(sizeof(Node));

        //将stu里面的内容复制给新创造的节点,后面表示复制的字节数
        memcpy(&pp->stu, &stu1, sizeof(Student));
        //将新节点的指针设置为空
        pp->pnext = NULL;

        //将头文件中的做为全局变量的头节点,连接到这个新创建的节点,这是在构建一个链表
        if (phead == NULL)
        {
            //将新节点连接到头结点
            phead = pp;
        }
        else
        {
            //注意: 这里是不断的在头结点往前插入新的节点,同以前的方法不一样
            pp->pnext = phead; //将新节点插在头结点的前面
            phead = pp; //移动头结点到最前面

        }


    }

    fclose(fp);
    printf("数据加载成功!\n");
    system("pause"); //暂停
    system("cls"); // 清屏
}

//统计所有学生人数
void countStudent()
{
    //这里用的是全局变量的头结点
    //初始化学生总数

    int count = 0;
    //一个与头结点一样的节点
    Node* pp = phead;
    //不断遍历节点
    while (pp != NULL)
    {

        count++;
        pp = pp->pnext;
    }
    //打印学生总人数
    printf("学生总人数为:%d\n", count);
    system("pause"); //暂停
    system("cls"); // 清屏

}

//查找学生信息
Node* findStudent()
{
    //定义基本变量
    char stuName[10];
    int stuNum;
    printf("请输入要查找的学生姓名:\n");
    //在输入字节时,用最细的scanf表示方法
    scanf_s("%s", stuName, 10);
    printf("请输入要查找到的学生的学号:\n");
    scanf_s("%d", &stuNum);
    //定义一个与头结点相同的指针
    Node* p = phead;
    //循环遍历节点
    while (p != NULL)
    {
        //strcmp 表示比较两个字符串,如果相同则返回0, 不相同则返回1
        if (stuNum == p->stu.age || 0 == strcmp(p->stu.name, stuName))
        {
            //返回这个节点
            return p;
        }
        p = p->pnext;
    }
    //此时p为空节点
    return p;
}

//修改学生信息
void modifyStudent()
{
    //定义基本的变量
    int nu;
    printf("请输入要修改的学生的学号:\n");
    scanf_s("%d", &nu);

    //定义一个与头结点相同的指针
    Node* p = phead;
    //循环遍历节点
    while (p != NULL)
    {
        //如果找到了这个节点
        if (nu == p->stu.ID)
        {

            printf("请输入要修改的 姓名 年龄 成绩\n");
            //实验证明可以这么连着写
            scanf_s("%s%d%d", p->stu.name, 20, &p->stu.age, &p->stu.score);

            printf("修改成功\n");
            break;

        }
        p = p->pnext;
    }

    if (p == NULL)
    {
        printf("没有找到此节点\n");
    }
    system("pause"); //暂停
    system("cls"); // 清屏

}

//删除头结点
void deleteStudent()
{
    //定义要删除的学号
    int num;
    printf("请输入要删除的学生的学号:\n");
    scanf_s("%d", &num);
    //如果要删除的节点是头结点
    //定义一个用于删除节点的指针
    Node* pd;
    if (phead->stu.ID == num)
    {
        pd = phead;
        //将头结点向后移动一个节点
        phead = phead->pnext;
        //删除头结点
        free(pd);
        //产生结果
        printf("删除成功\n");

        system("pause"); //暂停
        system("cls"); // 清屏

        return;
    }

    //如果要删除的节点不是头结点
    //重新定义一个节点,用于删除指定的节点,并且这里重复利用了上面定义的节点
    Node* pd1;
    //让pd去寻找需要的节点,这里头节点并不动
    pd = phead;
    //注意这个循环同样适用于两个节点的链表
    while (pd->pnext != NULL)
    {
        //如果找到了这个节点
        if (pd->pnext->stu.ID == num)
        {
            //这里利用到了pd1
            pd1 = pd->pnext;
            //将前后两个节点相连
            pd->pnext = pd->pnext->pnext;
            //删除目标节点
            free(pd1);
            //返回信息
            printf("节点删除成功\n");
            system("pause"); //暂停
            system("cls"); // 清屏
            return;

        }


        //将节点向后移动一个位置用于寻找
        pd = pd->pnext;
    }
    //如果没有找到目标节点
    if (pd->pnext == NULL)
    {
        //返回信息
        printf("没有找到要删除的节点\n");
        return;

    }

}

 

posted @ 2020-09-30 20:10  看星星的派大星  阅读(413)  评论(0编辑  收藏  举报