c入门第十八篇——支持学生数的动态增长(链表,指针的典型应用)

数组最大的问题,就是不支持动态的扩缩容,它是静态内存分配的,一旦分配完成,其容量是固定的。为了支持学生的动态增长,这里可以引入链表。

链表

在C语言中,链表是一种常用的数据结构,它由一系列的节点组成,每个节点包含数据和指向下一个节点的指针。
链表的关键点:

  1. 节点(Node): 链表中的每个元素称为节点。每个节点通常包含两个部分:数据(Data)和指向另一个节点的指针(Next)。
  2. 头指针(Head Pointer):一个指针,它指向链表的第一个节点。这是链表的起点,通过头指针可以遍历整个链表。
  3. 尾节点(Tail Node):链表的最后一个节点,并不是一个独立的指针,而是链表中的一个节点,其指针部分指向NULL,表示链表的结束。
    在这里插入图片描述
    学生信息的结构体可以重新定义为:
typedef struct student {
    int id; // 学号
    char name[MAX_NAME_LEN]; // 姓名
    float score; // 成绩
    struct student *next; //这里不能够使用 Student *next原因是Student还未定义。
} Student;

链表实现完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for access() function

#define MAX_NAME_LEN 50
#define STUDENT_SYSTEM "student_system"

typedef struct student {
    int id; // 学号
    char name[MAX_NAME_LEN]; // 姓名
    float score; // 成绩
    struct student *next;
} Student;

struct student_db {
    Student *header; // 后续指向学生信息链表头部的指针
    int student_count; // 学生数量
};

struct student_db stu_db = {
    .header = NULL,
    .student_count = 0
};

int write_student_info(Student *s)
{
    FILE *fp = fopen(STUDENT_SYSTEM, "a");
    if (fp == NULL) {
        printf("fopen student_system failed!\n");
        return 1;
    }

    fprintf(fp, "%-4d %-10s %-.2f\n", s->id, s->name, s->score);

    fclose(fp);
    return 0;
}

int check_if_student_exsit(int id)
{
    Student *cur= stu_db.header;

    while(cur!= NULL) {
        if(cur->id == id) {
            return 1;
        }
        cur = cur->next;
    }

    return 0;
}

Student *init_node(int id, char *name, int score)
{
    Student *new_s;

    new_s = malloc(sizeof(Student));
    if (new_s == NULL) {
        printf("malloc Student failed!\n");
        exit(-1);
    }
    new_s->next = NULL;
    new_s->id = id;
    strcpy(new_s->name, name);
    new_s->score = score;
    return new_s;
}

void add_student()
{
    Student s, *cur, *new_s;

    printf("Enter student ID: ");
    scanf("%d", &s.id);
    printf("Enter student name: ");
    scanf("%s", s.name);
    s.score = 0.0; // 初始成绩设置为0

    if (!check_if_student_exsit(s.id)) {
        cur = stu_db.header;
        if (cur) {
            while(cur) {
                if (cur->next == NULL) {
                    new_s = init_node(s.id, s.name, s.score);
                    cur->next = new_s;
                    break;
                }
                cur = cur->next;
            }
        } else {
            new_s = init_node(s.id, s.name, s.score);
            stu_db.header = new_s;
        }

        stu_db.student_count++;
        printf("Student added successfully, all student: %d!\n", stu_db.student_count);
        write_student_info(&s);
    } else {
        printf("student has in db, do nothing!\n");
    }
}

void print_title()
{
    printf("%-4s %-10s %-5s\n", "ID", "Name", "Score");
}

void display_all_students()
{
    Student *cur;

    printf("-------- All students info --------\n");
    if (stu_db.student_count == 0) {
        printf("No students!\n");
    } else {
        print_title();
        cur = stu_db.header;
        while (cur) {
            printf("%-4d %-10s %-.2f\n", cur->id, cur->name, cur->score);
            cur = cur->next;
        }
    }
    printf("--------      End       -----------\n");
}

void find_student_by_id()
{
    int id;

    printf("Enter student ID to search: ");
    scanf("%d", &id);

    Student *cur = stu_db.header;
    while (cur) {
        if (cur->id == id) {
            printf("%-4d %-10s %-.2f\n", cur->id, cur->name, cur->score);
            return;
        }
        cur = cur->next;
    }

    printf("Student with ID %d not found!\n", id);
}

void find_student_by_name()
{
    int is_find = 0;
    char name[MAX_NAME_LEN];

    printf("Enter student name to search: ");
    scanf("%s", name);

    Student *cur = stu_db.header;
    while (cur) {
        if(strcmp(cur->name, name) == 0) {
            printf("%-4d %-10s %-.2f\n", cur->id, cur->name, cur->score);
            is_find = 1;
        }
        cur = cur->next;
    }

    if (is_find == 0) {
        printf("Student with name %s not found!\n", name);
    }
}

void add_score()
{
    int id;
    float score;

    printf("Enter student ID: ");
    scanf("%d", &id);
    printf("Enter student score: ");
    scanf("%f", &score);

    Student *cur = stu_db.header;
    while (cur) {
        if(cur->id == id) {
            cur->score = score;
            printf("Score added successfully!\n");
            return;
        }
        cur = cur->next;
    }
    printf("Student with ID %d not found!\n", id);
}

void display_average_score()
{
    float total = 0.0;

    Student *cur = stu_db.header;
    while (cur) {
        total += cur->score;
        cur = cur->next;
    }

    printf("Average score of all students: %.2f\n", total / stu_db.student_count);
}

int init_student_info()
{
    if(access(STUDENT_SYSTEM, F_OK) != 0) { // 文件不存在
        return 0;
    }

    FILE *fp = fopen(STUDENT_SYSTEM, "r");
    if (fp == NULL) {
        printf("fopen student_system failed!\n");
        return 1;
    }

#define BUF_SIZE 1024
    char buf[BUF_SIZE];
    Student *s, *current;
    while(fgets(buf, BUF_SIZE - 1, fp) != NULL) {
        s = malloc(sizeof(Student));
        if (s == NULL) {
            printf("malloc Student failed!\n");
            exit(-1);
        }

        s->next = NULL;
        sscanf(buf, "%d %s %f\n", &s->id, s->name, &s->score);
        stu_db.student_count++;
        if (stu_db.header == NULL) {
            stu_db.header = s;
            current = s;
        } else {
            current->next = s;
            current = s;
        }
    }

    fclose(fp);
    return 0;

}

int main()
{
    int choice;
    int ret;

    ret = init_student_info();
    if (ret) {
        printf("init_student_info failed!\n");
        return 1;
    }
    display_all_students();

    do {
        printf("\nStudent Score Management System\n");
        printf("1. Add Student\n");
        printf("2. Display All Students\n");
        printf("3. Find Student by ID\n");
        printf("4. Find Student by Name\n");
        printf("5. Add Score\n");
        printf("6. Display Average Score\n");
        printf("7. Exit\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);

        switch(choice) {
            case 1:
                add_student();
                break;
            case 2:
                display_all_students();
                break;
            case 3:
                find_student_by_id();
                break;
            case 4:
                find_student_by_name();
                break;
            case 5:
                add_score();
                break;
            case 6:
                display_average_score();
                break;
            case 7:
                printf("Exiting...\n");
                break;
            default:
                printf("Invalid choice!\n");
        }
    } while(choice != 7);

    return 0;
}

总结

通过链表重构学生成绩管理系统,学生上限数除了受限于内存,其他不受限制。链表相较于数组,它有灵活的扩展的优势,但是它的内存不是连续的,访问性能比不上数组。
虽然当前数组实现的查询,也是遍历数组,但是这里是可以进行排序优化查询的,但是链表不行。
在高性能转发场景中,比如dpdk场景中,使用的还是数组

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/392165.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入解析鸿蒙系统的页面路由(Router)机制

鸿蒙系统以其独特的分布式架构和跨设备的统一体验而备受瞩目。在这个系统中&#xff0c;页面路由&#xff08;Router&#xff09;机制是连接应用各页面的关键组成部分。本文将深入探讨鸿蒙系统的页面路由&#xff0c;揭示其工作原理、特点以及在应用开发中的实际应用。 1. 实现…

使用Autodl云服务器或其他远程机实现在本地部署知识图谱数据库Neo4j

本篇博客的目的在于提高读者的使用效率 温馨提醒&#xff1a;以下操作均可在无卡开机状态下就可完成 一.安装JDK 和 Neo4j 1.1 ssh至云服务器 打开你的pycharm或者其他IDE工具或者本地终端&#xff0c;ssh连接到autodl的服务器。(这一步很简单如下图) 1.2 安装JDK 由于我…

gitlab代码控制平台搭建

docker-compose容器化gitlab docker-compose安装 # 官方链接(不推荐&#xff0c;太慢了) curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose# 下面的官方链接会快一…

JAVA面试题基础篇

1. 二分查找 要求 能够用自己语言描述二分查找算法 能够手写二分查找代码 能够解答一些变化后的考法 算法描述 前提&#xff1a;有已排序数组 A&#xff08;假设已经做好&#xff09; 定义左边界 L、右边界 R&#xff0c;确定搜索范围&#xff0c;循环执行二分查找&#…

计算机网络——15套接字编程

套接字编程 Socket编程 Socket编程&#xff1a;应用进程使用传输层提供的服务才能够交换报文&#xff0c;实现应用协议&#xff0c;实现应用 TCP/IP&#xff1a;应用进程使用Socket API访问传输服务 地点&#xff1a;界面上的SAP 方式&#xff1a;Socket API 目标&#xff1…

鸿蒙开发系列教程(二十四)--List 列表操作(3)

列表编辑 1、新增列表项 定义列表项数据结构和初始化列表数据&#xff0c;构建列表整体布局和列表项。 提供新增列表项入口&#xff0c;即给新增按钮添加点击事件。 响应用户确定新增事件&#xff0c;更新列表数据。 2、删除列表项 列表的删除功能一般进入编辑模式后才可…

stable diffusion webui学习总结(2):技巧汇总

一、脸部修复&#xff1a;解决在低分辨率下&#xff0c;脸部生成异常的问题 勾选ADetailer&#xff0c;会在生成图片后&#xff0c;用更高的分辨率&#xff0c;对于脸部重新生成一遍 二、高清放大&#xff1a;低分辨率照片提升到高分辨率&#xff0c;并丰富内容细节 1、先通过…

Leetcode-429.N叉树的层序遍历

题目&#xff1a; 给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&#xff09;。 示例 1&#xff1a; 输入&#xff…

Rocky Linux 下载安装

一、VMware Workstation下载安装 1、安装教程 VMware Workstation下载安装&#xff08;含密钥&#xff09; 二、VMware Workstation 创建虚拟机 1、创建教程 VMware Workstation 创建虚拟机 三、Rocky Linux 下载 1、下载官网 RockyLinux.org 2、选择X86架构_64位系统_DVD镜…

【C++初阶】第三站:类和对象(中) -- 日期计算器

目录 前言 日期类的声明.h 日期类的实现.cpp 获取某年某月的天数 全缺省的构造函数 拷贝构造函数 打印函数 日期 天数 日期 天数 日期 - 天数 日期 - 天数 前置 后置 前置 -- 后置-- 日期类中比较运算符的重载 <运算符重载 运算符重载 ! 运算符重载 …

JavaScript设计模式与开发实战

JavaScript设计模式与开发实践 第一章、面向对象的JavaScript 1.1 多态 类似java面向对象&#xff0c;通过继承共有特征&#xff0c;来实现不同方法。JavaScript的多态就是把“做什么”和“谁去做”分离&#xff0c;消除类型间的耦合关系。 他的作用就是把过程化的条件分支…

TIM编码器接口(编码器测速)

定时器编码器接口自动计次--------->对应手册14.3.12编码器接口模式 应用场景&#xff1a; 电机控制PWM驱动电机&#xff0c;编码器测电机速度&#xff0c;PID算法闭环控制 ------------------------------------------------------------------------------------------…

【Linux】程序地址空间 -- 详解 Linux 2.6 内核进程调度队列 -- 了解

一、程序地址空间回顾 在学习 C/C 时&#xff0c;我们知道内存会被分为几个区域&#xff1a;栈区、堆区、全局/静态区、代码区、字符常量区等。但这仅仅是在语言层面上的理解&#xff0c;是远远不够的。 如下空间布局图&#xff0c;请问这是物理内存吗&#xff1f; 不是&…

LV.23 D3 STM32 GPIO口操作平台介绍 学习笔记

一、GPIO的基本概念及寄存器介绍 1.1 GPIO接口简介 通用输入输出接口GPIO是嵌入式系统、单片机开发过程中最常用的接口&#xff0c;用户可以通过编程灵活的对接口进行控制&#xff0c;实现对电路板上LED、数码管、按键等常用设备控制驱动&#xff0c;也可以作为串口的数据收发…

文件上传漏洞--Upload-labs--Pass02--Content-Type绕过

一、什么是 Content-Type 我们在上传文件时利用 Burpsuite 进行抓包&#xff0c;如下图所示&#xff1a; 上传文件后台的源代码可能会对 Content-Type 进行规定&#xff0c;设置白名单 或 黑名单&#xff0c;这时就要利用Content-Type绕过上传含有恶意代码的 php文件。 二、代…

2023年中国数据智能管理峰会(DAMS上海站2023):核心内容与学习收获(附大会核心PPT下载)

随着数字经济的飞速发展&#xff0c;数据已经渗透到现代社会的每一个角落&#xff0c;成为驱动企业创新、提升治理能力、促进经济发展的关键要素。在这样的背景下&#xff0c;2023年中国数据智能管理峰会&#xff08;DAMS上海站2023&#xff09;应运而生&#xff0c;汇聚了众多…

解锁Spring Boot中的设计模式—03.委派模式:探索【委派模式】的奥秘与应用实践!

委派模式 文章目录 委派模式1.简述**应用场景****优缺点****业务场景示例** 2.类图3.具体实现3.1.自定义注解3.2.定义抽象委派接口3.3.定义具体执行者3.4.定义委派者(统一管理委派任务)3.5.定义委派者管理类 4.测试4.1.controller层4.2.测试不同场景4.2.1.测试生产部门计算费用…

排序前言冒泡排序

目录 排序应用 常见的排序算法 BubbleSort冒泡排序 整体思路 图解分析 ​ 代码实现 每趟 写法1 写法2 代码NO1 代码NO2优化 时间复杂度 排序概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递…

python in Vscode

背景 对于后端的语言选择&#xff1a; python&#xff0c;java&#xff0c;JavaScript备选。 选择Python 原因&#xff1a;可能是非IT专业的人中&#xff0c;会Python的人比较多。 目的 之前使用的IDE是VSCODE&#xff0c;在WSL的环境下使用。现在需要在在WSL的VSCODE下使…

【开源】SpringBoot框架开发创意工坊双创管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…