C语言实现员工管理系统

员工管理系统

1. 题目要求

设计一个计算机程序,能够实现简单的员工管理功能。

  1. 每个员工的信息包括:编号、姓名、性别、出生年月、学历、职务、电话、住址等。
  2. 系统的功能包括:
    1. 文件操作:将数据输出到文件中以及从文件中加载数据
    2. 查询:按特定条件查找员工。
    3. 修改:按编号对某个员工的某项信息进行修改。
    4. 插入:加入新员工的信息。
    5. 删除:按编号删除已离职员工的信息。
    6. 排序:按特定条件对所有员工的信息进行排序。

2. 结构定义

2.1 员工结构定义

// 生日结构
typedef struct birthday
{int year;int month;int day;
}birthday;// 员工结构
typedef struct employee
{int id;char name[50];char gender[10];birthday birthday;char qualification[20];char job[30];char teleNum[15];char location[50];
}employee;

2.2 存储结构定义

typedef struct employee employee;
// 存储结构定义
typedef employee SLDataType;
typedef struct SeqList_dynamic
{SLDataType* SeqList;//指向可以修改大小的数据空间int size;//有效数据个数int capacity;//数据空间的总大小
}SL;//动态顺序表的实现
//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
//顺序表的扩容 
void SLCheckCapacity(SL* ps);
//顺序表的头部插⼊删除 / 尾部插⼊删除 
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//顺序表指定位置之前插⼊/删除数据 
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);

3. 项目文件

在本项目中,一共有五个文件

  1. SeqList.h:存放动态顺序表功能声明
  2. SeqList.c:存放动态顺序表功能定义
  3. employee.c:存放员工管理系统功能声明
  4. employee.h:存放员工管理系统功能定义
  5. test.c:测试文件

4. 项目功能

本项目主要实现下面的功能:

  1. 加载上次程序结束时保存到文件的员工信息
  2. 从控制台输入员工信息
  3. 查找指定信息的员工:仅包括id和姓名查找
  4. 修改员工的信息
  5. 插入一个新员工
  6. 删除指定员工
  7. 对员工信息按照指定信息排序:仅包括id、姓名和生日
  8. 打印所有员工信息
  9. 向文件中写入员工信息数据,便于下次读取

程序主菜单

void menu()
{printf("*****************************\n");printf("******员工信息管理系统*******\n");printf("*1. 输入员工信息\n");printf("*2. 查找员工\n");printf("*3. 修改员工\n");printf("*4. 插入员工\n");printf("*5. 删除员工\n");printf("*6. 排序输出员工信息\n");printf("*7. 查看所有员工信息\n");printf("*8. 退出系统\n");printf("*****************************\n");
}

程序功能对应函数

// 程序菜单
void menu();// 导入数据
void LoadEmployee(SL* employees);// 初始化——输入
void employeeInfoGet(SL* employees);// 查找员工
// 查找方式菜单
void menuForFind();
// 查找员工——返回下标
int findEmployee(SL* employees);
// 查找员工——显示对应员工信息
void findEmployee_print(SL* employees);// 修改菜单
void menuForModify();
// 修改员工信息
void modifyEmployee(SL* employees);// 插入员工信息
void insertEmployee(SL* employees);// 删除员工信息
void deleteEmployee(SL* employees);// 排序菜单
void menuForSort();
// 按照指定内容排序
void sortEmployees(SL* employees);
// 打印排序后的内容
void printSortedEmp(employee* tmp, int size);// 向文件中写入数据
void writeIntoFile(SL* employees);// 销毁系统数据
void destroyEmployee(SL* employees);// 打印所有员工信息
void printEmployees(SL* employees);

程序主函数

#define _CRT_SECURE_NO_WARNINGS 1#include "SeqList.h"
#include "employee.h"int main()
{SL employees;SLInit(&employees);char ans = 0;printf("是否需要导入上次的数据:y/n");scanf(" %c", &ans);if (ans == 'y'){LoadEmployee(&employees);}menu();printf("请输入选项:");int choice = 0;while (scanf("%d", &choice)){switch (choice){case 1:employeeInfoGet(&employees);break;case 2:findEmployee_print(&employees);break;		case 3:modifyEmployee(&employees);break;case 4:insertEmployee(&employees);break;case 5:deleteEmployee(&employees);break;case 6:sortEmployees(&employees);break;case 7:printEmployees(&employees);break;case 8:destroyEmployee(&employees);printf("谢谢使用");return 1;default:printf("请按照菜单重新输入\n");break;}menu();printf("请输入选项:");}
}

5. 功能实现

5.1 加载数据

在加载数据函数中,使用fopen函数和fread函数进行文件操作,当fread文件读到一组数据时,向顺序表中插入一组数据,再循环读取直到读到文件结尾

// 导入数据
// 加载上一次的数据
void LoadEmployee(SL* employees) 
{FILE* pf = fopen("employees.txt", "rb"); if (pf == NULL) {perror("fopen error!\n"); return;}employee tmp;while (fread(&tmp, sizeof(employee), 1, pf)){SLPushBack(employees, tmp);}fclose(pf);printf("成功导入历史数据\n");
}

5.2 输入数据

首先通过num控制输入的员工个数

int num = 0;
printf("请输入员工个数:");
scanf("%d", &num);

接着通过for循环根据num的值控制数据的输入,对于生日的输入来说,为了保证生日日期的合法性,使用if语句和goto语句处理不正确的日期,输入完一组数据后,调用顺序表的尾插函数向顺序表中插入数据

for (int i = 0; i < num; i++)
{employee tmp;printf("请输入第%d个员工\n", i + 1);printf("请输入员工id:");scanf("%d", &(tmp.id));printf("请输入姓名:");scanf("%s", tmp.name);printf("请输入员工性别:");scanf("%s", tmp.gender);printf("请按照年月日的顺序以空格间隔输入员工生日:");
setBirth:scanf("%d%*c%d%*c%d", &(tmp.birthday.year),&(tmp.birthday.month),&(tmp.birthday.day));if (tmp.birthday.month < 1 || tmp.birthday.month > 12 ||(tmp.birthday.day < 1 ||tmp.birthday.day > GetMonthDays(tmp.birthday.year, tmp.birthday.month))){printf("请重新输入生日\n");goto setBirth;}printf("请输入员工学历:");scanf("%s", tmp.qualification);printf("请输入员工职业:");scanf("%s", tmp.job);printf("请输入员工电话:");scanf("%s", tmp.teleNum);printf("请输入员工的住址:");scanf("%s", tmp.location);SLPushBack(employees, tmp);
}

完整模块代码

// 获取日期函数
int GetMonthDays(int year, int month)
{int monthDays[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))){return monthDays[month] + 1;}return monthDays[month];
}// 获取输入
void employeeInfoGet(SL* employees)
{int num = 0;printf("请输入员工个数:");scanf("%d", &num);for (int i = 0; i < num; i++){employee tmp;printf("请输入第%d个员工\n", i + 1);printf("请输入员工id:");scanf("%d", &(tmp.id));printf("请输入姓名:");scanf("%s", tmp.name);printf("请输入员工性别:");scanf("%s", tmp.gender);printf("请按照年月日的顺序以空格间隔输入员工生日:");setBirth:scanf("%d%*c%d%*c%d", &(tmp.birthday.year),&(tmp.birthday.month),&(tmp.birthday.day));if (tmp.birthday.month < 1 || tmp.birthday.month > 12 ||(tmp.birthday.day < 1 ||tmp.birthday.day > GetMonthDays(tmp.birthday.year, tmp.birthday.month))){printf("请重新输入生日\n");goto setBirth;}printf("请输入员工学历:");scanf("%s", tmp.qualification);printf("请输入员工职业:");scanf("%s", tmp.job);printf("请输入员工电话:");scanf("%s", tmp.teleNum);printf("请输入员工的住址:");scanf("%s", tmp.location);SLPushBack(employees, tmp);}
}

5.3 查找员工信息

在设计查找模块时,一共实现了两种查找方式:

  1. 查找返回下标
  2. 查找打印员工信息
5.3.1 查找返回下标

调用返回下标函数便于删除函数调用,一共实现了两种查找方式

  1. 按照名字查找
// 按照名字查找
int findBy_name(SL* employees, char* target)
{for (int i = 0; i < employees->size; i++){if (strcmp(employees->SeqList[i].name, target) == 0){return i;// 返回对应位置下标}}return -1;
}
  1. 按照id查找
// 按照id查找
int findBy_id(SL* employees, int target)
{for (int i = 0; i < employees->size; i++){if (employees->SeqList[i].id == target){return i;// 返回对应位置下标}}return -1;
}

调用两种函数的主调函数

// 查找员工——返回下标
int findEmployee(SL* employees)
{int choice = 0;int pos = 0;menuForFind();printf("请选择查找方式:");while (scanf("%d", &choice)){switch (choice){case 1:{int target = 0;printf("请输入需要查找的员工id:");scanf("%d", &target);pos = findBy_id(employees, target);return pos;}break;case 2:{char name[50] = { 0 };printf("请输入需要查找的员工姓名:");scanf("%s", name);pos = findBy_name(employees, name);return pos;}break;case 3:return -1;default:menuForFind();printf("请重新按照菜单输入:");break;}menuForFind();printf("请选择查找方式:");}return -1;
}
5.3.2 查找打印员工信息

调用返回下标的函数,根据返回的pos下标打印对应的员工信息

// 查找并打印员工信息
void findEmployee_print(SL* employees)
{// 调用findEmployee函数int pos = findEmployee(employees);if (pos != -1){printf("\t员工id:%d", employees->SeqList[pos].id);printf("\t姓名:%s", employees->SeqList[pos].name);printf("\t性别:%s", employees->SeqList[pos].gender);printf("\t生日:%d-%02d-%02d\n", employees->SeqList[pos].birthday.year,employees->SeqList[pos].birthday.month,employees->SeqList[pos].birthday.day);printf("\t学历:%s", employees->SeqList[pos].qualification);printf("\t职业:%s", employees->SeqList[pos].job);printf("\t电话:%s", employees->SeqList[pos].teleNum);printf("\t地址:%s\n", employees->SeqList[pos].location);}else{printf("查无此人\n");}
}

5.4 修改员工信息

实现修改员工信息函数可以选择修改8种信息:

  1. 编号
  2. 姓名
  3. 性别
  4. 出生日期
  5. 学历
  6. 职业
  7. 电话
  8. 地址

对于生日日期的输入来说,存在合法日期判断,与输入处理方式类似,结合if语句和goto语句进行处理

[!IMPORTANT]
在下面的代码中,对于生日信息的修改使用了整体修改和判断而不是针对年、月或者日进行单独修改,原因如下:
以年为例,如果用户的生日所在年份是闰年,那么对应的2月有29天,但是当用户需要修改年为非闰年时,那么2月的日期也需要修改,此时需要对年、月和日都写判断条件,所以看似是修改一个年份,实际上个别情况需要两个变量都需要修改,所以为了使得修改方便,考虑整体修改再最后整体判断
// 修改员工
void modifyEmployee(SL* employees)
{// 调用查找函数找出需要修改的员工int pos = findEmployee(employees);if (pos == -1){printf("查无此人\n");return;}int choice = 0;menuForModify();printf("请选择需要修改的内容:");while (scanf(" %d", &choice)){switch (choice){case 1:printf("请输入需要修改的id:");scanf("%d", &(employees->SeqList[pos].id));printf("修改完成\n");break;case 2:printf("请输入需要修改的姓名:");scanf("%s", employees->SeqList[pos].name);printf("修改完成\n");break;case 3:printf("请输入需要修改的性别:");scanf("%s", employees->SeqList[pos].gender);printf("修改完成\n");break;case 4:{modifyBirth:printf("请输入修改后的年月日,以空格间隔:");scanf("%d%*c%d%*c%d", &(employees->SeqList[pos].birthday.year),&(employees->SeqList[pos].birthday.month),&(employees->SeqList[pos].birthday.day));if (employees->SeqList[pos].birthday.month < 1 || employees->SeqList[pos].birthday.month > 12 ||(employees->SeqList[pos].birthday.day < 1 ||employees->SeqList[pos].birthday.day > GetMonthDays(employees->SeqList[pos].birthday.year, employees->SeqList[pos].birthday.month))){printf("日期不合法,请重新输入生日\n");goto modifyBirth;}}printf("修改完成\n");break;case 5:printf("请输入需要修改的学历:");scanf("%s", employees->SeqList[pos].qualification);printf("修改完成\n");break;case 6:printf("请输入需要修改的职业:");scanf("%s", employees->SeqList[pos].job);printf("修改完成\n");break;case 7:printf("请输入需要修改的电话:");scanf("%s", employees->SeqList[pos].teleNum);printf("修改完成\n");break;case 8:printf("请输入需要修改的地址:");scanf("%s", employees->SeqList[pos].location);printf("修改完成\n");break;case 9:return;default:printf("请重新选择\n");break;}menuForModify();printf("请选择需要修改的内容:");}
}

5.5 插入员工信息

在插入员工信息函数中,因为与输入员工信息函数基本思路相同,所以考虑直接复用输入员工信息函数

// 插入数据
void insertEmployee(SL* employees)
{// 复用输入函数employeeInfoGet(employees);
}

5.6 删除员工信息

删除员工信息首先需要调用查找到指定员工,再执行删除,如果没找到,则提示“查无此人,删除失败”,否则“删除成功”,因为删除是删除顺序表中的元素,所以直接调用顺序表的删除函数

// 删除员工
void deleteEmployee(SL* employees)
{// 调用查找函数int pos = findEmployee(employees);if (pos < 0){printf("查无此人,删除失败");}SLErase(employees, pos);printf("删除完成\n");
}

5.7 排序员工信息

实现员工的排序信息一共有三种实现方式:

  1. 按照员工id排序
// 按照id排序
int cmp_id(const void* p1, const void* p2)
{return ((employee*)p1)->id - ((employee*)p2)->id;
}
  1. 按照员工姓名排序
// 名字比较
int cmp_name(const void* p1, const void* p2)
{return strcmp(((employee*)p1)->name, ((employee*)p2)->name);
}
  1. 按照员工生日日期排序
// 日期比较
int birthdayCmp(const void* p1, const void* p2)
{//如果年大就直接返回1if (((employee*)p1)->birthday.year > ((employee*)p2)->birthday.year){return 1;}else if (((employee*)p1)->birthday.year == ((employee*)p2)->birthday.year &&((employee*)p1)->birthday.month > ((employee*)p2)->birthday.month)//年相等时比较月份,月份大就直接返回true{return 1;}else if (((employee*)p1)->birthday.year == ((employee*)p2)->birthday.year &&((employee*)p1)->birthday.month == ((employee*)p2)->birthday.month && ((employee*)p1)->birthday.day > ((employee*)p2)->birthday.day)//年相等,月份相等时,天大就直接返回true{return 1;}else//其他情况均返回-1{return -1;}
}

在排序主调函数中,使用C语言库中的qsort函数结合函数指针调用上述三种函数完成对应的排序功能

调用三种函数的主调函数:

直接调用函数

// 排序主体
void sortEmployees(SL* employees)
{int choice = 0;menuForSort();printf("请选择需要排序的字段:");while (scanf("%d", &choice)){switch (choice){case 1:qsort(employees->SeqList, employees->size, sizeof(employee), cmp_id);printSortedEmp(employees->SeqList, employees->size);break;case 2:qsort(employees->SeqList, employees->size, sizeof(employee), cmp_name);printSortedEmp(employees->SeqList, employees->size);break;case 3:qsort(employees->SeqList, employees->size, sizeof(employee), birthdayCmp);printSortedEmp(employees->SeqList, employees->size);break;case 4:return;default:menuForSort();printf("请重新按照菜单输入:");break;}menuForSort();printf("请选择需要排序的字段:");}
}

转移表优化

// 转移表优化
void sortEmployees(SL* employees)
{int choice = 0;menuForSort();printf("请选择需要排序的字段:");// 定义函数指针数组int (*cmp[4])(const void*, const void*) = {0, cmp_id, cmp_name, birthdayCmp};//cmp arr[4] = {0, cmp_id, cmp_name, birthdayCmp};while (scanf("%d", &choice)){if (choice >= 1 && choice <= 3){qsort(employees->SeqList, employees->size, sizeof(employee), cmp[choice]);printSortedEmp(employees->SeqList, employees->size);}else if (choice == 4){break;}else{menuForSort();printf("请重新输入:");}menuForSort();printf("请选择需要排序的字段:");}
}

为了可以更好看到排序后的结果,在每一次排序结束后,将自动执行一次排序结果打印函数

// 打印排序后的内容
void printSortedEmp(employee* tmp, int size)
{for (int i = 0; i < size; i++){printf("第%d名员工:\n", i + 1);printf("\t员工id:%d", tmp[i].id);printf("\t姓名:%s", tmp[i].name);printf("\t性别:%s", tmp[i].gender);printf("\t生日:%d-%02d-%02d\n", tmp[i].birthday.year,tmp[i].birthday.month,tmp[i].birthday.day);printf("\t学历:%s", tmp[i].qualification);printf("\t职业:%s", tmp[i].job);printf("\t电话:%s", tmp[i].teleNum);printf("\t地址:%s\n", tmp[i].location);}
}

5.8 写入数据与顺序表空间释放

为了更好地保存数据,在程序结束时考虑将内存中的数据使用fopenfwrite函数写入硬盘中

// 向文件中写入数据
void writeIntoFile(SL* employees)
{FILE* pf = fopen("employees.txt", "wb"); if (pf == NULL) {perror("fopen error!\n"); return;}//将通讯录数据写⼊⽂件for (int i = 0; i < employees->size; i++){fwrite(employees->SeqList + i, sizeof(employee), 1, pf);}fclose(pf);printf("数据保存成功!\n");
}

在程序结束前,防止内存泄漏问题,需要对顺序表在堆上的空间进行释放,考虑设计空间销毁函数,因为需要写数据到文件中,所以写入文件过程可以放入空间释放函数中,通过询问用户是否需要保存数据实现更好的交互性

void destroyEmployee(SL* employees)
{char ans = 0;printf("是否需要保存数据:y/n");scanf(" %c", &ans);if (ans == 'y'){writeIntoFile(employees);}SLDestroy(employees);
}

5.9 打印所有员工信息

为了更好让用户看到已经保存到内存缓冲区的内容,考虑使用打印函数将缓冲区内容打印到控制台

// 打印所有员工信息
void printEmployees(SL* employees)
{// 没有员工直接返回if (employees->size == 0){printf("暂无数据\n");return;}for (int i = 0; i < employees->size; i++){printf("第%d名员工:\n", i + 1);printf("\t员工id:%d", employees->SeqList[i].id);printf("\t姓名:%s", employees->SeqList[i].name);printf("\t性别:%s", employees->SeqList[i].gender);printf("\t生日:%d-%02d-%02d\n", employees->SeqList[i].birthday.year,employees->SeqList[i].birthday.month,employees->SeqList[i].birthday.day);printf("\t学历:%s", employees->SeqList[i].qualification);printf("\t职业:%s", employees->SeqList[i].job);printf("\t电话:%s", employees->SeqList[i].teleNum);printf("\t地址:%s\n", employees->SeqList[i].location);}
}

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

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

相关文章

Next.js 加载页面及流式渲染(Streaming)

Next.js 加载页面及流式渲染&#xff08;Streaming&#xff09; 在现代的 Web 应用开发中&#xff0c;用户体验是至关重要的。快速响应的页面加载和流畅的用户界面可以显著提升用户的满意度。而加载页面&#xff08;Loading Page&#xff09;和流式渲染&#xff08;Streaming&…

大模型太贵?找找自己的原因好吧?

什么&#xff1f; 炼个大模型还嫌贵&#xff1f; 到底哪里贵了&#xff01;&#xff1f; 大模型算力贵&#xff1f;哪里贵了&#xff01;&#xff1f; 争先恐后训练大模型&#xff0c; 搞得现在“算力慌”“一卡难求”&#xff0c; 算力当然水涨船高了! “特供版”GPU又…

python format详解

一、format() 内置函数 format(value, format_spec) 其中format_spec参数必须是一个字符串类型的&#xff0c;否则会抛出 TypeError异常如果format_spec参数是一个空的字符串&#xff0c;且value没有实现 __format__(value, format_spec) 实例方法&#xff1b;则该函数结果与…

MYSQL、ORACLE、PostgreSQL数据库对象层次及权限管理对比

文章目录 前言一、PostgreSQL二、MySQL三、Oracle 前言 本文为出于自己扩展、比较、图形化的思维路径自行总结归纳&#xff0c;可能有些细节不太准确&#xff0c;欢迎指正。 MySQL、Oracle、PostgreSQL关系型数据库都有管理员用户、用户、权限管理、表函数索引等数据库对象&am…

hexo实战:(二)个人独立博客优化合集

前言 上次介绍了使用 HexoGitHub Pages&#xff0c;零成本搭建一个专属自己的独立博客网站。我觉得那篇文章是没有入门门槛的&#xff0c;不管你是什么行业&#xff0c;只要想打造个人 IP&#xff0c;又不太想受博客平台约束&#xff0c;那么读完后动手操作一下也能轻松完成。…

图片Base64编码

将图片进行base64编码 在线转换 加头转换并保存为txt import base64 def image_to_base64(image_path):with open(image_path, "rb") as img_file:# 读取图片文件img_data img_file.read()# 对图片数据进行base64编码base64_data base64.b64encode(img_data)# 将…

[vue3]组件通信

自定义属性 父组件中给子组件绑定属性, 传递数据给子组件, 子组件通过props选项接收数据 props传递的数据, 在模版中可以直接使用{{ message }}, 在逻辑中使用props.message defineProps defineProps是编译器宏函数, 就是一个编译阶段的标识, 实际编译器解析时, 遇到后会进行…

Oracle 是否扼杀了开源 MySQL

Oracle 是否无意中扼杀了开源 MySQL Peter Zaitsev是一位俄罗斯软件工程师和企业家&#xff0c;曾在MySQL公司担任性能工程师。大约15年前&#xff0c;当甲骨文收购Sun公司并随后收购MySQL时&#xff0c;有很多关于甲骨文何时“杀死MySQL”的讨论。他曾为甲骨文进行辩护&#…

【GD32F303红枫派使用手册】第十七节 USART-中断串口收发实验

17.1 实验内容 通过本实验主要学习以下内容&#xff1a; 使用中断进行串口收发 17.2 实验原理 前面章节中我们已经学习了串口的状态标志位&#xff0c;本实验就是使用TBE中断和RBNE中断来实现中断收发数据&#xff0c;实验原理是RBNE中断用来接受数据&#xff0c;IDLE中断用…

记录第一次edusrc挖掘

文章目录 一、前言二、漏洞说明截止目前已修复 一、前言 edusrc平台介绍 我们可以在关于页面看到edusrc的收录规则 现阶段&#xff0c;教育行业漏洞报告平台接收如下类别单位漏洞&#xff1a; 教育部 各省、自治区教育厅、直辖市教委、各级教育局 学校 教育相关软件 可以看到…

基于FOC控制器的BLDC无刷直流电机控制系统matlab编程与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于FOC控制器的BLDC无刷直流电机控制系统matlab编程与仿真&#xff0c;使用MATLAB编程实现&#xff0c;包括FOC控制器&#xff0c;clark&#xff0c;park等&#xff0c;不使用…

【PyQt5】一文向您详细介绍 self.setGeometry() 的作用

【PyQt5】一文向您详细介绍 self.setGeometry() 的作用 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本…

linux下的进程通讯

一. 实验内容 1&#xff0e;编写一个程序&#xff0c;实现在两个进程之间运用管道进行通讯。程序中创建一个子进程&#xff0c;然后父、子进程各自独立运行。父进程不断地在标准输入设备上读入小写字母&#xff0c;写入管道。子进程不断地从管道中读取字符&#xff0c;转换为大…

充电宝什么牌子耐用?2024年四大品牌推荐!这四款值得入!

在现代生活中&#xff0c;充电宝已经成为我们日常必备的数码配件之一。无论是旅行、出差还是日常通勤&#xff0c;拥有一款耐用且高效的充电宝&#xff0c;能够为我们的电子设备提供源源不断的电力支持。然而&#xff0c;市场上充电宝品牌众多&#xff0c;质量参差不齐&#xf…

深入理解 Java 中的 volatile 关键字

暮色四合&#xff0c;晚风轻拂&#xff0c;湖面上泛起点点波光&#xff0c;宛如撒下了一片星河。 文章目录 前言一、CPU 三级缓存二、JMM三、并发编程正确性的基础四、volatile 关键字五、volatile 可见性六、volatile 有序性6.1 指令重排序6.2 volatile 禁止指令重排6.3 vola…

如何区分人工智能生成的图像与真实照片(下)

4 功能上的不合理性 AI 生成的图像往往会因为缺乏对现实世界物体结构和相互作用的了解&#xff0c;而产生各种功能不合理之处。这些不合理之处主要表现在以下几个方面&#xff1a; 4.1 构图不合理 物体关系不合逻辑: AI 生成的图像中&#xff0c;物体和人物之间的关系可能不符…

python3GUI--记账助手By:PyQt5(附下载地址)

文章目录 一&#xff0e;前言二&#xff0e;开发环境三&#xff0e;预览1.登录&注册2.主界面3.新增账单1.当前日期2.选择日期3.添加成功 4.删除账单4.筛选账单5.账单数据汇总1.日账单2.月账单3.年账单 四&#xff0e;设计心得1.项目代码结构2.UI设计概览3.UI设计详细1.登录…

人员的社保缴纳情况直接影响设计资质的延续结果。

是的&#xff0c;人员的社保缴纳情况会直接影响设计资质的延续结果。社保缴纳情况是评估企业运营稳定性和合规性的重要指标之一&#xff0c;特别是在设计资质延续的审核过程中。 设计资质延续时&#xff0c;相关部门会要求企业提供涉及资质延续所需人员的社保缴纳证明&#xff…

kettle学习(利用jsonPath定位,json文件转换)

kettle学习&#xff08;利用jsonPath定位&#xff0c;json文件转换&#xff09; 于数据处理的广袤天地间&#xff0c;我们时常需应对各类繁杂状况与各式格式。Kettle 作为极具威力的数据集成利器&#xff0c;赋予了我们诸多功能与无限可能此次博客里&#xff0c;我们将重点投向…

如何在电磁仿真软件CST中获得多天线同频的SAR

上期介绍了多天线不同频率情况下如何计算SAR&#xff0c;不用考虑相位差&#xff1b;这期我们看看MIMO&#xff0c;多天线同频&#xff0c;考虑相位差&#xff1a; 简单模型&#xff0c;一只手和两个天线&#xff1a; 工作频率2GHz&#xff1a; 仿真结束查看S11&#xff1a; 查…