zl程序教程

您现在的位置是:首页 >  后端

当前栏目

基于C语言实现(控制台)学生信息管理系统【100010722】

C语言 实现 基于 控制台 学生 信息管理系统
2023-09-11 14:17:49 时间

学生信息管理系统

问题定义

目的

训练学生的基本编程能力,了解管理信息系统的开发流程,熟悉 C 语言的文件和单链表的各种基本操作。本程序中涉及结构体、单链表、文件等方面的知识。通过本程序的训练,使学生能对 C 语言的文件操作有一个更深刻的了解,掌握利用单链表存储结构实现对学生成绩管理的原理,为进一步开发出高质量的管理信息系统打下坚实的基础。

任务及要求

任务:运用 C 语言中的相关知识,独立设计一个学生信息管理系统,并编程实现以下功能:

学生信息录入。进入系统录入学生成绩信息(包括学生姓名、年龄、性别、电话等)。

学生信息删除。输入学生姓名,可删除此学生在系统中保存的信息。

学生信息查找。输入姓名,查询并显示出该学生的相关信息。

浏览全部已录入信息。将全部已录入的学生的姓名、年龄、性别、电话等信息有序的罗列出来。

修改已录入的学生信息。输入需修改的学生姓名可单独修改此学生的个人信息。

要求:

定义学生信息结构,并采用链表结构对数据进行存储;

为了保证所有的数据可以长期被使用,要求程序能将录入数据存储在外部数据文件中;

提供友好的用户界面,方便用户操作;

提供提示信息和版本信息。

程序的运行效果如图 1 所示,按下数字键实现相应功能。

图 1 学生信息管理系统菜单图

系统简介

设计思路

采用模块化的程序设计方法,即将较大的任务按照一定的原则分为一个个较小的任务,然后分别设计各个小任务。各个模块大致功能如图 2 所示

图 2 通讯录系统功能模块分析图

程序设计

主函数功能描述

Main.cpp

引用自定义的头文件 myList.h

# include"myList.h"

一、菜单函数 Menu()

用于输出设计好的菜单界面。

voidmenu()

{
    system("color97");//设置默认的控制台前景和背景颜色

printf("************************************************************\n");

printf("************【桂林信息科技学院学生信息管理系统】************\n");

printf("************************************************************\n");

printf("--------------------------------\n");

printf("|1.录入信息 |\n");

printf("--------------------------------\n");

printf("|2.删除信息 |\n");

printf("--------------------------------\n");

printf("|3.查找信息 |\n");

printf("--------------------------------\n");

printf("|4.浏览信息 |\n");

printf("--------------------------------\n");

printf("|5.修改信息 |\n");

printf("--------------------------------\n");

printf("|0.退出系统 |\n");

printf("--------------------------------\n");

printf("***********************************************************\n");

printf("----------→ 请按下相应的数字键选择功能 ←----------\n");

printf("(madeby 黄梓芫版本 V0.3)\n");

printf("***********************************************************\n");

}

二、创建链表

链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用。链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节点。链表都有一个头指针,一般以 head 来表示,存放的是一个地址。链表中的节点分为两类,头结点和一般节点,头结点是没有数据域的。链表中每个节点都分为两部分,一个数据域,一个是指针域。说到这里你应该就明白了,链表就如同车链子一样,head 指向第一个元素:第一个元素又指向第二个元素;……,直到最后一个元素,该元素不再指向其它元素,它称为“表尾”,它的地址部分放一个“NULL”(表示“空地址”),链表到此结束。链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表的组成是由很多结点组成的。一个结点包含数据域和指针域,数据域用来存放数据,指针域负责指向其他结点,起到链接的作用。

创建头结点。(命名为:head)

在创建一个结点用来保存每次插入的结点.(命名为:p)

循环创建一般结点。(命名为:s)

将创建的结点与已有的结点链接起来

遍历链表,输出数据。

structNode*list=createList();

(详见下文头文件中的 createLis 函数介绍)

三、功能选择 KeyDown()

voidkeyDown()

{

- {
- intchoice=0;
- structstudentdata;
- structNode*pMove=NULL;
- scanf("%d",&choice);
- switch(choice)
- {
  -

0 退出系统:

case0:

- printf("---已退出---");
- system("pause");
- exit(0);
- break;

1 录入信息:

case1:

- printf("------------【录入信息】------------\n");
- //插入链表
- printf("请输入姓名,年龄,性别,电话:");
- fflush(stdin);//清空缓存区
- scanf("%s%d%s%s",data.name,&data.age,data.sex,data.tel);
- insertNodeByHead(list,data);
- break;

2 删除信息:

case2:

- printf("------------【删除信息】------------\n");
- printf("请输入需删除的学生姓名:");
- scanf("%s",data.name);
- deleteAppoinNode(list,data.name);
- break;

3 查找信息:

case3:

- printf("------------【查找信息】------------\n");
- printf("请输入需查找的学生姓名:");
- scanf("%s",data.name);
- pMove=searchInfoByData(list,data.name);
- if(pMove==NULL)
- {
- printf("未找到相关信息,无法删除!\n");
- system("pause");
- }
- else
- {
- printf("姓名\t 年龄\t 性别\t 电话\n");

printf("%s\t%d\t%s\t%s\n",pMove->data.name,pMove->data.age,pMove->data.sex,pMove->data.tel);

}

break;

4 浏览信息:

case4:

- printf("------------【浏览信息】------------\n");
- printList(list);
- break;

5 修改信息:

case5:

- printf("------------【修改信息】------------\n");
- //修改学生信息
- printf("请输入需修改的学生姓名:");
- scanf("%s",data.name);
- pMove=searchInfoByData(list,data.name);
- if(pMove==NULL)
- {
- printf("未找到相关信息,无法修改!\n");
- system("pause");
- }
- else
- {
- printf("姓名\t 年龄\t 性别\t 电话\n");

printf("%s\t%d\t%s\t%s\n",pMove->data.name,pMove->data.age,pMove->data.sex,pMove->data.tel);

-

- system("cls");
- printf("修改姓名----1\n");
- printf("修改年龄----2\n");
- printf("修改性别----3\n");
- printf("修改电话----4\n");
  -
- printf("请输入要修改的信息:");
- scanf("%d",&choice);
  -
- switch(choice)
- {

case1:

- printf("请输入姓名:");
- scanf("%s",&pMove->data.name);
- break;

case2:

- printf("请输入年龄:");
- scanf("%s",&pMove->data.age);
- break;

case3:

- printf("请输入性别:");
- scanf("%d",&pMove->data.sex);
- break;

case4:

- printf("请输入电话:");
- scanf("%d",&pMove->data.tel);
- break;
- }
- printf("是否继续修改学生信息?(y-1/n-0)\n");
- scanf("%d",&choice);
- if(choice==0)
- {
- break;
- }
- }

修改后打印:


printf("姓名\t年龄\t性别\t电话\n");

printf("%s\t%d\t%s\t%s\n",pMove->data.name,pMove->data.age,pMove->data.sex,pMove->data.tel);

break;

default:

printf("选择错误!请重新输入!\n");

system("pause");

break;

}

同步操作到文件:

}

writeInfoToFile(list,"学生信息.txt");

}

四、主函数 main()

intmain()
{
    - readInfoFromFile(list,"学生信息.txt");
- while(1)
- {
- menu();
- keyDown();
- system("pause");
- system("cls");
- }
- system("pause");
- return0;

```c++
}
```

头文件功能描述

```c++
myList.h
```

1 标准 io 库,用于 scanf, printf 标准输入输出

```c++
# include<stdio.h>
```

2 用于 malloc, free 内存申请及释放

```c++
# include<stdlib.h>
```

3 字符串链接函数

```c++
# include<string.h>
```

4 定义名为 student 的一个结构体类型

structstudent

```c++
{
```

- charname[20];
- intage;
- charsex[5];
- chartel[20];

```c++
};
```

5 定义了 Node 类型的结构体

structNode

```c++
{
```

structstudentdata;

structNode*next;

};
structstudent;//存放数据
struct node  *next; //地址域

6 创建链表

内存分配

Malloc 函数: (void *)malloc(int size)

malloc 函数的返回值是一个 void 类型的指针,参数为 int 类型数据,即申请分配的内存大小,单位是 byte。内存分配成功之后,malloc 函数返回这块内存的首地址。需要一个指针来接收这个地址,但由于函数的返回值是 void *类型,所以必须强制转换成你所要接收的类型,也就是说,内存将要用来存储什么类型的数据。同样在堆上分配的地址空间并没有赋予名字,也就是说堆上的内存都是以匿名访问的形式进行。在使用 malloc 函数时应注意函数的返回值是不是一个可用的地址,也就是说要判定堆上的空间是否被分配成功,若失败,函数返回的时 NULL。

————————————————

structNode*createList()
{
- structNode*headNode=(structNode*)malloc(sizeof(structNode));
- headNode->next=NULL;
- returnheadNode;
}

一个节点就像火车的一节车厢, data 是车厢里面的东西, next 相当于一个钩子, 用于将车厢之间的连接起来

7 创建节点 cteateNode

structNode*cteateNode(structstudentdata)
{
    - structNode*newNode=(structNode*)malloc(sizeof(structNode));
- newNode->data=data;
- newNode->next=NULL;
- returnnewNode;

```c++
}
```

8 插入节点(此处使用表头法插入)insertNodeByHead

voidinsertNodeByHead(structNode*headNode,structstudentdata)

```c++
{
```

- structNode*newNode=cteateNode(data);
- newNode->next=headNode->next;
- headNode->next=newNode;

}

插入节点就是用插入前节点的指针域链接上插入节点的数据域,再把插入节点的指针域链接上插入后节点的数据域。根据图,插入节点也就是:e->next = head->next; head->next = e;

9 删除节点 deleteAppoinNode

voiddeleteAppoinNode(structNode*headNode,char*name)

{
    - structNode*posNode=headNode->next;
- structNode*posFrontNode=headNode;
- if(posNode==NULL)
- {
- printf("数据为空,无法删除!\n");
- return;
- }
- while(strcmp(posNode->data.name,name))
- {
- posFrontNode=posNode;
- posNode=posFrontNode->next;
- if(posNode==NULL)
- {
- printf("未找到指定位置无法删除!\n");
- return;
- }
- }
- posFrontNode->next=posNode->next;
- free(posNode);

}
```
{
    - structNode*posNode=headNode->next;
- structNode*posFrontNode=headNode;
- if(posNode==NULL)
- {
- printf("数据为空,无法删除!\n");
- return;
- }
- while(strcmp(posNode->data.name,name))
- {
- posFrontNode=posNode;
- posNode=posFrontNode->next;
- if(posNode==NULL)
- {
- printf("未找到指定位置无法删除!\n");
- return;
- }
- }
- posFrontNode->next=posNode->next;
- free(posNode);

}

删除链表的元素也就是把前节点的指针域越过要删除的节点指向下下个节点。即:p->next = q->next;然后放出 q 节点的空间,即 free(q);

遍历链表查找 searchInfoByData

获取链表第 i 个数据的算法思路:

声明一个结点 p 指向链表第一个结点,初始化 j 从 1 开始;

当 j<i 时,就遍历链表,让 p 的指针向后移动,不断指向下一个结点,j 累加 1;

若到链表末尾 p 为空,则说明第 i 个元素不存在;

否则查找成功,返回结点 p 的数据;

structNode*searchInfoByData(structNode*headNode,char*name)

{
structNode*pMove=headNode->next;

if(pMove==NULL)

returnNULL;

while(strcmp(pMove->data.name,name))

{

pMove=pMove->next;

}

returnpMove;
}
{
    structNode*pMove=headNode->next;
if(pMove==NULL)
returnNULL;
while(strcmp(pMove->data.name,name))
{
pMove=pMove->next;
}
returnpMove;
}

链表的存储 readInfoFromFile

Fopen()函数:

FILE *fp = fopen(“demo.txt”, “r”);

fopen() 会获取文件信息,包括文件名、文件状态、当前读写位置等,并将这些信息保存到一个 FILE 类型的结构体变量中,然后将该变量的地址返回。

“r”

表示以“只读”方式打开当前目录下的 demo.txt 文件,并使 fp 指向该文件,这样就可以通过 fp 来操作 学生信息.txt 了。fp 通常被称为文件指针。

打开文件出错时,fopen() 将返回一个空指针,也就是 NULL,我们可以利用这一点来判断文件是否打开成功,

“w+”
以“写入/更新”方式打开文件,相当于 w 和 r+ 叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。

voidreadInfoFromFile(structNode*headNode,char*fileName)

```c++
{
    - FILE*fp;//文件指针
- structstudentdata;
- fp=fopen(fileName,"r");
- if(fp==NULL)
- {
- fp=fopen(fileName,"w+");
- }
- //2 读文件

while(fscanf(fp,"%s\t%d\t%s\t%s\n",data.name,&data.age,data.sex,data.tel)!=EOF)

- {
- insertNodeByHead(headNode,data);
- }
- //关闭文件
- fclose(fp);

}

- 链表的读取 writeInfoToFile
- “w”
  以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)
- voidwriteInfoToFile(structNode*headNode,char*fileName)

{

- FILE*fp;
- fp=fopen(fileName,"w");
- if(fp==NULL)
- {
- printf("文件写错误");
- return;
- }
- structNode*pMove=headNode->next;
- while(pMove)
- {

fprintf(fp,"%s\t%d\t%s\t%s\n",pMove->data.name,pMove->data.age,pMove->data.sex,pMove->data.tel);

- pMove=pMove->next;
- }
- fclose(fp);


}

打印链表 printList

voidprintList(structNode*headNode)

{

- structNode*pMove=headNode->next;
- printf("姓名\t 年龄\t 性别\t 电话\n");
- while(pMove)
- {

printf("%s\t%d\t%s\t%s\n",pMove->data.name,pMove->data.age,pMove->data.sex,pMove->data.tel);

- pMove=pMove->next;
- }
- printf("\n");

}
```
{
    - FILE*fp;//文件指针
- structstudentdata;
- fp=fopen(fileName,"r");
- if(fp==NULL)
- {
- fp=fopen(fileName,"w+");
- }
- //2 读文件

while(fscanf(fp,"%s\t%d\t%s\t%s\n",data.name,&data.age,data.sex,data.tel)!=EOF)

- {
- insertNodeByHead(headNode,data);
- }
- //关闭文件
- fclose(fp);

}

- 链表的读取 writeInfoToFile
- “w”
  以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)
- voidwriteInfoToFile(structNode*headNode,char*fileName)

{

- FILE*fp;
- fp=fopen(fileName,"w");
- if(fp==NULL)
- {
- printf("文件写错误");
- return;
- }
- structNode*pMove=headNode->next;
- while(pMove)
- {

fprintf(fp,"%s\t%d\t%s\t%s\n",pMove->data.name,pMove->data.age,pMove->data.sex,pMove->data.tel);

- pMove=pMove->next;
- }
- fclose(fp);


}

打印链表 printList

voidprintList(structNode*headNode)

{

- structNode*pMove=headNode->next;
- printf("姓名\t 年龄\t 性别\t 电话\n");
- while(pMove)
- {

printf("%s\t%d\t%s\t%s\n",pMove->data.name,pMove->data.age,pMove->data.sex,pMove->data.tel);

- pMove=pMove->next;
- }
- printf("\n");

}

边遍历边输出

程序运行截图

录入信息界面

删除信息界面

查找信息界面

浏览信息界面

修改信息界面

退出系统界面

♻️ 资源

在这里插入图片描述

大小: 801KB
➡️ 资源下载:https://download.csdn.net/download/s1t16/87430295
注:如当前文章或代码侵犯了您的权益,请私信作者删除!