赶紧进来看看---C语言实现学生信息管理系统(2.0动态内存版)

news2024/11/15 22:38:38

本文介绍了将学生信息管理系统静态版本改造为动态内存版本,主要涉及改造思路,枚举类型的使用,动态内存函数和柔性数组的使用,动手写程序才能使基础知识更为牢固…(文章最后有源码展示)

学生信息管理系统1.0静态版->学生信息管理系统2.0动态内存版

c语言实现学生信息管理系统---2.0动态内存版

  • 一.学生信息管理系统---静态版本的特点
  • 二.设计学生信息管理系统--动态内存版本
    • 1.为什么要设计动态内存版本
    • 2.动态内存版本设计思路
  • 三.设计学生信息管理系统--动态内存版
    • 1.用枚举类型改造功能选项
    • 2.设计动态内存结构
    • 3.开辟动态内存空间和初始化
    • 4.设计动态增容自定义函数
    • 5.改造增加学生信息自定义函数
    • 6.改造排序学生信息自定义函数
  • 四.学生信息管理系统(动态内存版)源码展示
    • 1.test.c源文件
    • 2.stu.h头文件
    • 3.stu.c源文件
  • 五.总结

一.学生信息管理系统—静态版本的特点

在之前博客中用c语言实现了静态版本的学生信息管理系统,
所谓静态就是能够容纳学生信息个数的最大容量编写代码时就已经确定,即编译代码运行程序时会根据所编写的代码一次性申请开辟对应的空间 ,
这种空间开辟的方法特点:开辟空间快捷方便,编写代码过程简洁,执行效率高

二.设计学生信息管理系统–动态内存版本

下面对静态版本的缺点进行改造的动态内存版设计介绍

1.为什么要设计动态内存版本

静态版本虽然方便,但是,什么东西都不会是一尘不变的,
实际情况千变万化,静态版本虽然简单快捷执行效率高,但是也有很多致命弊端如:
1.一次开辟的空间大小是固定的无法改变
2.无法确定程序运行过程中实际具体需要多大的空间
3.开始设定的容纳学生信息空间太小在实际运行中可能存放学生信息多会造成溢出,此时多出来的学生信息将无法存储!!!
4.开始设定的容纳学生信息空间太大,在实际运行中存放学生信息数量少时,所开辟的空间剩余太多的空余的空间被浪费掉…
而空间是有限在资源,静态空间满足不了实际程序需求
因此我们需要设计一种以时间换空间的方法即动态内存增长版来解决遇到的问题…

2.动态内存版本设计思路

动态内存版本设计主要解决静态版本遇到的问题…
1.首先最大容量一开始可以设定小一点,可以避免学生信息一开始数量少可以节省更多空间
2.设定一个增长容量数SZ,每次容量满的时候自动往后增加SZ个空间,以供后面继续添加学生信息
3.动态内存版本需要内存空间能够动态变化,空间需要在堆区上申请开辟,需要用到动态内存函数…

三.设计学生信息管理系统–动态内存版

下面是对静态版本改造为动态版本的过程…(主要用到了动态内存增长函数 和柔性数组的使用具体知识点在这篇博客中介绍到 ->动态内存管理)

1.用枚举类型改造功能选项

在这篇博客->自定义类型:枚举和联合体类型 中讲到了枚举类型,在改造静态版本时应用以下枚举类型…

在这里插入图片描述

在上面图中可以看到在switch case的分支中我们使用了数字0-7对应着不同的功能,但是在实际开始编写过程中,数字表达的含义是我们自己赋予的,那这样还不如在编写前设定枚举类型,将所有对应的数字选项都替换成枚举常量来表示…

enum option //声明 枚举类型 option 对应的枚举常量为实现 管理系统 菜单功能的选项名称  枚举常量不能同名
{
	EXIT,  //退出
	ADD,   //添加
	DROP,   //删除
	FIND,   //查找
	MODIFY, //修改
	TOTAL, //统计
	PRINT, //打印
	SORT,  //排序

};
enum option1   // 修改菜单的选择项
{
	END,   //结束修改
	MODALL, //修改整条信息
	MODONE  //修改某一项信息
};
enum option2  //修改单项的菜单选择项
{
	RETURN,   //返回上一层
	MODSNO, //修改学号
	MODNAME, //修改姓名
	MODSEX,  //修改性别
	MODAGE, //修改年龄
	MODROOM, //修改寝室号
	MODNUMBER, //修改电话号码
	MODADDRESS //修改地址
};
enum option3 //统计学生个数菜单 选择项
{
	ENDCOUNT,  //结束统计
	COUNTALL,  //统计所有学生信息
	COUNTAGE, // 按年龄统计
	COUNTROOM, //统计寝室号
	COUNTSEX //按性别统计
};

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上面代码在头文件stu.h里根据要选择的对应选项设计了多个枚举类型,每个枚举类型里的枚举常量对应着选项数字的功能,这样在设计选项对应选项功能时能更直观的表达对应的功能有对应类型检查后更清晰直观后续调试除错增加对应类型的功能时在对应枚举类型里添加对应枚举常量即可…

2.设计动态内存结构

根据上面的动态内存设计思路, 最大容量应该是能动态变化的,而每次容量满时增长的大小是固定不变的.

对存放学生信息的结构体进行改造↓

在这里插入图片描述

改造后↓

typedef struct studentmanagement
{
	
	int sz;       //记录当前有效的学生信息个数
	int capcity;   //记录存放学生信息的最大容量
	studata stu[]; //柔性数组 用于不确定数组元素个数 实现动态增长
}stumgt;

增加了一个 capcity 表示存放学生信息的最大容量,将stu[100]固定的100个大小改为了柔性数组的形式stu[]放在的最后

设计初始的容量大小和每次增容的大小↓

#define SZ 6         //每次增加的容量个数
#define CAPCITY 3    //一开始设置的容量

用#define宏定义 设定 SZ为6 表示每次增容的个数 CAPCITY为3 表示初始时容量的大小
用宏定义 在后续想更改初始化容量或者增容大小可以直接更改对应宏后面的常量数可维护性更高

3.开辟动态内存空间和初始化

开辟静态空间的方式(直接在栈区申请固定空间)↓

stumgt stus;

改造后开辟动态内存方式↓

	stumgt *stus=(stumgt *)calloc(1,sizeof(stumgt)+sizeof(studata)*CAPCITY);//在堆区创建stumgt类型大小的空间给柔性数组分配的空间 

在堆区申请空间用到calloc动态内存开辟函数,表示开辟1个 sizeof(stumgt)+sizeof(studata)*CAPCITY)大小的空间,并且将空间都初始化为0…
根据柔性数组的使用 sizeof(stumgt) 表示的是非柔性数组以外的空间大小 sizeof(studata)*CAPCITY)表示柔性数组内部的大小,即CAPCITY个学生信息容量大小

在这里插入图片描述

改造后结构传参时直接传指针变量stus即可

初始化学生信息管理结构体变量改造前↓

void initstus(stumgt* pstus)//初始化学生管理系统这个结果体变量
{
	assert(pstus != NULL);
	memset(pstus, 0, sizeof(stumgt));
}

初始化学生信息管理结构体变量改造后↓

void initstus(stumgt* pstus)//初始化学生管理系统这个结构体变量
{
	assert(pstus != NULL);
	pstus->capcity = CAPCITY;        //将最大容量设置为初始化容量大小
}

改造后 只需学生信息管理结构体中的最大容量成员变量初始化为 设置的初始化容量大小

4.设计动态增容自定义函数

在初始化的容量满后需要扩容,此时封装一个扩容函数实现对动态内存增容

函数定义↓

addcapcity(&pstus);

函数定义↓

static void addcapcity(stumgt** pstus)
{
	stumgt* tmp=(stumgt*)realloc(*pstus, sizeof(stumgt) + sizeof(studata) * ((*pstus)->capcity + SZ));    //在堆区创建stumgt类型大小的空间给柔性数组分配的空间 
	if (tmp == NULL)    // 增容失败 显示错误并返回
	{
		perror("realloc");
		return;
	}
	else
	{
		*pstus = tmp;     // 将重新开辟的空间地址赋给main函数里的pstus指针变量
		(* pstus)->capcity += SZ;             //最大容量增容 SZ 个
	}
}

注意:动态增容函数的实参传参需要是二级指针,因为 realloc重置动态空间函数使用时可能在堆区另外一块区域重新开辟空间返回重新开辟的空间指针,而需要将该指针传stus指针变量里则需要二级指针才能实现,否则只能对形参临时开辟的局部变量赋值…

如果增容失败会返回空指针 经过判断后显示增容失败信息然后返回

增容操作每次增加当前最大容量加SZ个大小后将最大容量增加SZ个供下次继续增容

5.改造增加学生信息自定义函数

有了增容函数后,增加学生信息就不再仅限于最后不能超过固定的学生个数了

改造添加学生信息函数前↓

void addstu(stumgt* pstus)
{
	assert(pstus != NULL);
	if (pstus->sz == 100)
	{
		printf("学生信息已满,无法新增学生信息\n");
		return;
	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号\n", tmp);
			return;
		}

		strcpy(pstus->stu[pstus->sz].sno, tmp);  //不存在重复时将当前信息拷贝作为学生学号信息
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[pstus->sz].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[pstus->sz].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[pstus->sz].age); //注意年龄这里要&其他的都是地址
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[pstus->sz].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[pstus->sz].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[pstus->sz].add);
		pstus->sz++;
		system("cls");
		printf("添加成功\n");
	}
}

改造添加学生信息函数后↓

void addstu(stumgt* pstus)
{
	assert(pstus != NULL);
	if (pstus->sz ==pstus-> capcity)             // 当sz有效个数等于最大容量时进入分支
	{
		addcapcity(&pstus);                 // 调用增容函数
		printf("存储空间已满..增容中...\n");   // 制造增容效果
		Sleep(3000);                            //睡眠3秒
		
	}
	if (pstus->sz == pstus->capcity)          //  当调用增容后 有效个数还是等于最大容量时则表示增容失败了 此时进入该分支  否则则增容成功 进行后续添加学生信息操作
	{
		printf("容量已满,无法再添加学生信息\n");
		return;

	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号\n", tmp);
			return;
		}

		strcpy(pstus->stu[pstus->sz].sno, tmp);  //不存在重复时将当前信息拷贝作为学生学号信息
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[pstus->sz].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[pstus->sz].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[pstus->sz].age); //注意年龄这里要&其他的都是地址
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[pstus->sz].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[pstus->sz].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[pstus->sz].add);
		pstus->sz++;
		system("cls");
		printf("添加成功\n");
	}
}

经过改造后,学生信息容量不局限于是100个而是可以动态增容…

6.改造排序学生信息自定义函数

排序学生信息函数改造前↓

void sortstu(stumgt* pstus) //  升序排序所有学生记录的函数
{
	if (pstus->sz == 0)   //判断排序时是否为空
	{
		printf("当前学生记录为空,无法排序\n");
		return;
	}
	qsort(pstus, pstus->sz, sizeof(studata), cmp_sno);
	printf("已按学号完成升序排序\n");
}

排序学生信息函数改造后↓

void sortstu(stumgt* pstus) //  升序排序所有学生记录的函数
{
	if (pstus->sz == 0)   //判断排序时是否为空
	{
		printf("当前学生记录为空,无法排序\n");
		return;
	}
	qsort(pstus->stu, pstus->sz, sizeof(studata), cmp_sno);    //
	printf("已按学号完成升序排序\n");
}

静态版本学生信息管理结构体成员变量位置不同,排序是对学生信息数组进行排序,所以要将第一个元素改为指向学生数组.

四.学生信息管理系统(动态内存版)源码展示

1.test.c源文件

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 6031)
#include"stu.h"


int main()
{
	stumgt *stus=(stumgt *)calloc(1,sizeof(stumgt)+sizeof(studata)*CAPCITY);//在堆区创建stumgt类型大小的空间给柔性数组分配的空间 

	int i = 0;
	initstus(stus);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &i);
		switch (i)
		{
		case ADD:
			addstu(stus);
			break;
		case DROP:
			dropstu(stus);
			break;
		case FIND:
			search(stus);
			break;
		case MODIFY:
			modifystu(stus);
			break;
		case TOTAL:
			countstu(stus);
			break;
		case PRINT:
			pritstus(stus);
			break;
		case SORT:
			sortstu(stus);
			break;
		case EXIT:
			printf("已退出学生信息管理系统\n");
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (i);
	return 0;
}

2.stu.h头文件

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>
#define SZ 6         //每次增加的容量个数
#define CAPCITY 3    //一开始设置的容量
typedef struct studentdata
{
	char sno[20];  //学号
	char name[20]; //名字
	char sex[5]; //性别
	int age;  //年龄
	char roomnum[20];// 寝室号
	char number[12];// 电话号码
	char add[20];  //地址
}studata;

typedef struct studentmanagement
{
	
	int sz;       //记录当前有效的学生信息个数
	int capcity;   //记录存放学生信息的最大容量
	studata stu[]; //柔性数组 用于不确定数组元素个数 实现动态增长
}stumgt;
enum option //声明 枚举类型 option 对应的枚举常量为实现 管理系统 菜单功能的选项名称  枚举常量不能同名
{
	EXIT,  //退出
	ADD,   //添加
	DROP,   //删除
	FIND,   //查找
	MODIFY, //修改
	TOTAL, //统计
	PRINT, //打印
	SORT,  //排序

};
enum option1   // 修改菜单的选择项
{
	END,   //结束修改
	MODALL, //修改整条信息
	MODONE  //修改某一项信息
};
enum option2  //修改单项的菜单选择项
{
	RETURN,   //返回上一层
	MODSNO, //修改学号
	MODNAME, //修改姓名
	MODSEX,  //修改性别
	MODAGE, //修改年龄
	MODROOM, //修改寝室号
	MODNUMBER, //修改电话号码
	MODADDRESS //修改地址
};
enum option3 //统计学生个数菜单 选择项
{
	ENDCOUNT,  //结束统计
	COUNTALL,  //统计所有学生信息
	COUNTAGE, // 按年龄统计
	COUNTROOM, //统计寝室号
	COUNTSEX //按性别统计
};
void menu();
//void initstus(stumgt* pstus);
void addstu(stumgt* pstus);
void pritstus(stumgt* pstus);
void dropstu(stumgt* pstus);
void search(stumgt* pstus);
void modifystu(stumgt* pstus);
void countstu(stumgt* pstus);
void sortstu(stumgt* pstus);

3.stu.c源文件

#define _CRT_SECURE_NO_WARNINGS  
#pragma warning(disable : 6031) //忽略返回值
#include"stu.h"

void menu()
{
	printf("           欢迎使用学生信息管理系统              \n");
	printf("*************************************************\n");
	printf("#  1.添加新的学生信息    2.删除指定学生信息     #\n");
	printf("#  3.查找指定学生信息    4.修改指定学生信息     #\n");
	printf("#  5.分类统计学生个数    6.显示所有学生信息     #\n");
	printf("#  7.排序所有学生信息    0.退出学生管理系统     #\n");
	printf("*************************************************\n");
}
static void modifymenu1()
{
	printf("*************************************************\n");
	printf("#  1.修改整条学生信息    2.修改某项学生信息     #\n");
	printf("#               0.退出修改菜单                  #\n");
	printf("*************************************************\n");
}

static void modifymenu2()
{
	printf("*************************************************\n");
	printf("#       1.修改学生学号    2.修改学生姓名        #\n");
	printf("#       3.修改学生性别    4.修改学生年龄        #\n");
	printf("#       5,修改学生寝室号  6.修改学生电话号码    #\n");
	printf("#       7.修改学生家庭住址 0.返回上一步修改     #\n");
	printf("*************************************************\n");
}
static void countmenu()
{
	printf("*************************************************\n");
	printf("#  1.统计所有学生个数    2.按年龄统计学生个数   #\n");
	printf("#  3.按寝室号统计学生个数4.按性别统计学生个数   #\n");
	printf("#                  0.结束统计                   #\n");
	printf("*************************************************\n");
}

void initstus(stumgt* pstus)//初始化学生管理系统这个结果体变量
{
	assert(pstus != NULL);
	pstus->capcity = CAPCITY;        //  //将最大容量设置为初始化容量大小
}
static void addcapcity(stumgt** pstus)
{
	stumgt* tmp=(stumgt*)realloc(*pstus, sizeof(stumgt) + sizeof(studata) * ((*pstus)->capcity + SZ));    //在堆区创建stumgt类型大小的空间给柔性数组分配的空间 
	if (tmp == NULL)    // 增容失败 显示错误并返回
	{
		perror("realloc");
		return;
	}
	else
	{
		*pstus = tmp;     //
		(* pstus)->capcity += SZ;             //最大容量增容 SZ 个
	}
	

}
static int is_repeat(stumgt* pstus, char tmp[]) //判断学号信息是否重复
{
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].sno) == 0)
		{
			return 1;
		}
	}
	return 0;
}
void addstu(stumgt* pstus)
{
	assert(pstus != NULL);
	if (pstus->sz ==pstus-> capcity)             // 当sz有效个数等于最大容量时进入分支
	{
		addcapcity(&pstus);                 // 调用增容函数
		printf("存储空间已满..增容中...\n");   // 制造增容效果
		Sleep(3000);                            //睡眠3秒
		
	}
	if (pstus->sz == pstus->capcity)          //  当调用增容后 有效个数还是等于最大容量时则表示增容失败了 此时进入该分支  否则则增容成功 进行后续添加学生信息操作
	{
		printf("容量已满,无法再添加学生信息\n");
		return;

	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号\n", tmp);
			return;
		}

		strcpy(pstus->stu[pstus->sz].sno, tmp);  //不存在重复时将当前信息拷贝作为学生学号信息
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[pstus->sz].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[pstus->sz].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[pstus->sz].age); //注意年龄这里要&其他的都是地址
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[pstus->sz].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[pstus->sz].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[pstus->sz].add);
		pstus->sz++;
		system("cls");
		printf("添加成功\n");
	}
}

void pritstus(stumgt* pstus)   //打印所有信息
{
	assert(pstus != NULL);
	system("cls");   //输出所有信息前先清屏一次
	printf("%-10s\t%-10s\t%-5s\t%-10s\t%-10s\t%-12s\t%-20s\t\n", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");//先设置好对应字段格式
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		printf("%-10s\t%-10s\t%-5s\t%-10d\t%-10s\t%-12s\t%-20s\t\n",  //按设置好的格式对其打印数据
			pstus->stu[i].sno,
			pstus->stu[i].name,
			pstus->stu[i].sex,
			pstus->stu[i].age,
			pstus->stu[i].roomnum,
			pstus->stu[i].number,
			pstus->stu[i].add);
	}
}
static int findstu(stumgt* pstus, char tmp[])  //封装的内部 查找学生学号信息的函数 找到返回对应的数组元素下标 没找到返回-1
{
	assert(pstus != NULL);
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].sno) == 0)
			return i;
	}
	return -1;
}
void dropstu(stumgt* pstus)  //删除学生信息
{
	assert(pstus != NULL);
	if (pstus->sz == 0)   //判断学生记录是否为空
	{
		printf("当前没有学生信息,无法删除\n");
		return;
	}
	char tmp[20] = { 0 };
	printf("输入要删除的学生的学号信息:");
	scanf("%s", tmp);
	int num = findstu(pstus, tmp);  //使用内部封装的查找函数
	if (num == -1)
	{
		printf("没有找到要删除的学生信息\n");
		return;
	}
	else
	{
		int i = 0;
		for (i = num + 1; i < pstus->sz; i++)
		{
			pstus->stu[i - 1] = pstus->stu[i];
		}
		pstus->sz--;
		printf("已删除学号为%s的学生成员\n", tmp);
	}
}
void search(stumgt* pstus)  //查找学生信息的函数  以名字作为查找标准
{
	assert(pstus != NULL);
	char tmp[20] = { 0 };
	printf("请输入要查找的学生姓名:");
	scanf("%s", tmp);
	system("cls");
	printf("已查询到以下姓名为%s的学生信息↓↓↓\n", tmp);  //找到后按设置的对齐格式输出查找的信息
	printf("%-10s\t%-10s\t%-5s\t%-10s\t%-10s\t%-12s\t%-20s\t\n", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].name) == 0)
		{
			printf("%-10s\t%-10s\t%-5s\t%-10d\t%-10s\t%-12s\t%-20s\t\n",
				pstus->stu[i].sno,
				pstus->stu[i].name,
				pstus->stu[i].sex,
				pstus->stu[i].age,
				pstus->stu[i].roomnum,
				pstus->stu[i].number,
				pstus->stu[i].add);
		}
	}
}
static void modifyall(stumgt* pstus)  //内部封装的修改整条学生信息的函数
{
	char tmp[20] = { 0 };
	printf("请输入要修改的学生学号信息:");
	scanf("%s", tmp);

	int num = findstu(pstus, tmp);  //先判断是否存在要修改的学生信息
	if (num == -1)
	{
		printf("未找到要修改的学生信息\n");
		return;
	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号\n", tmp);
			return;
		}

		strcpy(pstus->stu[num].sno, tmp);  //修改后的学号在之前学生信息里没有重复的则将tmp的拷贝修改当前学生信息学号
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[num].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[num].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[num].age);
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[num].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[num].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[num].add);
		printf("修改成功\n");
	}
}
static void modifysno(stumgt* pstus, int num) //内部封装的单独修改学号的函数
{
	printf("你要将学号修改为:");
	char tmp[20] = { 0 };
	scanf("%s", tmp);
	if (is_repeat(pstus, tmp))
	{
		printf("修改失败,不能输入已有的学号\n");
		return;
	}
	else
	{
		strcpy(pstus->stu[num].sno, tmp);
		printf("修改成功\n");
	}

}
static void modifyname(stumgt* pstus, int num)//内部封装的单独修改名字的函数
{
	printf("你要将名字修改为:");
	scanf("%s", pstus->stu[num].name);
	printf("修改成功\n");
}
static void modifysex(stumgt* pstus, int num)//内部封装的单独修改性别的函数
{
	printf("你要将性别修改为:");
	scanf("%s", pstus->stu[num].sex);
	printf("修改成功\n");
}
static void modifyage(stumgt* pstus, int num)//内部封装的单独修改年龄的函数
{
	printf("你要将年龄修改为:");
	scanf("%d", &pstus->stu[num].age);
	printf("修改成功\n");
}
static void modifyroomnum(stumgt* pstus, int num)//内部封装的单独修改寝室号的函数
{
	printf("你要将寝室号修改为:");
	scanf("%s", pstus->stu[num].roomnum);
	printf("修改成功\n");
}
static void modifynumber(stumgt* pstus, int num)//内部封装的单独修改电话号码的函数
{
	printf("你要将电话号码修改为:");
	scanf("%s", pstus->stu[num].number);
	printf("修改成功\n");
}
static void modifyadd(stumgt* pstus, int num)//内部封装的单独修改地址的函数
{
	printf("你要将地址修改为:");
	scanf("%s", pstus->stu[num].add);
	printf("修改成功\n");
}

static void modifyone(stumgt* pstus)  //内部封装修改整条学生信息里的某项信息函数
{
	char tmp[20] = { 0 };
	printf("请输入要修改的学生学号信息:");
	scanf("%s", tmp);
	int num = findstu(pstus, tmp);  //先判断是否存在该学生信息
	if (num == -1)
	{
		printf("未找到要修改的学生信息\n");
		return;
	}
	else
	{
		int input = 0;
		modifymenu2();  //下面为函数指针数组将一个0和上面7个封装好的修改对应学生信息的函数指针作为数组初始化信息(0是为了方便下标对其选项)
		void(*mod[8])(stumgt*, int) = { 0,modifysno,modifyname,modifysex,modifyage,modifyroomnum,modifynumber,modifyadd };
		printf("请选择修改的内容:");
		do
		{
			scanf("%d", &input);
			if (input >= 8 || input < 0)
			{
				printf("非法输入,请重新选择\n");

			}
			else if (input == 0)
			{
				printf("退回上一层修改菜单\n");
			}
			else
				mod[input](pstus, num); //根据菜单对应input输入的值调用 数组里相对应的函数指针

		} while (input >= 8 || input < 0); //超出重新输入

	}
}
void modifystu(stumgt* pstus)  //修改学生信息的函数
{


	int input = 0;
	do
	{
		modifymenu1();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)//选择修改整条学生信息还是修改一条里某一项的学生信息
		{
		case MODALL:
			modifyall(pstus);
			break;
		case MODONE:
			modifyone(pstus);
			break;
		case END:
			printf("已结束修改操作\n");
			break;
		default:
			printf("非法输入,请重新输入\n");
		}

	} while (input);

}
static void countall(stumgt* pstus)  //内部封装的统计当前所有学生信息记录函数
{
	printf("已统计当前系统中有%d个学生\n", pstus->sz);
	return;
}
static void countage(stumgt* pstus)  //统计年龄范围内学生记录的个数
{
	int age1 = 0;
	int age2 = 0;
	int age = 0;
	printf("请输入两个数字将统计其范围内的年龄个数(如果两个数字相同则统计这个数字年龄的学生个数)");
	scanf("%d%d", &age1, &age2);
	int count = 0;
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		age = pstus->stu[i].age;
		if (age >= age1 && age <= age2)
		{
			count++;
		}
	}
	printf("在%d岁和%d岁之间的学生个数为%d\n", age1, age2, count);
	return;
}
static void countroom(stumgt* pstus) //统计 寝室号的个数
{
	char room[20] = { 0 };
	printf("请输入寝室号:");
	scanf("%s", room);
	int i = 0;
	int count = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(room, pstus->stu[i].roomnum) == 0)
		{
			count++;
		}
	}
	printf("寝室号为%s的寝室个数为%d个\n", room, count);
	return;
}
static countsex(stumgt* pstus)   //统计相同性别的学生个数
{
	char sex[5] = { 0 };
	printf("请输入要统计的性别:");
	scanf("%s", sex);
	int i = 0;
	int count = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(sex, pstus->stu[i].sex) == 0)
		{
			count++;
		}
	}
	printf("性别为%s的学生个数为:%d\n", sex, count);
}
void countstu(stumgt* pstus)  //统计学生信息的函数
{
	assert(pstus != NULL);
	system("cls");

	int input = 0;
	do
	{
		countmenu();
		printf("请选择统计方式:");
		scanf("%d", &input);
		switch (input)  //对应菜单输入input选择 跳转到上面封装的统计函数
		{
		case COUNTALL:
			countall(pstus);
			break;
		case COUNTAGE:
			countage(pstus);
			break;
		case COUNTROOM:
			countroom(pstus);
			break;
		case COUNTSEX:
			countsex(pstus);
			break;
		case ENDCOUNT:
			printf("已结束统计\n");
			break;
		default:
			printf("非法输入,请重新选择\n");
		}

	} while (input);
}
int cmp_sno(const studata stu1, const studata stu2) // 为qsort 函数设置的函数指针 用于比较两个元素的大小传给qsort
{
	return strcmp(stu1.sno, stu2.sno);    //比较两个学生里的学号大小 进行排序 这两个学生元素
}
void sortstu(stumgt* pstus) //  升序排序所有学生记录的函数
{
	if (pstus->sz == 0)   //判断排序时是否为空
	{
		printf("当前学生记录为空,无法排序\n");
		return;
	}
	qsort(pstus->stu, pstus->sz, sizeof(studata), cmp_sno);    //
	printf("已按学号完成升序排序\n");
}

五.总结

本篇博客实现了将学生信息管理系统静态版变为动态内存版本.主要涉及了枚举类型,动态内存增长函数和柔性数组的使用,动手敲代码才能使所学的知识更为牢固
博主在后续还会更新学生信息管理系统(3.0文件存储版本)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在python中使用ggplot2

python的ggplot2库:plotnine > 一.安装方法&#xff1a; pip install plotnine使用的编译器&#xff1a;pycharm 二.plotnine绘图 1.第一个图形 除了导包的操作不一致&#xff0c;其他类似 from plotnine import ggplot, geom_point, aes, stat_smooth, facet_wrap fr…

70.【JavaScript 6.0】

前端三要素1.前端三要素2.引入JavaScript3.JavaScript基本语法入门4.数据类型5.严格检查模式( use strict)6.Map和Set7.函数的定义和参数获取8.变量的作用域(局部 全局)-------> 和Java一样9.全局规范:10.方法的定义和调用11.内部对象1.Date--------->日期2.JSON--------…

自定义mybatis插件实现sql日志打印

自定义mybatis插件实现sql日志打印 mysql插件实现原理 官网的关键信息 参考文档 https://mybatis.org/mybatis-3/zh/configuration.html#plugins 官方文档 MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下&#xff0c;MyBatis 允许使用插件来拦截的方…

【JavaSE】一篇文章领悟Java运算符

前言&#xff1a; 作者简介&#xff1a;爱吃大白菜1132 人生格言:纸上得来终觉浅&#xff0c;绝知此事要躬行 如果文章知识点有错误的地方不吝赐教&#xff0c;和大家一起学习&#xff0c;一起进步&#xff01; 如果觉得博主文章还不错的话&#xff0c;希望三连支持&#xff01…

Java项目:超市管理系统(java+SSM+JSP+LayUI+jQ+Mysql)

源码获取&#xff1a;俺的博客首页 "资源" 里下载&#xff01; 项目介绍 本项目分为超级管理员、总经理、店长、员工等角色&#xff0c;超级管理员可添加修改删除角色并进行角色菜单配置&#xff1b; 超级管理员角色包含以下功能&#xff1a; 商品管理&#xff1a;添…

C语言高级-4栈

14天阅读挑战赛 目录 一、栈的原理 1、栈的定义 2、栈的应用 &#xff08;1&#xff09;选课问题 &#xff08;2&#xff09;旅游&#xff1a;怎么样把每个城市去且仅去一遍&#xff1f; &#xff08;3&#xff09;栈的使用场景 &#xff08;4&#xff09;思考&#xf…

C++多态之虚函数表详解及代码示例

引言 C相对其他面向对象语言来说&#xff0c;之所以灵活、高效。很大程度的占比在于其多态技术和模板技术。C虚函数表是支撑C多态的重要技术&#xff0c;它是C动态绑定技术的核心。 如果对多态还不了解的小伙伴&#xff0c;可以点这里C多态详解基础篇。 在不考虑继承的情况下…

Vue3 Hooks 模块化抽离

Vue3中的Hooks 其实就是业务逻辑的抽离&#xff0c;跟Vue2中mixin 本质上是一样的&#xff1a;将当前组件的业务逻辑抽离到一个公共的文件中&#xff0c;提高逻辑复用性&#xff0c;让当前组件看起来更加清爽&#xff0c;不太一样的地方是我们封装hooks 的时候一般是返回一个函…

如何不改动 GatewayWorker 依赖包下自定义协议

前言&#xff1a; GatewayWorker 是 Workerman 的一个框架&#xff0c;对应用层开发者更友好。GatewayWorker 多了一个网关&#xff0c;也就是 Gateway&#xff0c;负责与客户端连接&#xff0c;消息转发等。而自定义的协议&#xff0c;也就是 gateway 面向客户端提供服务的协议…

java毕业设计——基于java+JDBC+sqlserver的物业管理系统设计与实现(毕业论文+程序源码)——物业管理系统

基于javaJDBCsqlserver的物业管理系统设计与实现&#xff08;毕业论文程序源码&#xff09; 大家好&#xff0c;今天给大家介绍基于javaJDBCsqlserver的物业管理系统设计与实现&#xff0c;文章末尾附有本毕业设计的论文和源码下载地址哦。 文章目录&#xff1a; 基于javaJDB…

【H5微信授权】简单实现H5页面微信授权功能,微信开发者工具报错 系统错误,错误码-1,undefined解决办法【详细】

前言 最近写到了H5公众号&#xff0c;需要微信授权的功能。 这里记录一下授权的流程和踩了个坑 图片 授权代码执行后会跳转到授权的地方&#xff0c;没有授权的会有确认授权&#xff0c;授权过得会这样&#xff0c;直接自动登录&#xff0c;然后再跳转到中转页 授权流程 …

204 - 205.表的基本用法

表的基本操作 1.基本概念 1.1数据库和表的关系 每个数据库包含N张表&#xff0c;及表示在库中 1.2 表&#xff08;二维表&#xff09; 行和列组成&#xff0c;可以将复杂的数据保存在简单的表中 表中的每一行就是一条完整的记录 表中的列用于保存每条记录中特点的信息 2.…

【Redis】散列表(Hash)和列表(List)的运用和理解以及Hash和List应用场景对比详解

文章目录一. 散列表(hash)1.1 基本操作1.2 当value字符串的内容是数字时二.列表&#xff08;List&#xff09;2.1 基本操作三.Hash和List的应用场景3.1Hash的应用场景3.2List的应用场景一. 散列表(hash) Redis哈希是字符串类型字段和值的映射表。哈希特别适合存储对象。 Redis中…

mindspore.dataset的map问题

1、创建一个包含transform的自定义类并实例化 2. 类的实现如下&#xff1a; 请注意&#xff1a;在call函数中&#xff0c;我并没有调用init中定义的transform操作。 3. ImageFolder_forPretrain的定义如下。 在划红线的那行&#xff0c;出现错误。 错误信息&#xff1a; 疑问…

【Spark】spark-submit作业提交及参数设定

note 文章目录note一、Spark的常用启动方式1.1 local本地模式1.2 Standalone模式1.3 Spark on Yarn模式二、spark-submit 详细参数说明--master--deploy-mode--class--name--jars--packages--exclude-packages--repositories--py-files--files--conf PROPVALUE--properties-fil…

【趣学算法】Day3 贪心算法——背包问题

14天阅读挑战赛努力是为了不平庸~ 算法学习有些时候是枯燥的&#xff0c;这一次&#xff0c;让我们先人一步&#xff0c;趣学算法&#xff01; ❤️一名热爱Java的大一学生&#xff0c;希望与各位大佬共同学习进步❤️ &#x1f9d1;个人主页&#xff1a;周小末天天开心 各位大…

tomcat应用部署

目录 tomcta介绍 tomcat安装 每个目录的作用 端口 实验开始 安装&#xff0c;启动MySQL 创建数据库 更改数据库连接 项目导入tomcat和数据库查看 重启tomcat 访问应用 【注意】 tomcta介绍 Tomcat的是完全开源的 Tomcat的是免费的 Tomcat不支持EJB 应用范围&#xff1…

创造一个表格编辑距离指标

这个是我自研的&#xff0c; 与百度PaddleOCR的方式略有不同。 数据的格式&#xff1a; 相当于一个目标检测有两类&#xff0c;分别是table和cell。 在预测值和标签中要先把根据位置关系所有的cell划分到不同的table中。 另外cell标签中还有起止位置 比如 四个数字代表行和…

window10远程桌面控制Ubuntu系统

Windows操作系统作为全球使用最多的个人操作系统&#xff0c;在我们身边随处可见&#xff0c;但放眼各类电子设备的操作系统&#xff0c;windows并不是一家独大&#xff0c;服务器系统大多基于Linux系统开发、手机操作系统几乎都是安卓、更不用说还有苹果的iOS、树莓派、Ubuntu…

【MySQL高级篇】数据库到底是什么?一文带你快速上手MySQL

在学习JavaWeb过程中&#xff0c;数据库学习是不可或缺的。整个JavaWeb体系中&#xff0c;数据库部分用于储存和管理数据&#xff0c;而数据作为网页中非常重要的一部分&#xff0c;自然我们是有必要深入学习数据库的。 推荐学习专栏&#xff1a;Java编程 进阶之路 文章目录1. …