【C语言】学生管理系统

  大家好,欢迎来到我的博客总结应用。在上一篇博客中,我写了有关结构体和内存操作函
数的总结,这些博客记录了我的学习、思考和经验。为了更好地总结和回顾这些内容,在此
篇博客中,我编写了”学生管理系统“来帮助我整理和应用上一篇博客的总结知识点。在这个
”学生管理系统“中,我列举了九条不同的标题和内容来进行说明,以下便是我的总结整理。

一、定义学生信息的结构体

添加必要的头文件和声明,之后定义学生信息结构体。

学生信息结构体中含有必要的学生id、学生姓名和学生成绩,除此之外,也可以自行添加一些其他信息,如学生家庭年龄,学生住址,学生班级,学生教师,学生所属学校等

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

// 学生信息结构体
typedef struct _Student {
    int id;
    float score;  /* 数据域 */
    char name[50];
    struct Student *next; /* 指针域 */ 
} Student;

int isExistId(Student **head, int id);
void freeMemory(Student *head);

void addStudent(Student **head);
void deleteStudent(Student **head);
void updateStudent(Student **head);
void printStudent(Student **head);
void searchStudent(Student **head);

可以将数据域和指针域分开来定义,使结构逻辑更加严整。

typedef struct _Student {
	int id;
	float score;
	char name[50];
} Student;

// 嵌套结构体
typedef struct _StuNode {
	Student stu;
	struct _Node *next;
} StuNode;

二、主函数逻辑

主函数主要负责输出学生管理系统的文字页面、选择对应的功能、暂停并清空控制台

int main()
{
    int choice;
    Student *head = NULL; // 学生链表头指针

    while (1)
    {
        // 暂停程序
        system("pause");
        // 清空控制台
        system("cls");

        printf("--------学生管理系统--------\n");
        printf("\t1. 添加学生信息\n");
        printf("\t2. 删除学生信息\n");
        printf("\t3. 修改学生信息\n");
        printf("\t4. 显示学生列表\n");
        printf("\t5. 查找学生信息\n");
        printf("\t0. 退出系统\n");
        printf("请选择操作:");

        // 输入非数字字符,清空输入缓冲区
        if (scanf("%d", &choice) != 1)
        {
            while (getchar() != '\n');
            printf("无效的操作,请重新选择。\n");
            continue;
        }

        // 当输入数字字符后,防止缓冲区中的字符影响自己的选择
        while (getchar() != '\n');
        switch (choice)
        {
        case 1:
            addStudent(&head); // 添加学生信息
            break;
        case 2:
            deleteStudent(&head); // 删除学生信息
            break;
        case 3:
            updateStudent(&head); // 更新学生信息
            break;
        case 4:
            printStudent(&head); // 打印学生信息
            break;
        case 5:
            searchStudent(&head); // 搜索学生信息
            break;
        case 0:
            printf("感谢使用学生管理系统,再见!\n");
            freeMemory(head); // 释放内存,防止内存泄漏
            exit(0);
        default:
            printf("无效操作,请重新选择。\n");
        }
    }

    return 0;
}

注意,学生管理系统是需要手动退出的一个页面,所以很多操作都是在一个循环里面。

  1. 输出学生管理系统的文字页面

    按照一定格式输出文字,将其美观排版后输出即可

    // 文字页面
    printf("--------学生管理系统--------\n");
    printf("\t1. 添加学生信息\n");
    printf("\t2. 删除学生信息\n");
    printf("\t3. 修改学生信息\n");
    printf("\t4. 显示学生列表\n");
    printf("\t5. 查找学生信息\n");
    printf("\t0. 退出系统\n");
    printf("请选择操作:");
    
  2. 选择对应的功能

    使用switch语句,每一种case对应一种功能,此外还需要一定的防御性编程,如选择时要求输入数字字符,消除输入数字字符的后面其他无关字符的影响

    // 输入非数字字符,清空输入缓冲区
    if (scanf("%d", &choice) != 1)
    {
    	while (getchar() != '\n');
    	printf("无效的操作,请重新选择。\n");
    	continue;
    }
    
    // 当输入数字字符后,防止缓冲区中的字符影响自己的选择
    while (getchar() != '\n');
    switch (choice)
    {
    	case 1:
    		addStudent(&head); // 添加学生信息
    		break;
    	case 2:
    		deleteStudent(&head); // 删除学生信息
    		break;
    	case 3:
    		updateStudent(&head); // 更新学生信息
    		break;
    	case 4:
    		printStudent(&head); // 打印学生信息
    		break;
    	case 5:
    		searchStudent(&head); // 搜索学生信息
    		break;
    	case 0:
    		printf("感谢使用学生管理系统,再见!\n");
    		freeMemory(head); // 释放内存,防止内存泄漏
    		exit(0);
    	default:
    		printf("无效操作,请重新选择。\n");
    }
    
    1. 暂停并清空控制台

      为了让输出界面和输出的结果更加直观,所以要求暂停程序观看,之后清空控制台以达到简洁直观的目的

      // 暂停程序
      system("pause");
      // 清空控制台
      system("cls");
      

三、添加学生信息

  1. 录入学生信息

    添加学生信息这一环节主要是创建一个结点,结点中含有填写完的信息,然后把这个结点放在链表之中。

    // 添加学生信息
    void addStudent(Student **head) {
    	int id;
        printf("请输入学生id: ");
    	scanf("%d", &id);
    
    	// 判断是否重复录取学生信息
    	if (IsExistId(head, id)) {
    		printf("已存在id为%d的学生信息!\n", id);
    		return;
    	}
    	
    	// 开辟空间,并填写信息
    	Student *newStudent = (Student *) malloc(sizeof(Student));
    	newStudent->next = NULL;
    
        char name[50];
        float score;
    	
        printf("请输入学生姓名: ");
        scanf("%s", name);
    
        printf("请输入学生分数: ");
        scanf("%f", &score);
    
        newStudent->id = id;
    
    	/* 注意字符串赋值的方式 */
        strcpy(newStudent->name, name);
        newStudent->score = score;
    
    	// 尾插法:将结点插入在链表之后
        if (*head == NULL) {
            *head = newStudent;
        } 
        
        else 
        {
            Student *temp = *head;
            while (temp->next != NULL) {
                temp = temp->next;
            }
            temp->next = newStudent;
        }
    }
    
  2. 插入结点的方法

    插入节点的两个方法:头插法和尾插法

    • 头插法:将结点放在头部,使之成为新的头结点

      // 头插法
      // 无论有没有头结点都可以
      newStudent->next = *head;
      *head = newStudent;
      
    • 尾插法:不断地将结点插在链表尾部

      // 尾插法:将结点插入在链表之后
      // 情况一,没有头结点
      if (*head == NULL) 
      { 
          *head = newStudent;
      } 
      
      // 情况二,有头结点
      else 
      {
          Student *temp = *head;
      		// 一直找到最后一个结点
          while (temp->next != NULL) {
              temp = temp->next;
          }
          temp->next = newStudent;
      }
      
  3. 避免重复录入学生信息

    为了不重复录入学生信息,定义一个IsExistId函数,该函数的实现就是遍历链表,判断链表中是否存在待录入学生的id,如果存在,返回1;否则,返回0。

    int IsExistId(Student *head, int id) {
    		while (head != NULL) {
    			if (head->id == id) {
    					return 1;
    			}
    		}
    		return 0;
    }
    

四、删除学生信息

  1. 删除学生信息

    这意味着将去除链表中指定学生信息的结点,然后释放内存。

    // 删除学生信息
    void deleteStudent(Student **head) {
        int id;
        Student *temp = *head;
    
        // 待删除结点的前一个结点,用于指向待删除结点的下一个结点
        Student *prev = NULL;  
    
        printf("请输入要删除的学生id: ");
        scanf("%d", &id);
    
        // 遍历链表,查找要删除的学生结点位置
        while (temp != NULL && temp->id != id) {
            prev = temp;
            temp = temp->next;
        }
    
    		// 说明链表为空,或者到了链表尾部,即没有找到指定学生id
        if (temp == NULL) {
            printf("未找到学生id为%d的记录。\n", id);
            return;
        }
    
        // 如果找到了要删除的学生,从链表中删除它
        else
        {
            if (prev == NULL) 
            {
                // 删除头节点
                *head = temp->next;
            } 
            
            else 
            {
                prev->next = temp->next;
            }
            
            free(temp);
            printf("已删除学生id为%d的记录。\n", id);
        }
    
    }
    
  2. 删除学生信息结点有两个位置区分

    • 头结点位置:删除头结点后,头结点的下一位即为头结点
    • 其他位置:待删除结点的前一位,它的下一位是待删除结点的下一位
    if (prev == NULL) 
    {
    	// 删除头节点
    	*head = temp->next;
    } 
    
    else 
    {
    	prev->next = temp->next;
    }
    
    free(temp);
    

五、修改学生信息

遍历链表,找到待修改信息的学生id即可修改学生信息

// 修改学生信息
void updateStudent(Student **head)
{
    int id;
    Student *temp = *head;

    printf("请输入要修改信息的学生id: ");
    scanf("%d", &id);

    while (temp != NULL && temp->id != id)
    {
        temp = temp->next;
    }

    // 要么链表为空,要么已经到链表尾部,这两种情况都是未找到id
    if (temp == NULL)
    {
        printf("未找到学生id为%d的记录。\n", id);
    }

    else
    {
        printf("请输入新的姓名和成绩:\n");
        scanf("%s %f", temp->name, &temp->score);
        printf("已更新学生id为%d的信息。\n", id);
    }
}

六、显示学生列表

遍历链表,将学生信息一个个打印出来。这个过程是按照链表的插入顺序进行打印输出的,还可以自己实现按照id大小排序进行输出,抑或着按照学生成绩大小排序进行输出。

// 打印学生信息
void printStudent(Student **head)
{
    if (*head == NULL)
    {
        printf("暂未录入学生信息\n");
        return;
    }

    printf("\n学生信息如下:\n");
    Student *temp = *head;
    while (temp != NULL)
    {
        printf("ID:%d,姓名:%s,成绩:%.2f\n", temp->id, temp->name, temp->score);
        temp = temp->next;
    }
}

七、查询学生信息

本质上还是遍历链表,查看是否存在指定id的人

void searchStudent(Student **head) {
    int id;
    Student *temp = *head;

    printf("输入待搜索学生的id: ");
    scanf("%d", &id);

    while(temp != NULL && temp->id != id) {
        temp = temp->next;
    }

    if (temp == NULL) {
        printf("查无此id:%d信息。", id);
    } 

    else 
    {
        printf("id: %d  name: %s  score: %.2f\n", id, temp->name, temp->score);
    }
}

八、退出程序

退出程序只需要在switch中添加一个选项即可,在这个选项中有exit。当然,退出程序前,要主动释放内存,避免内存泄漏。

以下这个函数也i将添加在含有exit选项中。

// 释放内存空间
void freeMemory(Student *head)
{
    Student *temp;
    while (head != NULL)
    {
        temp = head;
        head = head->next;
        free(temp);
    }
}

九、完整代码及补充

以上就是学生管理系统的大致代码,之后若是学习了文件管理相关的函数,还可以将文件导出保存,将其他的对应格式的学生信息文件导入进行管理。除了文件管理相关的函数,我们还可以将数据导入到数据库中,这些都是之后将会学习的知识。

  • 完整代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    // 学生信息结构体
    typedef struct Student
    {
        int id;
        float score; /* 数据域 */
        char name[50];
        struct Student *next; /* 指针域 */
    } Student;
    
    int isExistId(Student **head, int id);
    void freeMemory(Student *head);
    
    void addStudent(Student **head);
    void deleteStudent(Student **head);
    void updateStudent(Student **head);
    void printStudent(Student **head);
    void searchStudent(Student **head);
    
    int main()
    {
        int choice;
        Student *head = NULL; // 学生链表头指针
    
        while (1)
        {
            // 暂停程序
            system("pause");
            // 清空控制台
            system("cls");
    
            printf("--------学生管理系统--------\n");
            printf("\t1. 添加学生信息\n");
            printf("\t2. 删除学生信息\n");
            printf("\t3. 修改学生信息\n");
            printf("\t4. 显示学生列表\n");
            printf("\t5. 查找学生信息\n");
            printf("\t0. 退出系统\n");
            printf("请选择操作:");
    
            // 输入非数字字符,清空输入缓冲区
            if (scanf("%d", &choice) != 1)
            {
                while (getchar() != '\n')
                    ;
                printf("无效的操作,请重新选择。\n");
                continue;
            }
    
            // 当输入数字字符后,防止缓冲区中的字符影响自己的选择
            while (getchar() != '\n');
            switch (choice)
            {
            case 1:
                addStudent(&head); // 添加学生信息
                break;
            case 2:
                deleteStudent(&head); // 删除学生信息
                break;
            case 3:
                updateStudent(&head); // 更新学生信息
                break;
            case 4:
                printStudent(&head); // 打印学生信息
                break;
            case 5:
                searchStudent(&head); // 搜索学生信息
                break;
            case 0:
                printf("感谢使用学生管理系统,再见!\n");
                freeMemory(head); // 释放内存,防止内存泄漏
                exit(0);
            default:
                printf("无效操作,请重新选择。\n");
            }
        }
    
        return 0;
    }
    
    // 添加学生信息
    void addStudent(Student **head)
    {
        int id;
        printf("请输入学生id: ");
        scanf("%d", &id);
    
        // 判断是否重复录取学生信息
        if (isExistId(head, id))
        {
            printf("已存在id为%d的学生信息!\n", id);
            return;
        }
    
        // 开辟空间,并填写信息
        Student *newStudent = (Student *)malloc(sizeof(Student));
        newStudent->next = NULL;
    
        char name[50];
        float score;
    
        printf("请输入学生姓名: ");
        scanf("%s", name);
    
        printf("请输入学生分数: ");
        scanf("%f", &score);
    
        newStudent->id = id;
    
        /* 注意字符串赋值的方式 */
        strcpy(newStudent->name, name);
        newStudent->score = score;
    
        // 尾插法:将结点插入在链表之后
        if (*head == NULL)
        {
            *head = newStudent;
        }
    
        else
        {
            Student *temp = *head;
            while (temp->next != NULL)
            {
                temp = temp->next;
            }
            temp->next = newStudent;
        }
    }
    
    // 删除学生信息
    void deleteStudent(Student **head)
    {
        int id;
        Student *temp = *head;
    
        // 待删除结点的前一个结点,用于指向待删除结点的下一个结点
        Student *prev = NULL;
    
        printf("请输入要删除的学生id: ");
        scanf("%d", &id);
    
        // 遍历链表,查找要删除的学生结点位置
        while (temp != NULL && temp->id != id)
        {
            prev = temp;
            temp = temp->next;
        }
    
        // 如果找到了要删除的学生,从链表中删除它
        if (temp == NULL)
        {
            printf("未找到学生id为%d的记录。\n", id);
            return;
        }
    
        else
        {
            if (prev == NULL)
            {
                // 删除头节点
                *head = temp->next;
            }
    
            else
            {
                prev->next = temp->next;
            }
    
            free(temp);
            printf("已删除学生id为%d的记录。\n", id);
        }
    }
    
    // 修改学生信息
    void updateStudent(Student **head)
    {
        int id;
        Student *temp = *head;
    
        printf("请输入要修改信息的学生id: ");
        scanf("%d", &id);
    
        while (temp != NULL && temp->id != id)
        {
            temp = temp->next;
        }
    
        // 要么链表为空,要么已经到链表尾部,这两种情况都是未找到id
        if (temp == NULL)
        {
            printf("未找到学生id为%d的记录。\n", id);
        }
    
        else
        {
            printf("请输入新的姓名和成绩:\n");
            scanf("%s %f", temp->name, &temp->score);
            printf("已更新学生id为%d的信息。\n", id);
        }
    }
    
    // 打印学生信息
    void printStudent(Student **head)
    {
        if (*head == NULL)
        {
            printf("暂未录入学生信息\n");
            return;
        }
    
        printf("\n学生信息如下:\n");
        Student *temp = *head;
        while (temp != NULL)
        {
            printf("ID: %d\t 姓名: %s\t 成绩: %.2f\n", temp->id, temp->name, temp->score);
            temp = temp->next;
        }
    }
    
    // 释放内存空间
    void freeMemory(Student *head)
    {
        Student *temp;
        while (head != NULL)
        {
            temp = head;
            head = head->next;
            free(temp);
        }
    }
    
    // 判断链表中是否存在指定学生id
    int isExistId(Student **head, int id)
    {
        Student *temp = *head;
        while (temp != NULL)
        {
            if (temp->id == id)
            {
                return 1;
            }
            temp = temp->next;
        }
        return 0;
    }
    
    void searchStudent(Student **head) {
        int id;
        Student *temp = *head;
    
        printf("输入待搜索学生的id: ");
        scanf("%d", &id);
    
        while(temp != NULL && temp->id != id) {
            temp = temp->next;
        }
    
        if (temp == NULL) {
            printf("查无此id:%d信息。\n", id);
        } 
    
        else 
        {
            printf("id: %d  name: %s  score: %.2f\n", id, temp->name, temp->score);
        }
    }
    
  • 79
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值