C语言实现学生信息管理系统

前言

由于疫情原因,最近只能呆在家里上网课,但实在不想听这个旅游管理的专业课(一直他喵的洗脑不要我们转专业DX)和英语(PS. 数学还是要听一听的),所以搞出来了这个东西……

连带摸鱼耗费了4天的时间,共760行左右的代码,实现了链表节点的增删查改功能。由于还没有系统学习过C语言,所以许多东西都是自己摸索加查资料得来的。可能十分臃肿,欢迎批评斧正。
PS. 在大神们看来这可能不算什么,但我还是十分兴奋的(=v=)。

代码详情

main.c

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

#include"head.h"

newStudent *studentNext;

int main(void)
{
    int modeCode;
    initStudentList();
    loadData(1);
    while(1)
    {
        welcome();
        printf("\nPlease select mode:");
        scanf("%1d%*c", &modeCode);
        switch(modeCode)
        {
        case 1:
            system("cls");
            addStudent();
            break;
        case 2:
            system("cls");
            selStudentMain();
            break;
        case 3:
            system("cls");
            delStudentMain();
            break;
        case 4:
            system("cls");
            changeStudentMain();
            break;
        case 5:
            system("cls");
            loadData(0);
            break;
        case 6:
            system("cls");
            updateData();
            break;
        case 0:
            free(studentNext);
            exit(0);
        }
    }
}

head.h

//当前加载学生数量
int studentNumber = 0;

//学生结构体
typedef struct students
{
    char id[11];
    char name[40];
    char sex[7];
    char age[4];
    struct students *next;
}newStudent;

//全局链表
extern newStudent *studentNext;

//欢迎词
void welcome();

//链表初始化
void initStudentList();

//更新学生数据
int updateData();

//加载学生数据
int loadData(int autoCode);

//添加学生
int addStudent();

//删除学生主菜单
int delStudentMain();
//通过学号删除学生
int delStudentById(char *id, int autoCode);
//通过姓名删除学生
int delStudentByName(char *name, int autoCode);
//删除当前所有数据
int delAllStudent();

//搜索学生主菜单
int selStudentMain();
//通过学号搜索学生
newStudent *selStudentById(char *id);
//通过姓名搜索学生
newStudent *selStudentByName(char *name);

//展示所有学生
int showStudent();

//更改学生数据主菜单
int changeStudentMain();
//更改学生数据
int changeStudent(newStudent *studentTmp);

//欢迎词
void welcome()
{
    system("cls");
    printf("========================================\n");
    printf("=   _____    _____   __  __    _____   =\n");
    printf("=  / ____|  / ____| |  \\/  |  / ____|  =\n");
    printf("= | |      | (___   | \\  / | | (___    =\n");
    printf("= | |       \\___ \\  | |\\/| |  \\___ \\   =\n");
    printf("= | |____   ____) | | |  | |  ____) |  =\n");
    printf("=  \\_____| |_____/  |_|  |_| |_____/   =\n");
    printf("========================================\n");
    printf("=====CUIT Student Management System=====\n");
    printf("========================================\n");
    printf("============Student Number:%d============\n", studentNumber);
    printf("========================================\n");
    printf("=============1.Add Student==============\n");
    printf("=============2.Sel Student==============\n");
    printf("=============3.Del Student==============\n");
    printf("=============4.Cha Student==============\n");
    printf("=============5.load   Data==============\n");
    printf("=============6.update Data==============\n");
    printf("=============0.Exit System==============\n");
    printf("========================================\n");
}

//链表初始化
void initStudentList()
{
    studentNext = (newStudent*)malloc(sizeof(newStudent));
    studentNext->next = NULL;
}

//更新学生数据
int updateData()
{
    FILE *fp = NULL;
    newStudent *studentTmp = NULL;

    if(studentNext->next != NULL)
    {
        if(remove("studentInfo.txt") == 0)
        {
            fp = fopen("studentInfo.txt", "w");

            studentTmp = studentNext->next;
            if(fp != NULL)
            {
                while(studentTmp != NULL)
                {
                    fprintf(fp, "|%s|%s|%s|%s|\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
                    studentTmp = studentTmp->next;
                }
                fclose(fp);
                printf("Updata completed\n");
                delAllStudent();
                loadData(1);
            }
            else
                printf("File open fail\n");
        }
        else
            printf("File delete fail\n");
    }
    else
    {
        fp = fopen("studentInfo.txt", "w");
        if(fgetc(fp) != EOF)
        {
            fclose(fp);
            remove("studentInfo.txt");
            fp = fopen("studentInfo.txt", "w");
            fclose(fp);
        }
        else
            printf("The current data is empty!\n");
    }
    system("pause");
    return 1;

}

//加载学生数据
int loadData(int autoCode)
{
    FILE *fp = NULL;
    char data[64] = {0};
    char *str = NULL;
    int i = 0;
    int number = 0;
    int judgeCode = 0;
    newStudent *studentTmp = NULL;

    fp = fopen("studentInfo.txt", "r+b");

    printf("Start load Data...\n");

    while(fscanf(fp, "%[^\n]%*c", data) != EOF)
    {
        studentTmp = (newStudent*)malloc(sizeof(newStudent));
        str = strtok(data, "|");
        for(i = 0; i < 4; i++)
        {
            if(str != NULL && str != EOF && str != '\0')
            {
                switch(i)
                {
                case 0:
                    if(selStudentById(str) == NULL)
                    {
                        strcpy(studentTmp->id, str);
                        break;
                    }
                    else
                    {
                        judgeCode = 1;
                        break;
                    }
                case 1:
                    strcpy(studentTmp->name, str);
                    break;
                case 2:
                    strcpy(studentTmp->sex, str);
                    break;
                case 3:
                    strcpy(studentTmp->age, str);
                    break;
                }
                if(judgeCode)
                    break;
                str = strtok(NULL, "|");
            }
        }
        if(!judgeCode)
        {
            studentTmp->next = studentNext->next;
            studentNext->next = studentTmp;
            studentNumber++;
            number++;
        }
    }
    printf("All done, loaded %d student...\n", number);
    fclose(fp);
    if(!autoCode)
        system("pause");
    return 1;
}

//添加学生
int addStudent()
{
    int sexCode = 0;        //性别状态码
    int judgeCode = 0;
    FILE *fp = NULL;        //文件变量
    char continueCode = 1;   //判断是否继续添加
    newStudent *studentSel = NULL;

    while(1)
    {
        fp = fopen("studentInfo.txt", "a");
        //分配新内存
        newStudent *studentTmp = (newStudent*)malloc(sizeof(newStudent));

        printf("Please enter the id of the new student:");
        scanf("%10[^\n]%*c", &studentTmp->id);

        if(studentNext->next != NULL)
        {
            studentSel = selStudentById(studentTmp->id);

            if(studentSel != NULL)
            {
                printf("The same ID has been entered!\n");
                printf("Students found:%-11s%-20s%-7s%-4s\n", studentSel->id, studentSel->name, studentSel->sex, studentSel->age);
                printf("Would you like to update this student's information?[Yes(1)/No(0)]:");
                scanf("%1d%*c", &judgeCode);
                if(judgeCode == 1)
                    delStudentById(studentTmp->id, 1);
                else
                    return -1;
            }
        }

        printf("Please enter the name of the new student:");
        scanf("%39[^\n]", &studentTmp->name);

        while(1)
        {
            printf("Please choose the sex of the new student[Male(1)/Female(0)]:");
            scanf("%1d%*c", &sexCode);
            if(sexCode == 1)
            {
                strcpy(studentTmp->sex ,"Male");
                break;
            }
            else if(sexCode == 0)
            {
                strcpy(studentTmp->sex, "Female");
                break;
            }
            else
                printf("Choose Error\n");
        }

        printf("Please enter the age of the new student:");
        scanf("%3[^\n]%*c", &studentTmp->age);

        if(fp != NULL)
        {
            fprintf(fp, "|%s|%s|%s|%s|\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
            fclose(fp);
        }else
        {
            printf("File open fail!\n");
        }

        studentTmp->next = studentNext->next;
        studentNext->next = studentTmp;

        studentNumber++;

        while(continueCode)
        {
            printf("Do you want to continue adding students?[Yes(1)/No(0)]:");
            scanf("%1d%*c", &continueCode);
            if(continueCode)
                system("cls");
                break;
        }

        if(!continueCode)
            break;
    }
    return 1;
}

//删除学生主菜单
int delStudentMain()
{
    int modeCode = 0;
    int judgeCode = 0;
    char id[11] = {0};
    char name[40] = {0};

    if(studentNext->next != NULL)
    {
        printf("What keywords do you want to delete data from?\n");
        printf(">Cancel(Other)\n");
        printf(">Student's id(1)\n");
        printf(">Student's name(2)\n");
        printf(">Delete all student(3)\n");
        printf("I choose to delete data by:");
        scanf("%1d%*c", &modeCode);

        switch(modeCode)
        {
        case 1:
            system("cls");
            printf("Please enter the ID of the student you want to delete:");
            scanf("%10s%*c", &id);
            delStudentById(id, 0);
            modeCode = 1;
            break;
        case 2:
            system("cls");
            printf("Please enter the name of the student you want to delete:");
            scanf("%[^\n]%*c", &name);
            delStudentByName(name, 0);
            modeCode = 1;
            break;
        case 3:
            system("cls");
            printf("Are you sure you want to delete all student data?[Yes(1)/No(0)]:");
            scanf("%1d%*c", &judgeCode);
            if(judgeCode)
                delAllStudent();
            modeCode = 1;
            break;
        default:
            modeCode = 0;
            break;
        }
    }
    else
    {
        printf("The current data is empty!\n");
        system("pause");
    }
    return(modeCode);
}

//通过学号删除学生
int delStudentById(char *id, int autoCode)
{
    int judgeCode = 1;
    newStudent *studentDel = NULL;
    newStudent *studentTmp = NULL;

    studentTmp = studentNext;
    studentDel = studentNext->next;
    if(studentNext->next != NULL)
    {
        while(judgeCode)
        {
            judgeCode = strncmp(studentDel->id, id, 10);
            if(!judgeCode)
            {
                printf("Removed student:%-11s%-20s%-7s%-4s\n", studentDel->id, studentDel->name, studentDel->sex, studentDel->age);
                studentTmp->next = studentDel->next;
                studentNumber--;
                printf("successfully deleted\n");
                break;
            }
            if(studentDel->next == NULL)
            {
                printf("No corresponding ID found!\n");
                break;
            }
            studentTmp = studentDel;
            studentDel = studentDel->next;
        }
        free(studentDel);
    }
    else
    {
        printf("The current data is empty!\n");
    }
    if(!autoCode)
        system("pause");
    return 1;
}

//通过姓名删除学生
int delStudentByName(char *name, int autoCode)
{
    int judgeCode = 1;
    newStudent *studentDel = NULL;
    newStudent *studentTmp = NULL;

    studentTmp = studentNext;
    studentDel = studentNext->next;
    if(studentNext->next != NULL)
    {
        while(judgeCode)
        {
            judgeCode = strcmp(studentDel->name, name);
            if(!judgeCode)
            {
                printf("Removed student:%-11s%-20s%-7s%-4s\n", studentDel->id, studentDel->name, studentDel->sex, studentDel->age);
                studentTmp->next = studentDel->next;
                studentNumber--;
                printf("successfully deleted\n");
                break;
            }
            if(studentDel->next == NULL)
            {
                printf("No corresponding name found!\n");
                break;
            }
            studentTmp = studentDel;
            studentDel = studentDel->next;
        }
        free(studentDel);
    }
    else
    {
        printf("The current data is empty!\n");
    }
    if(!autoCode)
        system("pause");
    return 1;
}

//删除当前所有数据
int delAllStudent()
{
    free(studentNext);
    initStudentList();
    studentNumber = 0;
    return 1;
}

//搜索学生主菜单
int selStudentMain()
{
    int modeCode = 0;
    char id[11] = {0};
    char name[40] = {0};
    newStudent *studentTmp = NULL;

    if(studentNext->next != NULL)
    {
        printf("What keywords do you want to select data from?\n");
        printf(">Cancel(Other)\n");
        printf(">Student's ID(1)\n");
        printf(">Student's name(2)\n");
        printf(">Show all student(3)\n");
        printf("I choose to select data by:");
        scanf("%1d%*c", &modeCode);

        switch(modeCode)
        {
        case 1:
            system("cls");
            printf("Please enter the ID of the student you want to select:");
            scanf("%10[^\n]%*c", &id);
            studentTmp = selStudentById(id);
            if(studentTmp != NULL)
                printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
            else
                printf("No corresponding ID found!\n");
            system("pause");
            modeCode = 1;
            break;
        case 2:
            system("cls");
            printf("Please enter the name of the student you want to select:");
            scanf("%[^\n]%*c", &name);
            studentTmp = selStudentByName(name);
            if(studentTmp != NULL)
                printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
            else
                printf("No corresponding ID found!\n");
            system("pause");
            modeCode = 1;
            break;
        case 3:
            showStudent();
            break;
        default:
            modeCode = 0;
            break;
        }
    }
    else
    {
        printf("The current data is empty!\n");
        system("pause");
    }
    return(modeCode);
}

//通过学号搜索学生
newStudent *selStudentById(char *id)
{
    int judgeCode = 1;
    newStudent *studentTmp = NULL;

    if(studentNext->next != NULL)
    {
        studentTmp = studentNext->next;
        while(judgeCode)
        {
            judgeCode = strncmp(studentTmp->id, id, 10);
            if(judgeCode)
                studentTmp = studentTmp->next;
            if(studentTmp == NULL)
                judgeCode = 0;
        }
    }
    else
    {
        printf("The current data is empty!\n");
    }
    return studentTmp;
}

//通过姓名搜索学生
newStudent *selStudentByName(char *name)
{
    int judgeCode = 1;
    newStudent *studentTmp = NULL;

    if(studentNext->next != NULL)
    {
        studentTmp = studentNext->next;
        while(judgeCode)
        {
            judgeCode = strcmp(studentTmp->name, name);
            if(judgeCode)
                studentTmp = studentTmp->next;
            if(studentTmp == NULL)
                judgeCode = 0;
        }
    }
    else
    {
        printf("The current data is empty!\n");
    }
    return studentTmp;
}

//展示所有学生
int showStudent()
{
    newStudent *studentNow;

    if(studentNext->next != NULL)
    {
        studentNow = studentNext->next;
        while(studentNow != NULL)
        {
            printf("%-11s%-20s%-7s%-4s\n", studentNow->id, studentNow->name, studentNow->sex, studentNow->age);
            studentNow = studentNow->next;
        }
        printf("All done...\n");
    }
    else
    {
        printf("The current data is empty!\n");
    }
    system("pause");
    return 1;
}

//更改学生数据主菜单
int changeStudentMain()
{
    int modeCode = 0;
    char id[11] = {0};
    char name[40] = {0};
    newStudent *studentTmp = NULL;

    if(studentNext->next != NULL)
    {
        printf("What keywords do you want to select data from?\n");
        printf(">Cancel(Other)\n");
        printf(">Student's ID(1)\n");
        printf(">Student's name(2)\n");
        printf("I choose to select data by:");
        scanf("%1d%*c", &modeCode);

        switch(modeCode)
        {
        case 1:
            system("cls");
            printf("Please enter the ID of the student you want to select:");
            scanf("%10[^\n]%*c", &id);
            studentTmp = selStudentById(id);
            if(studentTmp != NULL)
            {
                printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
                changeStudent(studentTmp);
            }
            else
                printf("No corresponding ID found!\n");
            system("pause");
            modeCode = 1;
            break;
        case 2:
            system("cls");
            printf("Please enter the name of the student you want to select:");
            scanf("%[^\n]%*c", &name);
            studentTmp = selStudentByName(name);
            if(studentTmp != NULL)
            {
                printf("Students found:%-11s%-20s%-7s%-4s\n", studentTmp->id, studentTmp->name, studentTmp->sex, studentTmp->age);
                changeStudent(studentTmp);
            }
            else
                printf("No corresponding ID found!\n");
            system("pause");
            modeCode = 1;
            break;
        default:
            modeCode = 0;
            break;
        }
    }
    else
    {
        printf("The current data is empty!\n");
        system("pause");
    }

    return 1;
}

//更改学生数据
int changeStudent(newStudent *studentTmp)
{
    int sexCode = 0;

    if(studentNext->next != NULL)
    {
        printf("Please enter the id of the new student:");
        scanf("%10[^\n]%*c", &studentTmp->id);

        printf("Please enter the name of the new student:");
        scanf("%39[^\n]%*c", &studentTmp->name);

        while(1)
        {
            printf("Please choose the sex of the new student[Male(1)/Female(0)]:");
            scanf("%1d%*c", &sexCode);
            if(sexCode == 1)
            {
                strcpy(studentTmp->sex ,"Male");
                break;
            }
            else if(sexCode == 0)
            {
                strcpy(studentTmp->sex, "Female");
                break;
            }
            else
                printf("Choose Error\n");
        }

        printf("Please enter the age of the new student:");
        scanf("%3[^\n]%*c", &studentTmp->age);
    }
    else
    {
        printf("The current data is empty!\n");
        system("pause");
    }
    return 1;
}

一些我想要说的点

scanf读取空格以及缓冲区对scanf的影响

最开始的时候,我希望通过:

char str_1[11] = {0};
char str_2[11] = {0};

scanf("%10s", &str_1);
scanf("%10s", &str_2);

的方式来获取字符串,但我发现上例是无法读取空格的。而且,第二个scanf函数被跳过了。

关于第一个问题,稍微了解一点CTF知识的都知道,这里肯定不能使用gets()函数,因为他不安全。不过,我们可以使用gets_s()函数替换他。不过因为我喜欢搞事XD,所以我倔强地想要用scanf()函数(雾);还有一方面,虽然我没有上过C语言课,但我觉得像gets_s()scanf_s()这种函数应该不会讲的吧(,所以我打算用初学者的常用函数来实现。

而第二个问题我则完全没有头绪…

后来在一位师傅和搜集来的资料的帮助下。谜题,解开了。
师傅给我了一个这样的写法:

char str_1[11] = {0};
char str_2[11] = {0};

//这个是师傅给的写法
//scanf("%[^\n]%*c", &str_1);
//scanf("%[^\n]%*c", &str_2);

//我改进了一下(
scanf("%10[^\n]%*c", &str_1);
scanf("%10[^\n]%*c", &str_2);

详细资料:https://blog.csdn.net/q_l_s/article/details/22572777

首先,第一个问题。采取%10[^\n]%*c的写法需要分开来讲:

{%10[^\n]}
    {10}:读入10个字符
    {[^\n}:读入回车符前(不含回车符)的所有字符
{%*c}:忽略后面的字符

可以查看上面的详细资料,资料就不展开了

第二个问题的资料:https://blog.csdn.net/hhhhhyyyyy8/article/details/80917713
简单来说,就是前一个scanf把这次读取的回车符留在了缓冲区里,第二个scanf来读取缓冲区时便会读入这个回车导致第二个scanf被跳过。

整体架构(结构?)

由于我没有学过软件工程之类的课程,所以这里的用词可能不太准确。

|-主函数
|----|-次函数-|-功能函数
     |        |-功能函数
     |          |...
     |
     |-次函数-|...
    ...

上面的结构打的有点混乱,简单来说就是每个功能有自己独立的主函数,由这个函数来调用功能函数。比如查询学生数据,有一个进行数据输入的主函数,然后将收集的信息加载到功能函数中。

这次整体代码的架构很失败(PS. 最开始压根没有思考到架构这一码事,在慢慢码的过程中才发现架构很重要),有许多代码其实可以用函数封装重复使用。在早期还在一些功能上的函数里面加入了数据输入……下次需要注意。

后言

emmmm总之就先这么多吧……以后来温故知新
PS. 估计以后不想看见这坨屎山(确信

Comments