利用动态数组(堆)方式实现员工信息管理
头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _SInfo
{
int nNumb; //员工工号
char sName[20]; //姓名
float fSala; //工资
}SInfo;
typedef SInfo DATA;// SInfo
//extern DATA* g_pData; //共享变量 哪里都可以改
//私有变量 间接可以通过接口共享 访问权限 加上static私有
//extern DATA* g_pData;
//extern size_t g_nCount;
DATA* GetData();
size_t GetCount();
void Initialize();
void Add(DATA d);
void RemoveAt(int nIndex);
SInfo* FindNumb(int nNumb);
int SortMenu();
int FindMenu();
void Save();
void Print();
void Load();
void Print();
int Menu();
主函数
#include "main.h"
int main()
{
system("color 17");
Initialize();
Load();
while (Menu())
;
}
一、 动态数组(功能区)
#include "main.h"
static DATA* g_pData = NULL; //static 相当于private 不让你隔壁用 你用的话用接口 封装 不让你用核心数据
static size_t g_nSize = 4; //可用资源数 大小 size_t longlong 64位 42亿*42亿
static size_t g_count = 0; //已存入数量 记录位置 大小==位置 重新申请
DATA* GetData()
{
return g_pData; //获取结构体对象内容
}
size_t GetCount()
{
return g_count; //和获取有效数据个数
}
int GetFileSize(FILE* pf) //读取文件大小 利用ftell 和fseek函数
{
long m = ftell(pf);
fseek(pf, 0, SEEK_END);
long n = ftell(pf);
fseek(pf, m, SEEK_SET);//恢复原位置
return n;
}
void Initialize() //初始化空间大小
{
int g_nSize = 4; //大小
int g_count = 0;
g_pData = (DATA*)malloc(sizeof(DATA) * g_nSize);
}
void ReMalloc(size_t nSize) //重新申请空间大小
{
if (nSize <= g_nSize) //判断一下是否满足申请空间要求
return;
DATA* p = (DATA*)malloc(sizeof(DATA) * nSize); //自己写循环 nCount次 复制数据 或者直接memcpy
if (!p)
return;
memcpy(p, g_pData, sizeof(DATA) * g_count); //将g_pData数据拷贝到新申请的空间中
free(g_pData);
g_pData = p; //重新赋值大小
g_nSize = nSize;
}
void Save()
{
FILE* pf = fopen("Worker.txt", "wb");
if (!pf)
return;
fwrite(g_pData, sizeof(SInfo), g_count, pf);
fclose(pf);
}
void Load()
{
FILE* pf = fopen("Worker.txt", "rb");
if (!pf)
return;
long n = GetFileSize(pf) / sizeof(DATA); //读取文件块数
if (n > 0)
{
ReMalloc(n * 2);
g_count = fread(g_pData, sizeof(DATA), n, pf);
fclose(pf);
}
}
void Add(DATA d)
{
if (g_count >= g_nSize) //有效数据大于 给定空间
{
ReMalloc(g_count * 2); //扩容
}
g_pData[g_count++] = d;
}
void RemoveAt(int nIndex)
{
//作业 覆盖
if (nIndex >= g_count) //判断是否刪除有效数据
return;
if (nIndex < g_count - 1) //什么时候需要搬运
{ //g_pData 头部数据 第一个
memcpy(g_pData + nIndex, g_pData + nIndex + 1, sizeof(DATA) * (g_count - nIndex - 1));
//距离首地址3个 距离首地址4个 把它后面兄弟往前穿
}
g_count--;
}
SInfo* FindNumb(int nNumb)
{
DATA* p = g_pData;
while (p - g_pData < (long long)g_count) //p - g_pData 块之间相减判断是否在有效区间内
{
if (p->nNumb == nNumb)
return p;
++p;
}
return NULL;
}
//void Print()
//{
// int i = -1;
// while (++i < g_count) //选择有效数据
// {
// printf("%g", g_pData[i]);
// }
// printf("总共有%d条数据\n", i);
//}
//
二、业务区实现对人员的增删改查
#include "main.h"
//业务区
void Input()
{
int nNumb = 0;
printf("请输入新员工的工号:\n");
scanf_s("%d",&nNumb);
SInfo* p = FindNumb(nNumb);
if (p)
{
printf("你输入的工号已经存在:%d\t%s\t%g\n", p->nNumb, p->sName, p->fSala);
system("pause");
return;
}
SInfo d = { nNumb };
printf("请继续录入姓名和工资:\n");
scanf_s("%s%f", d.sName, (int)sizeof(d.sName), &d.fSala);
Add(d);
Print();
Save();
}
void Print()
{
SInfo* pData = GetData(),
* p = pData;
size_t nCount = GetCount();
printf("%-10s%-20s%s\n", "工号", "姓名", "工资");
while (p - pData < (long long)nCount)
{
printf("%-10d%-20s%0.2f\n", p->nNumb, p->sName, p->fSala);
++p;//28 跳
}
printf("总共有%lld条数据\n", nCount);
system("pause");
Save();
}
void Delete()
{
int nNumb = 0;
printf("请输入要删除的员工工号:\n");
scanf_s("%d", &nNumb);
SInfo* p = FindNumb(nNumb);
if (!p)
{
printf("你输入的工号不存在 ");
system("pause");
return;
}
printf("%d\t%s\t%g\n你确定要删除这条记录吗?[Y/N]?", p->nNumb, p->sName, p->fSala);
char c;
scanf_s("\n%c", &c, (int)sizeof(c));
if (c == 'Y' || c == 'y')
{
RemoveAt(p - GetData()); //选取头部地址
Print();
Save();
}
}
void Modify()
{
int nNumb = 0;
printf("请输入要修改的员工工号:\n");
scanf_s("%d", &nNumb);
SInfo* p = FindNumb(nNumb);
if (!p)
{
printf("你输入的工号不存在 ");
system("pause");
return;
}
printf("%d\t%s\t%g\n你确定要修改这条记录吗?[Y/N]?", p->nNumb, p->sName, p->fSala);
char c;
scanf_s("\n%c", &c, (int)sizeof(c));
if (c != 'Y' && c != 'y')
return;
printf("请录入新的姓名和工资!");
scanf_s("%s%f", &p->sName, (int)sizeof(p->sName), &p->fSala);
Print();
Save();
}
int Menu()
{
system("cls");
puts("\n\n\t\t********************************");
puts("\t\t*\t1、浏览所有信息 *");
puts("\t\t*\t2、添加信息 *");
puts("\t\t*\t3、删除信息 *");
puts("\t\t*\t4、修改信息 *");
puts("\t\t*\t5、查找信息 *");
puts("\t\t*\t6、排序信息 *");
puts("\t\t*\t0、退出 *");
puts("\t\t********************************");
printf("\t\t请选择:");
int i = 0;
scanf_s("%d", &i);
switch (i)
{
case 1:
Print();
break;
case 2:
Input();
break;
case 3:
Delete();
break;
case 4:
Modify();
break;
case 6:
while (SortMenu())
;
break;
case 5:
while (FindMenu())
;
break;
}
return i;
}
2.查找模块
#include "main.h"
void FindbyNumb()
{
int nNumb;
printf("请输入你要查找的工号:");
scanf_s("%d", &nNumb);
SInfo* p = FindNumb(nNumb);
if (p)
{
printf("%d\t%s\t%g\n", p->nNumb, p->sName, p->fSala);
}
else
{
puts("你输入的工号不存在!");
}
system("pause");
}
void FindbyName()
{
char sName[20],str[20];
printf("请输入要查找的员工姓名(允许部分):");
scanf_s("%s", sName, (int)sizeof(sName));
int i = -1;
SInfo* p = GetData();
int n = GetCount();
int sum = 0;
_strlwr(sName); //把录入的姓名转换成小写
//不区分大小写
// 调用strstr之前,把 大串和小串都改成小写或者大写
//把原内容拿出来改成小写,再跟子串查找
while (++i<n) //小于每一个元素
{
strcpy(str, p[i].sName); //不改变源
_strlwr(str); //这个在循环里面每变一下就重新转换成小写
if (strstr(str,sName))
{
printf("%d\t%s\t%g\n", p[i].nNumb, p[i].sName, p[i].fSala), ++sum;
}
}
printf("总共有%d条匹配的数据\n", sum);
system("pause");
}
void FindbySalary()
{
float fMin, fMax;
printf("请输入一个工资段(2个浮点数):");
scanf_s("%f%f", &fMin, &fMax);
if (fMin > fMax)
{
float t = fMin;
fMin = fMax;
fMax = t;
}
int i = -1;
SInfo* p = GetData();
int n = GetCount();
int sum = 0;
while (++i < n)
{
if (p->fSala >= fMin && p->fSala <= fMax)
{
printf("%d\t%s\t%g\n", p->nNumb, p->sName, p->fSala);
++sum;
}
++p;
}
printf("总共有%d条匹配的数据\n", sum);
system("pause");
}
int FindMenu()
{
system("cls");
puts("\n\n\t\t********************************");
puts("\t\t*\t1、按工号查找 *");
puts("\t\t*\t2、按姓名查找 *");
puts("\t\t*\t3、按工资查找 *");
puts("\t\t*\t0、返回主菜单 *");
puts("\t\t********************************");
printf("\t\t请选择:");
int i = 0;
scanf_s("%d", &i);
switch (i)
{
case 1:
FindbyNumb();
break;
case 2:
FindbyName();
break;
case 3:
FindbySalary();
break;
default:
break;
}
return i;
}
3.排序模块
#include "main.h"
void SortbyNumb()
{
int i = GetCount(); //5
SInfo* p = GetData();
while (--i>0)
{ //4....1
int j = 0;
while (j<i) //j:0...4 j+1:1...5
{
if (p[j].nNumb > p[j+1].nNumb)
{
SInfo t = p[j];
p[j] = p[j + 1];
p[j + 1] = t;
}
++j;
}
}
Print();
}
void SortbyName()
{
int i = GetCount();
SInfo* p = GetData();
while (--i > 0)
{ //4....1
int j = 0;
while (j < i) //j:0...3 j+1:1...4
{
if (_stricmp(p[j].sName, p[j+1].sName) > 0) //内容比较strcmp 直接比较是地址之间比较
{
SInfo t = p[j];
p[j] = p[j + 1];
p[j + 1] = t;
}
++j;
}
}
Print();
}
void SortbySalary()
{
int i = GetCount();
SInfo* p = GetData();
while (--i > 0)
{ //4....1
int j = 0;
while (j < i) //j:0...3 j+1:1...4
{
if (p[j].fSala > p[j+1].fSala)
{
SInfo t = p[j];
p[j] = p[j + 1];
p[j + 1] = t;
}
++j;
}
}
Print();
}
int SortMenu()
{
system("cls");
puts("\n\n\t\t********************************");
puts("\t\t*\t1、按工号排序 *");
puts("\t\t*\t2、按姓名排序 *");
puts("\t\t*\t3、按工资排序 *");
puts("\t\t*\t0、返回主菜单 *");
puts("\t\t********************************");
printf("\t\t请选择:");
int i = 0;
scanf_s("%d", &i);
switch (i)
{
case 1:
SortbyNumb();
break;
case 2:
SortbyName();
break;
case 3:
SortbySalary();
break;
default:
break;
}
return i;
}
总结
1、在查找模块要注意关于查找名字函数 这里不区分大小写转换的相应方法 后期会写一个函数来专门进行转换
2、在功能区 注意RemoveAt() ReMalloc()函数相应的判断条件