C语言——简单双链表学生成绩管理系统(详细讲解)

题目要求:链表A,每个节点存放一个新的链表B1,B2,B3,B4,B5的头结点。 场景:一个年级,相当链表A 该年级5个班,每个班5个人,相当于链表B1–B5 做一个学生成绩管理系统 学生成绩有语文 数学 英语 功能: 录入成绩 找三科总分的最高分 最低分 算出平均分

场景:一个年级,相当链表A
该年级5个班,每个班5个人,相当于链表B1–B5
做一个学生成绩管理系统
学生成绩有语文 数学 英语
功能: 录入成绩 找三科总分的最高分 最低分 算出平均分)

废话不多说,先给出完整的代码:

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

// 定义学生结构体,用于存储学生的信息
struct Student {
    int xuehao;         // 学号
    int chinese;        // 语文成绩
    int math;           // 数学成绩
    int english;        // 英语成绩
    double sum;         // 总分
    double average;     // 平均分
    struct Student *next; // 下一个学生节点指针
};

// 定义班级结构体,用于存储班级的信息 
struct Class {
    struct Student *stuhead; // 班级内学生链表的头指针
    int classnum; // 班级号
    struct Class *next; // 下一个班级节点指针
};

// 在学生链表头部插入新学生节点
struct Student* insertStuMesage(struct Student *head, struct Student *new) {
    if (head == NULL) {
        head = new;  // 如果链表为空,则直接插入作为第一个节点
    } else {
        new->next = head;  // 否则将新节点插入到链表头部
        head = new;
    }
    return head;
}

// 动态创建学生链表
struct Student* createStudent(struct Student *head, int stunum, int classnum) {
    int i;
    int num = stunum;
    double sum;
    double average;
    struct Student *new;
    for (i = 0; i < stunum; i++) {
        new = (struct Student*)malloc(sizeof(struct Student)); // 分配内存以存储新的学生节点
		printf("\n*************************************************\n");
        printf("请输入%d班第%d个学生的学号:\n", classnum, num);
        scanf("%d", &(new->xuehao));  // 输入学生信息
        printf("请输入第%d个学生的语文成绩:\n", num);
        scanf("%d", &(new->chinese));
        printf("请输入第%d个学生的数学成绩:\n", num);
        scanf("%d", &(new->math));
        printf("请输入第%d个学生的英语成绩:\n", num);
		printf("*************************************************\n");
        scanf("%d", &(new->english));
        sum = new->chinese + new->math + new->english; // 计算总分和平均分
        new->sum = sum;
        average = sum / 3;
        new->average = average;
        num--;
        head = insertStuMesage(head, new); // 将新学生节点插入到学生链表
    }
    return head;
}

// 在班级链表头部插入新班级节点
struct Class* insertClaMesage(struct Class *head, struct Class *new) {
    if (head == NULL) {
        head = new;  // 如果链表为空,则直接插入作为第一个节点
    } else {
        new->next = head;  // 否则将新节点插入到链表头部
        head = new;
    }
    return head;
}

// 动态创建班级链表
struct Class* creatClass(struct Class *head, int classnum, int stunum) {
    struct Class *new = NULL;
    struct Student *stuHead;
    int num = classnum;
    int i;
    for (i = 0; i < classnum; i++) {
        new = (struct Class*)malloc(sizeof(struct Class)); // 分配内存以存储新的班级节点
        new->classnum = num;
        stuHead = createStudent(stuHead, stunum, num); // 创建该班级的学生链表
        new->stuhead = stuHead;
        num--;
        head = insertClaMesage(head, new); // 将新班级节点插入到班级链表
    }
    return head;
}

// 打印学生信息
void printMessage(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;

    int k = stunum; 
    int i = 0;
    while (i < classnum) {
        p2 = p1->stuhead;
        while (p2 != NULL && k > 0){
			printf("\n*******************************\n");
            printf("%d班第%d个学生的学号:%d\n", p1->classnum, k, p2->xuehao);
            printf("语文成绩为:%d\n", p2->chinese);
            printf("数学成绩为:%d\n", p2->math);
            printf("英语成绩为:%d\n", p2->english);
            printf("总分为:    %lf\n", p2->sum);
            printf("平均分为:  %lf\n", p2->average);
            p2 = p2->next;
            k--;
        }
        k = stunum;
        p1 = p1->next;
        i++;
    }
}

// 获取学生总分最大值
int getMax(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;
    p2 = p1->stuhead;
    int i = 0;
    int j = 0;
    int max = 0;
    while (i < classnum) {
        while (j < stunum * classnum) {
            if (max < p2->sum) {
                max = p2->sum;  // 更新最高总分
            }
            p2 = p2->next;
            j++;
        }
        p1 = p1->next;
        i++;
    }
    printf("\n**************************\n");
    printf("最高总分为:%d\n", max);
    printf("**************************\n");
}

// 获取学生总分最小值
int getMin(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;

    int i = 0;
    int j = 0;
    int min = 10000;  // 初始设定一个较大值
    p2 = p1->stuhead;
    while (i < classnum) {
        while (j < stunum * classnum) {
            if (min > p2->sum) {
                min = p2->sum;  // 更新最低总
            min = p2->sum;  // 更新最低总分
            }
            p2 = p2->next;
            j++;
        }
        p1 = p1->next;
        i++;
    }
    printf("**************************\n");
    printf("最低总分为:%d\n", min);
    printf("**************************\n");
}

// 获取学生总分平均值
float getAvge(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;

    int i = 0;
    int j = 0;
    double sum = 0;
    double average;
    p2 = p1->stuhead;
    while (i < classnum) {
        while (j < stunum * classnum) {
            sum = sum + p2->sum;  // 累计总分
            p2 = p2->next;
            j++;
        }
        p1 = p1->next;
        i++;
    }
    average = sum / (stunum * classnum); // 计算平均总分
    printf("**************************\n");
    printf("年级平均分为:%lf\n", average);
    printf("**************************\n");
}

void checkPassword()//开机密码
{
	int n = 0; // 用于记录尝试登录的次数
	int flag = 1; // 标志变量,此处暂未使用
	char password[7] = {'l', 'i', 'e', '2', '5', '5', '\0'}; // 预设的正确密码
	char userpassword[7]; // 用户输入的密码,最多支持6位密码字符
	printf("***************《请输入你的密码,你一共有三次机会!!!》**************\n");
	
	while (n < 3)
	{
		if(n != 0){
			printf("***********《密码错误,请输入你的密码》你现在还有%d机会!!!***********\n", 3 - n);
		}
		scanf("%s", userpassword); // 获取用户输入的密码
		if (strcmp(userpassword, password) == 0){ // 比较用户输入的密码与预设密码是否一致
			printf("密码正确,登录成功!!!\n");
			return; // 密码正确,登录成功,退出函数
		}
		n++; // 增加尝试登录次数
		
	}
	printf("密码错误,登录失败,滚蛋!!!\n");
	
	exit(0); // 登录失败,尝试次数达到上限,退出程序
}

int main() {
	
	checkPassword();//开机密码
	printf("\n*******************************\n");
    printf("欢迎使用学生成绩管理系统!!!\n");
	printf("*******************************\n");
	
    int a; // 班级个数
    int b; // 学生个数
    struct Class *head;
	
    printf("请输入班级个数:\n");
    scanf("%d", &a);
    printf("请输入学生个数:\n");
    scanf("%d", &b);
    head = creatClass(head, a, b); // 创建班级链表
    printMessage(head, a, b);      // 打印学生信息

    getMax(head, a, b); // 获取并打印最高分
    getMin(head, a,b ); // 获取并打印最低分
    getAvge(head, a, b); // 获取并打印平均分

    system("pause");
	
    return 0;
}

1. 头文件和结构体定义

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

// 定义学生结构体,用于存储学生的信息
struct Student {
    int xuehao;            // 学号
    int chinese;           // 语文成绩
    int math;              // 数学成绩
    int english;           // 英语成绩
    double sum;            // 总分
    double average;        // 平均分
    struct Student *next;  // 下一个学生节点指针
};

// 定义班级结构体,用于存储班级的信息 
struct Class {
    struct Student *stuhead; // 班级内学生链表的头指针
    int classnum; // 班级号
    struct Class *next; // 下一个班级节点指针
};

定义了两个结构体,struct Student 用于存储学生的信息,包括学号、语文成绩、数学成绩、英语成绩、总分和平均分,以及一个指向下一个学生节点的指针。struct Clas 用于存储班级信息,包括班级号和下一个班级节点的指针。

2. 第一个函数:insertStuMesage

// 在学生链表头部插入新学生节点
struct Student* insertStuMesage(struct Student *head, struct Student *new) {
    if (head == NULL) {
        head = new;  // 如果链表为空,则直接插入作为第一个节点
    } else {
        new->next = head;  // 否则将新节点插入到链表头部
        head = new;
    }
    return head;
}

这个函数用于将一个新的学生节点插入到学生链表的头部。这个函数有两个参数,一个是链表的头指针 head,另一个是要插入的新节点 new

  • 如果链表为空(head == NULL),则将新节点直接作为第一个节点。
  • 如果链表不为空,它会将新节点插入到链表的头部,即将新节点的 next 指针指向原链表的头节点,并将 head 指针指向新节点。
  • 最后,它返回插入后的链表头指针 head

3. 第二个函数:createStudent

// 动态创建学生链表
struct Student* createStudent(struct Student *head, int stunum, int classnum) {
    int i;
    int num = stunum;
    double sum;
    double average;
    struct Student *new;
    for (i = 0; i < stunum; i++) {
        new = (struct Student*)malloc(sizeof(struct Student)); // 分配内存以存储新的学生节点
        // ...
        sum = new->chinese + new->math + new->english; // 计算总分和平均分
        new->sum = sum;
        average = sum / 3;
        new->average = average;
        num--;
        head = insertStuMesage(head, new); // 将新学生节点插入到学生链表
    }
    return head;
}

这个函数用于动态创建学生链表,根据指定的学生数量 stunum 和班级号 classnum。这个函数的三个参数为:学生链表的头指针 head,学生数量,以及班级号。

  • 在循环中,它为每个学生分配内存以创建一个新的学生节点。
  • 然后,它要求用户输入学生的信息,包括学号、语文、数学和英语成绩。
  • 计算总分和平均分。
  • 最后,将新的学生节点插入到学生链表,使用了上面定义的 insertStuMesage 函数。

4. 第三个函数:insertClaMesage

// 在班级链表头部插入新班级节点
struct Class* insertClaMesage(struct Class *head, struct Class *new) {
    if (head == NULL) {
        head = new;  // 如果链表为空,则直接插入作为第一个节点
    } else {
        new->next = head;  // 否则将新节点插入到链表头部
        head = new;
    }
    return head;
}

这个函数类似于 insertStuMesage,但是它是用于在班级链表的头部插入新的班级节点。这个函数的参数为:班级链表的头指针 head 和一个新的班级节点 new

  • 如果班级链表为空,它将新节点直接作为第一个节点。
  • 如果班级链表不为空,它将新节点插入到链表的头部,更新 head 指针。

5. 第四个函数:creatClass

// 动态创建班级链表
struct Class* creatClass(struct Class *head, int classnum, int stunum) {
    struct Class *new = NULL;
    struct Student *stuHead;
    int num = classnum;
    int i;
    for (i = 0; i < classnum; i++){
        new = (struct Class*)malloc(sizeof(struct Class)); // 分配内存以存储新的班级节点
        new->classnum = num;
        stuHead = createStudent(stuHead, stunum, num); // 创建该班级的学生链表
        new->stuhead = stuHead;
        num--;
        head = insertClaMesage(head, new); // 将新班级节点插入到班级链表
    }
    return head;
}

这个函数用于动态创建班级链表,根据指定的班级数量 classnum 和学生数量 stunum。这个函数的参数为:班级链表的头指针 head、班级数量和学生数量。

  • 在循环中,它为每个班级分配内存以创建一个新的班级节点。

  • 为新班级节点设置班级号 classnum

  • 调用 createStudent 函数创建该班级的学生链表,然后将学生链表的头指针赋给 new->stuhead

  • 更新班级号,然后使用 insertClaMesage 函数将新的班级节点插入到班级链表,更新 head 指针。

6. 打印学生信息的函数:printMessage

// 打印学生信息
void printMessage(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;

    int k = stunum; 
    int i = 0;
    
    while (i < classnum) {
        p2 = p1->stuhead;
        int m = 1;
        while (p2 != NULL && k > 0){
            // 打印学生信息,包括学号、成绩、总分和平均分
            p2 = p2->next;
            m++;
            k--;
        }
        k = stunum; 
        p1 = p1->next;
        i++;
    }
}

这个函数用于打印学生的信息,包括学号、语文、数学、英语成绩、总分和平均分。函数参数为:班级链表的头指针 head、班级数量 classnum 和学生数量 stunum

  • 定义了两个指针,p1 用于遍历班级链表,p2 用于遍历学生链表。
  • 使用循环遍历每个班级,并在每个班级内遍历每个学生。
  • 打印每个学生的信息,包括学号、成绩、总分和平均分。

7. 获取最高分的函数:getMax

// 获取学生总分最大值
int getMax(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;
    p2 = p1->stuhead;
    int i = 0;
    int j = 0;
    int max = 0;
    while (i < classnum) {
        while (j < stunum * classnum) {
            if (max < p2->sum) {
                max = p2->sum;  // 更新最高总分
            }
            p2 = p2->next;
            j++;
        }
        p1 = p1->next;
        i++;
    }
    printf("最高总分为:%d\n", max);
}

这个函数用于获取并打印学生总分的最大值。函数参数为:班级链表的头指针 head、班级数量 classnum 和学生数量 stunum

  • 定义了两个指针,p1 用于遍历班级链表,p2 用于遍历学生链表。
  • 使用循环遍历每个班级,并在每个班级内遍历每个学生。
  • 检查每个学生的总分,如果找到更高的总分,更新 max 变量。
  • 最后,打印最高总分。

8. 获取最低分的函数:getMin

// 获取学生总分最小值
int getMin(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;

    int i = 0;
    int j = 0;
    int min = 10000;  // 初始设定一个较大值
    p2 = p1->stuhead;
    while (i < classnum) {
        while (j < stunum * classnum) {
            if (min > p2->sum) {
                min = p2->sum;  // 更新最低总分
            }
            p2 = p2->next;
            j++;
        }
        p1 = p1->next;
        i++;
    }
    printf("最低总分为:%d\n", min);
}

这个函数用于获取并打印学生总分的最小值。它接受班级链表的头指针 head、班级数量 classnum 和学生数量 stunum 作为参数。

  • 类似于 getMax 函数,定义了两个指针 p1p2 用于遍历班级和学生链表。
  • 使用循环遍历每个班级和学生。
  • 检查每个学生的总分,如果找到更低的总分,更新 min 变量。
  • 最后,打印最低总分。

9. 获取平均分的函数:getAvge

// 获取学生总分平均值
float getAvge(struct Class *head, int classnum, int stunum) {
    struct Class *p1 = head;
    struct Student *p2 = NULL;

    int i = 0;
    int j = 0;
    double sum = 0;
    double average;
    p2 = p1->stuhead;
    while (i < classnum) {
        while (j < stunum * classnum) {
            sum = sum + p2->sum;  // 累计总分
            p2 = p2->next;
            j++;
        }
        p1 = p1->next;
        i++;
    }
    average = sum / (stunum * classnum); // 计算平均总分
    printf("年级平均分为:%lf\n", average);
}

这个函数用于获取并打印学生总分的平均值。它接受班级链表的头指针 head、班级数量 classnum 和学生数量 stunum 作为参数。

  • 同样,定义了两个指针 p1p2 用于遍历班级和学生链表。

  • 使用循环遍历每个班级和学生。

  • 累计每个学生的总分到 sum 变量中。

  • 最后,计算平均总分,将 sum 除以学生总数,然后打印年级的平均分。

10. 开机密码检查函数:checkPassword

void checkPassword() {
    int n = 0; // 用于记录尝试登录的次数
    char password[7] = {'l', 'i', 'e', '2', '5', '5', '\0'}; // 预设的正确密码
    char userpassword[7]; // 用户输入的密码,最多支持6位密码字符

    printf("请输入你的密码,你一共有三次机会!!!\n");
    while (n < 3) {
        if (n != 0) {
            printf("密码错误,请输入你的密码。你现在还有 %d 机会!!!\n", 3 - n);
        }
        scanf("%s", userpassword); // 获取用户输入的密码
        if (strcmp(userpassword, password) == 0) {
            printf("密码正确,登录成功!!!\n");
            return; // 密码正确,登录成功,退出函数
        }
        n++; // 增加尝试登录次数
    }
    printf("密码错误,登录失败,滚蛋!!!\n");
    exit(0); // 登录失败,尝试次数达到上限,退出程序
}

这个函数用于开机密码检查。它会要求用户输入密码,并在最多三次尝试后决定是否允许用户继续使用程序。预设的正确密码是 'lie255'

  • 使用 n 记录尝试登录的次数,如果密码错误三次,则退出程序。
  • 用户输入密码,并使用 strcmp 函数与正确密码比较。
  • 如果密码正确,打印登录成功的消息,然后返回。
  • 如果密码错误,增加尝试登录的次数,然后继续循环,最多三次。

11. 主函数:main

int main() {
    checkPassword(); // 开机密码
    int a; // 班级个数
    int b; // 学生个数
    struct Class *head;

    printf("请输入班级个数:\n");
    scanf("%d", &a);
    printf("请输入学生个数:\n");
    scanf("%d", &b);

    head = creatClass(head, a, b); // 创建班级链表
    printMessage(head, a, b);      // 打印学生信息

    getMax(head, a, b);  // 获取并打印最高分
    getMin(head, a, b);  // 获取并打印最低分
    getAvge(head, a, b); // 获取并打印平均分

    system("pause");
    return 0;
}

这是主函数,它调用其他函数来实现学生成绩管理系统的功能。

  • 首先,调用 checkPassword 函数进行开机密码验证。
  • 然后,要求用户输入班级个数和学生个数。
  • 创建一个班级链表并存储在 head 中,然后调用 printMessage 函数打印学生信息。
  • 使用 getMax 函数获取并打印最高分。
  • 使用 getMin 函数获取并打印最低分。
  • 使用 getAvge 函数获取并打印平均分。
  • 最后,使用 system("pause") 以等待用户按下任意键继续,然后返回 0 表示程序结束。

这个主函数将各个功能组合在一起,使整个学生成绩管理系统运行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值