C語言鏈表實現學生成績管理系統

本文實例為大傢分享瞭C語言基於鏈表實現學生成績管理系統的具體代碼,供大傢參考,具體內容如下

一、課程設計題目及內容

程序名稱:學生成績管理系統

功能要求:錄入學生成績,修改學生成績,統計每個學生的總分及平均分並能根據學生的平均成績排序,查詢學生成績,輸出學生成績單。能夠保存學生成績,實現文件的讀寫。界面簡潔大方,易操作。

二、主要設計思路

以鏈表作為數據結構存儲學生成績等信息,然後圍繞鏈表編寫一堆函數來實現一堆功能

程序開始時會讀取文件數據到鏈表,結束時會把更新後的鏈表中的信息重新寫入到文件中,以實現數據的保存

三、程序源碼及具體註釋

(1)預處理指令

導入<stdlib.h>是因為會用到malloc函數和free函數

導入<string.h>是因為會用到strcmp函數

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LEN 10
#define FILE_NAME "學生成績.txt"

(2)類型定義

1.student類型定義

一個student變量代表一組學生信息

typedef struct {
    char name[NAME_LEN + 1];//姓名
    int number;                //學號
    int chinese;            //語文
    int math;                //數學
    int english;            //英語
    int average;            //平均分
    int sum;                //總分
} student;                    //用於存儲單個學生的信息

2. studentNode類型定義

一個studentNode變量代表一個學生節點

typedef struct node {
    student stu;        //數據域,存儲學生信息
    struct node *next;    //指針域,指向下一個節點
} studentNode;            //學生節點

3. studentList類型定義

一個studentList變量代表一個學生鏈表

typedef struct {
    studentNode *head;    //頭指針
    studentNode *tail;    //尾指針
    int count;            //學生節點總數
} studentList;            //學生鏈表

(3)函數原型

void initialize(studentList *L);//初始化鏈表,創建頭節點
void enter(studentList *L);        //錄入鏈表
void display(studentList *L);    //輸出鏈表
void find(studentList *L);        //查找某節點
void modify(studentList *L);    //修改某節點
void sort(studentList *L);        //降序重新建表並輸出
void write(studentList *L);        //寫入文件,邊寫邊釋放空間
void read(studentList *L);        //讀取文件,邊讀邊建表

(4)main函數定義

開頭會創建並初始化一個鏈表,然後把文件的信息讀到鏈表中

通過一個無限循環裡面套一個switch來實現與用戶互動

結尾會把鏈表中的信息寫到文件中,然後銷毀鏈表

int main() {
    //互動界面
    printf("        **************學生成績管理系統**************\n");
    printf("        *  1.錄入新的學生成績                      *\n");
    printf("        *  2.按姓名修改學生成績                    *\n");
    printf("        *  3.按姓名查詢學生成績                    *\n");
    printf("        *  4.輸出全部學生的成績                    *\n");
    printf("        *  5.按平均分輸出學生成績                  *\n");
    printf("        *  6.退出學生成績管理系統                  *\n");
    printf("        ********************************************\n");
    printf("                                                      \n");
    //創建學生鏈表
    studentList *L = (studentList *)malloc(sizeof(studentList));
    //初始化學生鏈表
    initialize(L);
    //從文件裡讀取數據到鏈表
    read(L);
    //互動界面是用一個無限循環和一個switch寫的
    while (1) {
        int code;
        printf("請輸入你想進行的操作對應的數字: ");
        scanf("%d", &code);
        switch (code) {
            case 1:
                enter(L);
                break;
            case 2:
                modify(L);
                break;
            case 3:
                find(L);
                break;
            case 4:
                display(L);
                break;
            case 5:
                sort(L);
                break;
            case 6:
                write(L);
                free(L->head);    //頭節點被銷毀
                free(L);        //鏈表被銷毀
                return 0;
            default:
                printf("%d是無效的數字,請重新輸入!\n\n", code);
                break;
        }
    }
    return 0;
}

(5)其他函數定義 

1.initialize函數定義

接收一個鏈表指針作為參數

創建一個頭節點,不存儲任何信息,讓鏈表的頭尾指針都指向它

鏈表的初始長度設為0

void initialize(studentList *L) {
    //創建頭節點
    studentNode *s = (studentNode *)malloc(sizeof(studentNode));
    s->next = NULL;
    //初始化鏈表:
    //頭尾指針均指向頭節點,初始長度為零
    L->head = s;
    L->tail = s;
    L->count = 0;
}

2.enter函數定義

接收一個鏈表指針作為參數

讓用戶鍵入信息並存到新節點中

把新節點插進鏈表中

void enter(studentList *L) {
    //創建新節點
    studentNode *s = (studentNode *)malloc(sizeof(studentNode));
    //鍵入信息並存到新節點中
    printf("請輸入學生姓名:");
    scanf("%s", s->stu.name);
    printf("請輸入學生學號:");
    scanf("%d", &s->stu.number);
    printf("請輸入語文成績:");
    scanf("%d", &s->stu.chinese);
    printf("請輸入數學成績:");
    scanf("%d", &s->stu.math);
    printf("請輸入英語成績:");
    scanf("%d", &s->stu.english);
    s->stu.sum = s->stu.chinese + s->stu.math + s->stu.english;
    s->stu.average = s->stu.sum / 3;
    //若鏈表為空,將尾指針指向新節點
    if (L->head == L->tail) {
        L->tail = s;
    }
    //將新節點插進鏈表頭部(頭插法)
    s->next = L->head->next;
    L->head->next = s;
    L->count++;
    //輸出互動信息
    printf("信息錄入成功!\n\n");
}

3.display函數定義

遍歷鏈表輸出就完事兒瞭

void display(studentList *L) {
    printf("共有%d組學生數據:\n", L->count);
    printf("姓名\t\t學號\t\t語文\t\t數學\t\t英語\t\t總分\t\t平均分\n");
    //創建一節點指針指向頭節點
    studentNode *p;
    p = L->head;
    //遍歷鏈表輸出
    while (p->next) {
        p = p->next;
        printf("%s", p->stu.name);
        printf("\t\t%d", p->stu.number);
        printf("\t\t%d", p->stu.chinese);
        printf("\t\t%d", p->stu.math);
        printf("\t\t%d", p->stu.english);
        printf("\t\t%d", p->stu.sum);
        printf("\t\t%d", p->stu.average);
        printf("\n");
    }
    printf("\n");
}

4.find函數定義

void find(studentList *L) {
    //讓用戶輸入要查找的學生
    printf("請輸入學生姓名:");
    char name[NAME_LEN + 1];
    scanf("%s", name);
    //遍歷鏈表對比名字
    studentNode *p = L->head->next;
    while (p) {
        //符合瞭就輸出並結束函數
        if (strcmp(p->stu.name, name) == 0) {
            printf("姓名\t\t學號\t\t語文\t\t數學\t\t英語\t\t總分\t\t平均分\n");
            printf("%s", p->stu.name);
            printf("\t\t%d", p->stu.number);
            printf("\t\t%d", p->stu.chinese);
            printf("\t\t%d", p->stu.math);
            printf("\t\t%d", p->stu.english);
            printf("\t\t%d", p->stu.sum);
            printf("\t\t%d", p->stu.average);
            printf("\n\n");
            return;
        }
        //名字不符合就下一個
        p = p->next;
    }
    //遍歷完裡都沒找到這個名字
    printf("沒找到這個%s的信息!\n\n", name);
}

5.modify函數定義 

void modify(studentList *L) {
    //讓用戶輸入要修改的學生
    printf("請輸入學生姓名:");
    char name[NAME_LEN + 1];
    scanf("%s", name);
    //遍歷鏈表對比名字
    studentNode *p = L->head->next;
    while (p) {
        //符合瞭就讓用戶重新鍵入並結束函數
        if (strcmp(p->stu.name, name) == 0) {
            printf("請重新輸入信息:\n");
            printf("請輸入學生學號:");
            scanf("%d", &p->stu.number);
            printf("請輸入語文成績:");
            scanf("%d", &p->stu.chinese);
            printf("請輸入數學成績:");
            scanf("%d", &p->stu.math);
            printf("請輸入英語成績:");
            scanf("%d", &p->stu.english);
            p->stu.sum = p->stu.chinese + p->stu.math + p->stu.english;
            p->stu.average = p->stu.sum / 3;
            printf("信息修改成功!\n\n");
            return;
        }
        //名字不符合就下一個
        p = p->next;
    }
    //遍歷完裡都沒找到這個名字
    printf("沒找到這個%s的信息!\n\n", name);
}

6.sort函數定義

void sort(studentList *L) {
    //兩個節點都沒有排個屁序
    if (L->count < 2) {
        printf("鏈表排序完成!\n");
        display(L);
        return;
    }
    //插入排序
    studentNode *p, *pre, *tmp;
    //p指向第二個學生節點
    p = L->head->next;
    //鏈表從頭節點和第一個學生節點處斷開
    L->head->next = NULL;
    //從第一個學生節點開始一直往後循環
    while (p) {
        //存好下一個節點的指針
        tmp = p->next;
        //找到插入位置
        pre = L->head;
        while (pre->next != NULL && pre->next->stu.average > p->stu.average)
            pre = pre->next;
        //更新尾指針
        if (pre->next == NULL) {
            L->tail = p;
        }
        //插入
        p->next = pre->next;
        pre->next = p;
        //跳到下一個
        p = tmp;
    }
    printf("鏈表排序完成!\n");
    display(L);
}

7.write函數定義

此函數用於把鏈表中的信息保存到文件中並且銷毀所有節點(頭節點除外)

void write(studentList *L) {
    //打開文件流
    FILE *fp = fopen(FILE_NAME, "w");
    if (fp == NULL) {
        printf("文件%s打開失敗\n", FILE_NAME);
        exit(EXIT_FAILURE);
    }
    //將學生節點總數輸出在第一行
    fprintf(fp, "%d\n", L->count);
    //創建一節點指針指向頭節點
    studentNode *p;
    p = L->head->next;
    //遍歷鏈表,一組數據作為一行輸出
    while (p) {
        fprintf(fp, "%s ", p->stu.name);
        fprintf(fp, "%d ", p->stu.number);
        fprintf(fp, "%d ", p->stu.chinese);
        fprintf(fp, "%d ", p->stu.math);
        fprintf(fp, "%d ", p->stu.english);
        fprintf(fp, "%d ", p->stu.sum);
        fprintf(fp, "%d ", p->stu.average);
        fprintf(fp, "\n");
        //輸出完成之後釋放節點空間
        studentNode *next = p->next;
        free(p);
        p = next;
    }
    //關閉文件流
    fclose(fp);
    //互動信息
    printf("數據已保存!謝謝使用,再見!\n");
}

8.read函數定義

此函數用於把文件中的信息讀取到鏈表中並且創建節點(頭節點除外)

void read(studentList *L) {
    //打開文件流
    FILE *fp = fopen(FILE_NAME, "r");
    if (fp == NULL) {
        printf("文件%s打開失敗\n", FILE_NAME);
        exit(EXIT_FAILURE);
    }
    //讀取第一行的學生節點總數
    fscanf(fp, "%d", &L->count);
    //循環讀取數據,循環次數為count
    for (int i = 1; i <= L->count; i++) {
        //創建新節點
        studentNode *s = (studentNode *)malloc(sizeof(studentNode));
        //讀取數據
        fscanf(fp, "%s ", s->stu.name);
        fscanf(fp, "%d ", &s->stu.number);
        fscanf(fp, "%d ", &s->stu.chinese);
        fscanf(fp, "%d ", &s->stu.math);
        fscanf(fp, "%d ", &s->stu.english);
        fscanf(fp, "%d ", &s->stu.sum);
        fscanf(fp, "%d ", &s->stu.average);
        //將新節點插進鏈表尾部(尾插法)
        s->next = NULL;
        L->tail->next = s;
        L->tail = s;
    }
    //關閉文件流
    fclose(fp);
}

四、運行示例

輸出全部學生成績

錄入一組新數據然後關閉程序

上次輸入的信息還在,說明信息保存成功

五、註意事項 

文件得和源碼在同一目錄

文件名是"學生成績.txt"

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: