C语言加链表实现学生信息管理系统

简介: 用C语言加链表的知识实现简单的学生信息管理系统。(可以自己完善添加数据库,文件流等操作)
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include<stdbool.h>
#define NO_LENGTH 20
#define NAME_LENGTH 11

typedef struct Student {
    char number[NO_LENGTH]; //学号
    char name[NAME_LENGTH]; //姓名
    char sex[6];            //性别
    int age;                //年龄
    char phone[NO_LENGTH];  //手机号
    char box[NO_LENGTH];    //邮箱
    double grade;           //成绩
} st;

typedef struct node {
    struct Student data;
    struct node* next;
} Node,*Link;

//提示菜单:
void myMenu() {
    printf("* * * * * * * * * * 菜     单 * * * * * * * * * *\n");
    printf("     1 增加学生记录            2 删除学生记录                     \n");
    printf("     3 查找学生记录            4 修改学生记录                     \n");
    printf("     5 统计学生人数            6 显示学生记录                     \n");
    printf("     7 学生成绩排名            8 退出系统          \n");
    printf(" * * * * * * * * * * * * * * * * * * * * * * * *\n");
}

//尾插:按顺序存放
Link newList(struct Student list[],int n) {
    Link head = malloc(sizeof(Node));
    head->next = NULL;
    Link rear = head;
    for(int i = 0; i < n; i++) {
        Link node = malloc(sizeof(Node));
        node->data = list[i];
        node->next = NULL;
        rear->next = node;
        rear = node;
    }
    return head;
}

//遍历:
void displayNode(Link head) {
    Link p = head->next;
    int count = 0;
    while(p != NULL) {
        printf("\n第%d个学生的学号、姓名、性别、年龄分别是:%s %s %s %d\n",
               count+1,p->data.number,p->data.name,p->data.sex,p->data.age);
        printf("手机号是:%s , 邮箱是: %s,总成绩是:%.2f\n",p->data.phone,p->data.box,p->data.grade);
        count++;
        p = p->next;
    }
    printf("\n");
}

//删除记录:(查学号删除)
bool deleteNode(Link head,char number[]) {
    if(head == NULL || head->next == NULL) {
        return false;
    }
    Link p = head->next;
    Link q = head;
    while(p != NULL) {
        if(strcmp(p->data.number,number) == 0) {
            q->next = p->next;
            free(p);
            return true;
        } else {
            q = p;
            p = p->next;
        }
    }
    return false;
}


//选择记录插入:
bool insertNode(Link head,int i,struct Student newdata) {
    Link p = head;
    int count = 1;
    while(p != NULL && count < i) {
        p = p->next;
        count++;
    }
    if(p == NULL) {
        return false;
    } else {
        Link node = malloc(sizeof(Node));
        node->data = newdata;
        node->next= p->next;
        p->next = node;
        return true;
    }
}

//按学生学号大小增加学生记录:
void inputStudent(Link l) {
    printf("请分别输入学生的学号、姓名、性别、年龄、手机号、邮箱、总成绩:\n");
    scanf("%s%s%s%d%s%s%lf",l->data.number,l->data.name,l->data.sex,&l->data.age,
          l->data.phone,l->data.box,&l->data.grade);
    //每个新创建的节点的next域都初始化为NULL
    l->next = NULL;
}

//按学号大小插入新结点
bool addNode(Link head) {
    Link p = head->next;
    Link q = head;      //q指向head后面的第一个有效节点
    Link node = malloc(sizeof(Node));

    inputStudent(node);

    if(head->next == NULL)  //没有数据时插入第一个数据
        head->next = node;
    else {
        while(p != NULL) {
            if (strcmp(node->data.number,p->data.number) < 0) {
                //如果node节点的学号比p节点的学号小,则插在p的前面,完成插入后,提前退出子程序
                q->next = node;
                node->next = p;
                return true;
            } else {
                //如果node节点的学号比p节点的学号大,继续向后移动指针(依然保持pq一前一后)
                q = p;
                p = p->next;

            }

        }
        //如果没能提前退出循环,则说明之前没有插入,那么当前node节点的学号是最大值,此时插在链表的最后面
        q->next = node;
    }
    return true;
}

//统计学生人数:
int countNode(Link head) {
    Link p;
    int count = 0;
    p = head->next;
    while(p != NULL) {
        count ++;
        p = p->next;
    }
    return count;
}


//释放结点;
void clearLink(Link head) {
    Link q;
    while(head->next != NULL) {
        q = head;
        free(q);
        head = head->next;
    }
    free(head);
}

//查询学生记录
bool queryNode(Link head) {
    Link p = head->next;
    int key;
    printf("输入key(1~5),查询方式(1:姓名 2:学号 3:手机号 4:邮箱 5:年龄范围) :");
    scanf("%d",&key);

    if(key != 5) {

        char value[20];
        printf("\n请输入查询关键词:");
        scanf("%s",value);
        char middle[NO_LENGTH];
        switch(key) {
            case 1:
                strcpy(middle,p->data.name);
                break;
            case 2:
                strcpy(middle,p->data.number);
                break;
            case 3:
                strcpy(middle,p->data.phone);
                break;
            case 4:
                strcpy(middle,p->data.box);

        }
        while(p != NULL) {
            if(strcmp(middle,value) == 0)  {
                printf("\n查询成功!\n");
                printf("学生信息:姓名:%s 学号:%s 性别:%s 年龄:%d \n手机号:%s 邮箱:%s 总成绩:%.2f\n",
                       p->data.name,p->data.number,p->data.sex,p->data.age,p->data.phone,p->data.box,p->data.grade);
                printf("\n");
            }
            p = p->next;
            if(p != NULL) {
                if(key == 1) strcpy(middle,p->data.name);
                else if(key == 2) strcpy(middle,p->data.number);
                else if(key == 3) strcpy(middle,p->data.phone);
                else if(key == 4) strcpy(middle,p->data.box);
            }
        }

    }

    //指定年龄范围查询:
    else {
        int age1,age2;
        int key = 0;
        printf("请输入年龄范围:");
        scanf("%d%d",&age1,&age2);
        while(p != NULL) {
            if(age1 <= p->data.age && p->data.age <= age2) {
                printf("\n查询成功!\n");
                key = 1;//说明已经有找到的
                printf("学生信息:姓名:%s 学号:%s 性别:%s 年龄:%d \n手机号:%s 邮箱:%s 总成绩:%.2f\n",
                       p->data.name,p->data.number,p->data.sex,p->data.age,p->data.phone,p->data.box,p->data.grade);
                printf("\n");
            }
            p = p->next;
        }
        if(key == 1) {
            return true;
        }
    }
    return false;
}

//修改学生信息
bool modifyNode(Link head) {
    Link p = head->next;
    char value[20];
    printf("请输入你想要修改记录的学生姓名:");
    scanf("%s",value);

    while(p != NULL) {
        if(strcmp(p->data.name,value) == 0) {
            printf("请重新输入学生的信息:\n");
            printf("输入学生的学号、姓名、性别、年龄:\n");
            scanf("%s%s%s%d",p->data.number,p->data.name,p->data.sex,&p->data.age);
            printf("输入学生的手机号、邮箱、总成绩:\n");
            scanf("%s%s%lf",p->data.phone,p->data.box,&p->data.grade);
            break;
        }
        p = p->next;
    }
    return true;
}

//输出成绩排名
bool stuScore(Link head,double data[NO_LENGTH]) {
    Link p = head->next;
    if(p == NULL) {
        return false;
    }

    int i = 0,key = 0;
    while(p != NULL) {
        data[i] = p->data.grade;
        i++;
        p = p->next;
    }

    bubblesort(data,i);
    i = 0;
    for(p = head->next; p != NULL; p = p->next) {
        if(p->data.grade == data[i]) {
            printf("第%d名:学号:%s 姓名:%s 性别:%s 总成绩:%.2f\n",i+1,p->data.number,p->data.name,p->data.sex,p->data.grade);
            p = head;
            i++;
        }
    }
    return true;
}

//冒泡排序
void bubblesort(double array[],int array_size) {
    int exchange;
    for(int pass = 1; pass < array_size; pass++) {
        exchange = 0;
        for(int i = 0; i < array_size - pass; i++) {
            if(array[i] < array[i+1]) {
                double temp = array[i];
                array[i] = array[i+1];
                array[i+1] = temp;
                exchange = 1;
            }
        }
        if(exchange == 0) break;
    }
}

int main() {

    //输入学生数据:
    int arraysize;
    printf("输入您想要记录的学生人数:");
    scanf("%d",&arraysize);
    st list[100];
    for(int i=0; i < arraysize; i++) {
        printf("第%d个学生的学号、姓名、性别、年龄、手机号、邮箱、总成绩:\n",i+1);
        scanf("%s%s%s%d%s%s%lf",list[i].number,list[i].name,list[i].sex,&list[i].age,
              list[i].phone,list[i].box,&list[i].grade);
        printf("\n");
    }
    printf("\n");

    Link head = newList(list,arraysize);  //引入头部
    double data[NO_LENGTH];  //用于作成绩排名
    int count;
    int select;
    while(1) {
        myMenu();
        printf("\n请输入你的选择(1-8):");  //显示提示信息
        scanf("%d",&select);
        switch(select) {
            case 1:
                //增加学生记录
                if(addNode(head))
                    printf("成功插入一个学生记录。\n\n");
                break;
            case 2:
                //删除学生记录
                printf("输入要修改记录的学生学号:");
                char number[NO_LENGTH];
                scanf("%s",number);
                if(deleteNode(head,number))
                    printf("成功删除一个学生记录。\n\n");
                else
                    printf("没有找到要删除的学生节点。\n\n");
                break;

            case 3:
                //查询学生记录
                if(queryNode(head))
                    printf("无法找到这位学生!\n");
                break;
            case 4:
                //修改学生记录
                if(modifyNode(head))
                    printf("成功修改一个学生记录。\n\n");
                else
                    printf("没有找到要修改的学生节点。\n\n");
                break;

            case 5:
                //统计学生人数
                count = countNode(head);
                printf("学生人数为:%d\n\n",count);
                break;
            case 6:
                //显示学生记录
                displayNode(head);
                break;
            case 7:
                //显示学生成绩排名
                stuScore(head,data);
                break;
            case 8:
                //退出前释放内存空间
                clearLink(head);
                return 0;
            default:
                printf("输入不正确,请输入1-8之间的数!\n\n");
                break;
        }
    }
    return 0;
}
相关文章
|
19天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
45 4
|
1月前
|
存储 缓存 C语言
C语言:链表和数组有什么区别
C语言中,链表和数组是两种常用的数据结构。数组是一种线性结构,元素在内存中连续存储,通过下标访问,适合随机访问且大小固定的情况。链表由一系列不连续的节点组成,每个节点存储数据和指向下一个节点的指针,适用于频繁插入和删除操作的场景,链表的大小可以动态变化。
|
1月前
|
C语言
无头链表再封装方式实现 (C语言描述)
如何在C语言中实现无头链表的再封装,包括创建节点和链表、插入和删除操作、查找和打印链表以及销毁链表的函数。
26 0
|
1月前
|
C语言
C语言链式结构之有头单链表再封装写法
本文介绍了如何使用C语言对有头单链表进行封装,包括节点的创建、链表的初始化、数据的插入和删除,以及链表的打印等功能。
16 1
|
1月前
|
C语言
C语言结构体链式结构之有头单链表
文章提供了一个C语言实现的有头单链表的完整代码,包括创建链表、插入、删除和打印等基本操作。
22 1
|
19天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
38 0
|
1月前
|
测试技术 C语言
单链表之无头链表(C语言版)
本文详细介绍了使用C语言实现无头单链表的方法,包括节点和链表结构的定义、链表的创建与销毁、节点的插入与删除,以及链表的打印等功能。文章通过具体的代码示例,展示了如何在无头链表中进行头插法、尾插法、自定义位置插入和删除,以及如何清空和销毁链表。
32 0
单链表之无头链表(C语言版)
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
24 0
|
2月前
|
C语言
C语言里的循环链表
C语言里的循环链表
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3