C语言链表实现简单的学生信息管理系统
2019-07-02 11:56
597 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_39778055/article/details/94414424
第一次写博客,今天学习了C语言链表的相关知识,自己实现了一个很简单的学生成绩管理系统,同时也温习了一下多文件编程,想和大家分享一下自己从中的一些经验和感受。
头文件
[code]//List.h 包含结构体的定义 #ifndef M //使用条件编译来避免重复包含 #define M struct Student { char name[50];//学生的姓名 double score;//学生的成绩 struct Student *pnext;//存储下一个节点的地址 }; #endif typedef struct Student ST;//简化结构体的声明
[code]//function.h,包含函数的定义 #define _CRT_SECURE_NO_WARNINGS//关闭安全检查 #include<stdio.h> #include<stdlib.h> #include<string.h> #include"List.h" void add(ST **head, char *name, double iscore);//增加学生的成绩信息 void del(ST **head, char *name, double iscore);//删除学生的成绩信息 void get(const ST *head, char *name);//查询学生的成绩信息 void change(ST *head, char *name, double score, double sscore);//改变学生的成绩信息 void sort(const ST *head);//对学生的成绩进行排序 ST *rev(ST *head);//逆转所有学生的成绩信息 void insert(ST **head, char *name, double iscore);//插入学生的成绩信息 void print(const ST *head);//打印学生的成绩信息 ST *delall(ST *head);//删除所有学生的信息
//各个函数的实现
[code]#include"function.h" //实现add函数 void add(ST **head, char *name, double iscore)//增加学生的成绩信息 { if (*head == NULL)//整个链表为空 { ST *phead = (ST *)malloc(sizeof(ST));//动态分配内存空间 strcpy(phead->name, name);//字符串拷贝 phead->score = iscore; phead->pnext = NULL;//最后一个节点的指针域为NULL *head = phead;//指向头节点 } else//链表为非空 { ST *p = *head;//存储首节点的地址 while (p->pnext)//循环到最后一个节点,并且不改变传入的头节点指针的指向 { p = p->pnext; } ST *pnew = (ST *)malloc(sizeof(ST)); strcpy(pnew->name, name); pnew->score = iscore; pnew->pnext = NULL;//最后一个指针域为空 p->pnext = pnew;//将节点连接起来 } }
由于函数的副本机制,所以改变一个指针的指向需要使用二级指针
[code]#include"function.h" //实现del函数 void del(ST **head, char *name, double iscore)//删除学生的成绩信息 { ST *p = *head; if ((strcmp(p->name, name) == 0) && (p->score == iscore))//删除的为首节点 { *head = p->pnext;//指向下一个节点 free(p);//释放内存 } else//删除的不是首节点 { ST *p1 = p;//记录上一个节点的地址 while (p->pnext) { if ((strcmp(p->name, name) == 0) && (p->score == iscore))//找到了待删除的节点 { p1->pnext = p->pnext;//删除节点p free(p); break;//跳出循环 } p1 = p; p = p->pnext;//下一次的循环 } } }
删除链表的一个节点只需让上一个节点存储该节点的指针域即可
[code]#include"function.h" //实现get函数 void get(const ST *head, char *name) { ST *p = head; while (p->pnext) { if (strcmp(p->name, name) == 0) { printf("%s的成绩为%lf\n", name, p->score); } p = p->pnext; } }
[code]#include"function.h" //实现change函数 void change(ST *head, char *name, double score, double sscore) { ST *p = head; while (p->pnext) { if ((strcmp(p->name, name) == 0) && (p->score == score)) { p->score = sscore;//函数的副本机制,必须通过指针才能改变原来的值 break; } p = p->pnext; } }
[code]#include"function.h" //实现sort函数 void sort(const ST *head) { //选择排序法 for (ST *pi = head; pi; pi = pi->pnext) { for (ST *pj = pi->pnext; pj; pj = pj->pnext) { if ((pi->score) > (pj->score)) { //交换成绩 double temp = pi->score; pi->score = pj->score; pj->score = temp; //交换姓名 char str[50]; strcpy(str, pi->name); strcpy(pi->name, pj->name); strcpy(pj->name, str); } } } }
[code]#include"function.h" //实现rev函数 ST * rev(ST *head)//链表的逆转 { if (head == NULL || head->pnext == NULL)//链表为空或者只有一个节点 { return head; } ST *p1 = head, *p2 = NULL, *p3 = NULL; p2 = p1->pnext;//指向下一个节点 while (p2)//p2为NULL时循环结束 { p3 = p2->pnext; p2->pnext = p1;//存储前一个节点的值 p1 = p2; p2 = p3;//指针依次向后移动一位 } head->pnext = NULL;//最后一个指针域为NULL head = p1;//指向头节点 return head;//返回头节点,由于函数有副本机制,因此只有通过返回值 //并且在main函数中赋值才能在不使用二级指针的情况下改变头节点 }
链表的逆转就是让每一个节点依次存储前一个节点的地址,最后再让头指针指向之前的最后一个节点即可。
[code]#include"function.h" //实现insert函数 static void inserth(ST **head, char *name, double iscore)//在链表的头部插入 { ST *p = (ST *)malloc(sizeof(ST)); strcpy(p->name, name); p->score = iscore; p->pnext = *head;//将节点连接起来 *head = p;//指向头节点 } static void insertc(const ST *head, ST *phead, ST *pback, char *name, double iscore)//在链表的中间插入 { ST *p = (ST *)malloc(sizeof(ST)); strcpy(p->name, name); p->score = iscore; phead->pnext = p; p->pnext = pback;//将链表连接起来 } void insert(ST **head, char *name, double iscore)//实现节点的插入 { ST *p = *head; if (iscore < (p->score))//比第一个成绩还小,则在首节点前面插入 { inserth(head, name, iscore); } else//在中间或者尾部插入 { ST *pc = NULL;//记录当前节点的位置 //定位到待插入点的位置 while (((p->score) < iscore) && p->pnext) { pc = p; p = p->pnext; } if (p->pnext == NULL)//尾部插入 { add(head, name, iscore); } else//中间插入 { insertc(*head, pc, pc->pnext, name, iscore); } } }
链表在插入之前需要先进行排序操作
[code]#include"function.h" //实现print函数 void print(const ST *head)//输出所有节点 { ST *p = head; while (p) { printf("学生%s的成绩为%lf\n", p->name, p->score); p = p->pnext; } }
[code]#include"function.h" //实现delall函数 ST *delall(ST *head)//删除所有节点 { ST *p1 = NULL; while (head->pnext) { p1 = head->pnext; head->pnext = p1->pnext;//删除节点p2 free(p1);//释放p1的内存 //printf("\n删除后的链表为:\n\n"); //print(head);//输出删除后的结果 } free(head);//删除第一个节点 return NULL;//返回空指针 }
删除整个链表时,保持头节点的位置不变,依次删除下一个节点,最后再删除头节点即可。
[code]#include"function.h" void main() { ST *head = NULL; int num; printf("请输入学生的人数:\n"); scanf("%d", &num);//从键盘获取num的输入 int count = 1;//计数 while (num) { char name[50]; double score = 0; printf("请输入第%d个学生的姓名:\n", count); scanf("%s", name);//从键盘获取输入 printf("请输入第%d个学生的成绩:\n", count); scanf("%lf", &score); add(&head, name, score); count++; num--; } sort(head); printf("\n\n学生的成绩为:\n"); print(head); system("pause"); }
最后是main函数中进行调用,由于已经直接包含了头文件,所以此时没必要再用extern进行外部函数声明。
通过这个简单的小项目,也进一步巩固了自己对链表的增删查改,逆转等操作的熟悉,同时也复习了函数副本以及二级指针的相关知识!
相关文章推荐
- Linux环境下C语言实现简单的基于文件的学生信息管理系统
- c语言使用链表编写一个可以实现班级学生管理系统,增加,删除,修改学生信息
- C语言实现学生信息管理系统(单链表)
- 学生信息管理系统简单模拟(C语言实现)
- C语言简单用链表实现学生管理系统
- C语言使用链表实现学生信息管理系统
- c++封装链表实现-->学生信息管理分析系统
- 【c语言】简单学生信息管理系统
- 简单实现了一个学生成绩信息管理系统
- c语言实现的学生信息管理系统
- C语言单链表实现学生管理系统(增删改查)
- C语言实现 学生信息管理系统
- python下学生管理系统:从文件中读取30位学生的信息(含邮箱),并实现简单的增、删、查找、统计(邮箱使用人数)。---附程序哦!
- 学生信息管理简单版本(C语言链表)
- c语言基于链表的学生信息管理系统(源代码)
- c#实现简单学生信息管理系统
- C语言实现学生信息管理系统
- <C语言>使用一个二维数组实现学生姓名管理系统,要求不能使用链表
- C语言链表实现的简易学生成绩管理系统
- C语言单链表版学生信息管理系统