// 按行读取score.txt文件的所有内容，并生成有序的链表，且打印链表数据。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct stu_s
{
    int sid;
    char dh; // 逗号
    float score;

    struct stu_s *next;
} STU;

// 打印链表
void show(STU *head)
{
    if (NULL == head)
    {
        printf("数据为空，无法打印\n");
        return;
    }
    STU *tp = head;
    printf("\n学号\t成绩\n");
    while (NULL != tp)
    {
        printf("%d\t%.2f\n", tp->sid, tp->score);
        tp = tp->next;
    }
}

// 添加学生
STU *insert_stu(STU *head, STU *item)
{
    // 如果头指针为空,说明链表为空,直接将新建的节点作为头指针
    if (head == NULL)
    {
        head = item;
    }
    else
    {
        // 如果头指针不为空,说明链表不为空,需要找到链表的尾部,将新建的节点插入到尾部
        STU *p = head;          // 创建一个临时指针,用来保存头指针,防止头指针丢失
        while (p->next != NULL) // 当 p 的下一个节点不为空时,说明 p 不是尾部
        {
            p = p->next; // p 一直向后移动,直到找到尾部
        }
        p->next = item; // 将 item 插入到尾部
    }
    return head; // 返回头指针
}

int main()
{
    FILE *fp = fopen("score.txt", "r");

    if (NULL == fp)
    {
        return 1;
    }

    STU *head = NULL; // 建立链表头节点

    // 计算文件大小
    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    printf("score.txt 文件大小: %ld B\n", file_size);

    // 重置光标位置
    fseek(fp, 0, SEEK_SET); // 等同于使用 rewind(fp);
    // 按照 STU 的结构存储数据，计算出以存放学生数量
    int stu_num = file_size / sizeof(STU);
    printf("学生数量: %d\n", stu_num);

    // printf("\n学号\t成绩\n");
    for (int i = 0; i < stu_num; i++)
    {
        // 为新的链表节点分配内存空间
        STU *s = calloc(1, sizeof(STU));
        // 从文件中读取一个学生的数据
        fread(s, sizeof(STU), 1, fp);

        head = insert_stu(head, s); // 插入链表节点
    }
    show(head); // 显示链表内容

    // 最后循环释放动态申请的内存
    STU *free_tp = head;
    while (free_tp != NULL)
    {
        STU *to_free_this_p = free_tp;
        free_tp = free_tp->next;
        free(to_free_this_p);
    }

    fclose(fp);

    return 0;
}