当前位置: 首页 > news >正文

【C语言】——通讯录(静态-动态增长-文件储存)

 

目录

前言:

一:整体框架

关于通讯录结构体的创建 

二:通讯录的功能实现(静态)

2.1初始化通讯录

2.2增加联系人

2.3打印通讯录

2.4删除联系人

 2.5 查找联系人

2.6修改联系人 

2.7排序联系人

三:通讯录优化——动态内存

 3.1通讯录的创建

3.2初始化通讯录 

3.3增加联系人 

3.4清空通讯录 

 四:通讯录优化——文件版本

4.1退出保存信息到文件

 4.2初始化时加载文件信息

五:整体代码

test.c

 contact.c

contact.h

前言:

在之前的篇章中讲述了【C语言】进阶——结构体,【C语言】进阶——动态内存,【C语言】进阶——文件操作。

在本篇运用以上知识结合来写一个小项目——通讯录

我会逐步从静态版本优化到动态增加以及最终的文件存储版,循循渐进,详解通讯录的实现

实现思路

通讯录类似一个复杂结构体,包含了很多信息,以个人信息的通讯录而言,需要包含个人名字,年龄,电话,性别以及地址;

而它所具有的基本功能:增(Add)删(Del) 改(modify) 查 (Search);以及我们可以对其一些简单的拓展功能;

这些具体分析为:

  1. 打印一个菜单,提供用户选择功能;
  2. 添加联系人信息;
  3. 删除联系人信息;
  4. 查询联系人信息;
  5. 修改联系人信息;
  6. 显示所有联系人信息;
  7. 对所有联系人信息进行排序整理;
  8. 删除所有联系人信息;
  9. 操作完毕可选择退出。

将整个项目分为三部分 :

test.c ——测试代码模块

contact.c——函数的实现

contact.h——类型的定义,函数声明等 

一:整体框架

我们需要映入眼帘的菜单选择和提示,可以选择do...while();和switch语句相结合,来打印出整个框架体系;

另外因为switch语句中case 1,case2...这样的数字不好看,我们可以采用枚举变量来定义;

        枚举的关键字是enum

在括号内部注意每个成员名后面要加逗号,同时别忘了括号外面的分号

枚举内部的成员被依次赋值为0,1,2

我们假如将female赋值为1,secret就被赋值为2,male赋值为0

        枚举的优点:

1.增加代码的可读性和可维护性

2. 和 #define 定义的标识符比较枚举有类型检查,更加严谨。

3. 防止了命名污染(封装)

4. 便于调试

5. 使用方便,一次可以定义多个常量

void menu()
{printf("<-==============通讯录=============->\n");printf("<-==========1.增加联系人===========->\n");printf("<-==========2.删除联系人===========->\n");printf("<-==========3.查找联系人===========->\n");printf("<-==========4.修改联系人===========->\n");printf("<-==========5.打印通讯录===========->\n");printf("<-==========6.排序通讯录===========->\n");printf("<-==========0.退出通讯录===========->\n");printf("<-=================================->\n");
}
enum Option
{EXIT,	//0ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};
int main()
{int input = 0;do{//菜单menu();printf("请输入操作:");scanf("%d", &input);switch (input){case ADD:printf("增加联系人\n");break;case DEL:printf("删除联系人\n");break;case SEARCH:printf("查找联系人\n");break;case MODIFY:printf("修改联系人\n");break;case SHOW:printf("打印联系人\n");break;case SORT:printf("排序联系人\n");break;case EXIT:printf("退出通讯录\n");break;default:printf("输入错误,重新输入\n");break;}} while (input);return 0;
}

 

关于通讯录结构体的创建 

创建所需的个人信息结构体

利用#define 定义常量,有利于维护;

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30typedef struct Peo		//个人信息结构体
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}Peo;

另外还需要创建一个结构体,来记录Peo的信息,以数组来存放,创建变量,记录个数 

typedef struct Contact
{Peo data[DATA_MAX];		//存放个人信息int sz;		//记录信息人数
}Contact;

二:通讯录的功能实现(静态)

2.1初始化通讯录

//静态-初始化通讯录
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;memset(pc->data, 0, sizeof(pc->data)); 
}

memset来初始化,以字节为单位一个字节一个字节的初始化! 

2.2增加联系人

增加之前,先判断是否为满,增加成功后,还需要将sz++,记录加入的人数

//增加联系人
void AddContact(Contact* pc)
{assert(pc);//判断通讯录是否满了if (pc->sz == DATA_MAX){printf("通讯录已满,增加失败\n");return;}//增加信息printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);//对sz增加,pc->sz++;printf("增加成功\n");
}

 

2.3打印通讯录

增加联系人后,真的在内存中增加与否,并不知道,我们需要打印出来

先判断是否有信息,然后打印标题,增加可读性,再利用for循环,将sz个信息打印出来 

-20就代表域宽是20(长度不够20用空格填充),负号代表左对齐,默认是右对齐的!

//显示所有的联系人
void ShowContact(const Contact* pc)
{assert(pc);//判断通讯录内是否有信息if (pc->sz == 0){printf("打印失败,通讯录为空\n");return;}//打印//打印标题printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印信息int i = 0;for (i = 0; i < pc->sz; i++){//打印每个人的信息printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}

2.4删除联系人

  1. 先判断通讯录是否有信息,通过名字来查找是否存在此人,
  2. 封装函数:因为我们在查找联系人,修改联系人中也会用到此功能。查找到此人,返回sz位置,没有此人,返回-1;
  3.  通过for循环:假如要删除人为 tmp的信息;就只需要把tmp后的数据往前移动,覆盖掉tmp位置的信息就可以了;
  4. 如果要删除最后一个人,则直接sz--;可以不进行访问,算是删除了
  5. 删除成功后,就把sz--;说明数组里的有效数据减1!
//通过名字查找被删除人
static int FindByName(Contact* pc, char* name)
{assert(pc);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;//找不到
}
//删除联系人
void DelContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("删除失败,通讯录为空\n");return;}//查找是否存在此人char name[NAME_MAX];printf("请输入被删除人名字:\n");scanf("%s", name);//查找此人,存在返回位置,不存在返回-1int ret = FindByName(pc,name);if (ret == -1){printf("要删除的人不存在\n");return;}//删除(覆盖)此人for (int i = ret; i < pc->sz - 1; i++)	//sz-1 是防止执行体越界,如果要删除的是最后一个元素,通过sz--,直接不访问,{pc->data[i] = pc->data[i + 1];}pc->sz --;printf("删除成功\n");
}

 

 

 2.5 查找联系人

跟删除同理,先查找是否存在此人,查找到了返回下标打印出来即可 

//查找联系人
void FindContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("查找失败,通讯录为空\n");return;}//查找此人,存在返回位置,不存在返回-1char name[NAME_MAX];printf("请输入被查找人名字:\n");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要查找的人不存在\n");return;}//显示出来printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

2.6修改联系人 

查找到此人位置,记录返回,通过该位置进行修改 

//修改联系人
void ModifyContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("修改失败,通讯录为空\n");return;}//查找此人,存在返回位置,不存在返回-1char name[NAME_MAX];printf("请输入被修改人名字:\n");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要查找的人不存在\n");return;}//修改printf("请输入名字:");scanf("%s", pc->data[ret].name);printf("请输入年龄:");scanf("%d", &(pc->data[ret].age));printf("请输入性别:");scanf("%s", pc->data[ret].sex);printf("请输入电话:");scanf("%s", pc->data[ret].tele);printf("请输入地址:");scanf("%s", pc->data[ret].addr);printf("修改成功\n");
}

 

2.7排序联系人

利用qsort快速排序,然后我们以名字strcmp函数来比较

//目录排序
//void qsort(void* base, size_t num, size_t size,
//	int (*compar)(const void*, const void*));
int cmpare(const void* p1, const void* p2)
{return strcmp(((Peo*)p1)->name, ((Peo*)p2)->name);
}void SortContact(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(Peo), cmpare);
}

三:通讯录优化——动态内存

 3.1通讯录的创建

增加变量capacity——用来记录通讯录容量

利用指针动态创建内存,结合malloc,realloc,calloc

typedef struct Contact
{Peo* data;    //存放数据int sz;		    //记录信息人数int capacity;    //记录的是通讯录的当前容量
}Contact;

3.2初始化通讯录 

利用calloc 开辟动态空间给data 

#define DEFAULT_SZ 3		//默认容量
#define DEFAULT_INC 2		//扩容量
//动态版本的初始化
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;	pc->data = calloc(pc->capacity, sizeof(Peo));	if (pc->data == NULL){perror("InitContact->calloc");return;}
}

3.3增加联系人 

 利用realloc来进行动态扩容,存放到临时变量ptr里,开辟成功给data

//检查是否需要扩容
void CheckCapacity(Contact* pc)
{if (pc->sz == pc->capacity){Peo* ptr = (Peo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(Peo));if (ptr != NULL){pc->data = ptr;pc->capacity += DEFAULT_INC;printf("增容成功\n");}else{perror("AddContact->realloc");return;}}
}
//增加联系人
void AddContact(Contact* pc)
{assert(pc);//增加容量CheckCapacity(pc);//增加信息printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");
}

3.4清空通讯录 

因为涉及到了动态开辟,所以使用后要进行free空间

防止内存泄漏

写到EXIT退出通讯录里面,让它退出直接调用这个清空销毁函数!就算不销毁最终程序结束也会自动销毁!

void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}

 四:通讯录优化——文件版本

4.1退出保存信息到文件

使用文件操作,涉及到了文件缓冲区;

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序 中每一个正在使用的文件开辟一块“文件缓冲区”。

① 从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。

② 从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓 冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。

③ 缓冲区的大小根据C编译系统决定的。

因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。 如果不做,可能导致读写文件的问题。

 

先把信息存储起来后,在执行销毁并退出! 

//保存信息到文件
void SaveContact(Contact* pc)
{FILE* pf = fopen("contact.txt", "wb");	//二进制读文件if (pf == NULL){perror("SaveContact");return;}//写信息到文件int i = 0;for (i = 0; i < pc->sz; i++){//fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);fwrite(pc->data + i, sizeof(Peo), 1, pf);}fclose(pf);pf = NULL;
}

 4.2初始化时加载文件信息

将信息加载到文件当中,

在初始化阶段加载文件信息

void CheckCapacity(Contact* pc);//检查上次保存的信息是否需要扩容
void LoadContact(Contact* pc)
{FILE* pf = fopen("contact.txt", "rb");    //以二进制读文件if (pf == NULL){perror("LoadContact");return;}//读文件Peo tmp = { 0 };    //临时变量while (fread(&tmp, sizeof(Peo), 1, pf)){CheckCapacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}fclose(pf);pf = NULL;
}//文件版本的初始化函数
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity, sizeof(Peo));if (pc->data == NULL){perror("InitContact->calloc");return;}//加载文件中的信息到通讯录LoadContact(pc);
}

 

五:整体代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include "contact.h"
void menu()
{printf("<-==============通讯录=============->\n");printf("<-==========1.增加联系人===========->\n");printf("<-==========2.删除联系人===========->\n");printf("<-==========3.查找联系人===========->\n");printf("<-==========4.修改联系人===========->\n");printf("<-==========5.打印通讯录===========->\n");printf("<-==========6.排序通讯录===========->\n");printf("<-==========0.退出通讯录===========->\n");printf("<-=================================->\n");
}
enum Option
{EXIT,	//0ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};
int main()
{int input = 0;Contact con;	//创建通讯录//初始化通讯录InitContact(&con);do{//菜单menu();printf("请输入操作:");scanf("%d", &input);switch (input){case ADD:printf("增加联系人\n");AddContact(&con);break;case DEL:printf("删除联系人\n");DelContact(&con);break;case SEARCH:printf("查找联系人\n");FindContact(&con);break;case MODIFY:printf("修改联系人\n");ModifyContact(&con);break;case SHOW:printf("打印联系人\n");ShowContact(&con);break;case SORT:printf("排序联系人\n");SortContact(&con);break;case EXIT:printf("退出通讯录\n");SaveContact(&con);DestroyContact(&con);break;default:printf("输入错误,重新输入\n");break;}} while (input);return 0;
}

 contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"静态-初始化通讯录
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data)); 
//}
动态版本的初始化
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	pc->capacity = DEFAULT_SZ;	
//	pc->data = calloc(pc->capacity, sizeof(Peo));	
//	if (pc->data == NULL)
//	{
//		perror("InitContact->calloc");
//		return;
//	}
//}
void CheckCapacity(Contact* pc);//检查上次保存的信息是否需要扩容
void LoadContact(Contact* pc)
{FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("LoadContact");return;}//读文件Peo tmp = { 0 };while (fread(&tmp, sizeof(Peo), 1, pf)){CheckCapacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}fclose(pf);pf = NULL;
}//文件版本的初始化函数
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity, sizeof(Peo));if (pc->data == NULL){perror("InitContact->calloc");return;}//加载文件中的信息到通讯录LoadContact(pc);
}
//
静态增加联系人
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	//判断通讯录是否满了
//	if (pc->sz == DATA_MAX)
//	{
//		printf("通讯录已满,增加失败\n");
//		return;
//	}
//	//增加信息
//	printf("请输入名字:");
//	scanf("%s", pc->data[pc->sz].name);
//	printf("请输入年龄:");
//	scanf("%d", &(pc->data[pc->sz].age));
//	printf("请输入性别:");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入电话:");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//	//对sz增加,
//	pc->sz++;
//	printf("增加成功\n");
//}
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}
//检查是否需要扩容
void CheckCapacity(Contact* pc)
{if (pc->sz == pc->capacity){Peo* ptr = (Peo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(Peo));if (ptr != NULL){pc->data = ptr;pc->capacity += DEFAULT_INC;printf("增容成功\n");}else{perror("AddContact->realloc");return;}}
}
//增加联系人
void AddContact(Contact* pc)
{assert(pc);//增加容量CheckCapacity(pc);//增加信息printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");
}//显示所有的联系人
void ShowContact(const Contact* pc)
{assert(pc);//判断通讯录内是否有信息if (pc->sz == 0){printf("打印失败,通讯录为空\n");return;}//打印//打印标题printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");//打印信息int i = 0;for (i = 0; i < pc->sz; i++){//打印每个人的信息printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}//通过名字查找被删除人
static int FindByName(Contact* pc, char* name)
{assert(pc);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;//找不到
}
//删除联系人
void DelContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("删除失败,通讯录为空\n");return;}//查找是否存在此人char name[NAME_MAX];printf("请输入被删除人名字:\n");scanf("%s", name);//查找此人,存在返回位置,不存在返回-1int ret = FindByName(pc,name);if (ret == -1){printf("要删除的人不存在\n");return;}//删除(覆盖)此人for (int i = ret; i < pc->sz - 1; i++)	//sz-1 是防止执行体越界,如果要删除的是最后一个元素,通过sz--,直接不访问,{pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//查找联系人
void FindContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("查找失败,通讯录为空\n");return;}//查找此人,存在返回位置,不存在返回-1char name[NAME_MAX];printf("请输入被查找人名字:\n");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要查找的人不存在\n");return;}//显示出来printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}//修改联系人
void ModifyContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("修改失败,通讯录为空\n");return;}//查找此人,存在返回位置,不存在返回-1char name[NAME_MAX];printf("请输入被修改人名字:\n");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要查找的人不存在\n");return;}//修改printf("请输入名字:");scanf("%s", pc->data[ret].name);printf("请输入年龄:");scanf("%d", &(pc->data[ret].age));printf("请输入性别:");scanf("%s", pc->data[ret].sex);printf("请输入电话:");scanf("%s", pc->data[ret].tele);printf("请输入地址:");scanf("%s", pc->data[ret].addr);printf("修改成功\n");
}//目录排序
//void qsort(void* base, size_t num, size_t size,
//	int (*compar)(const void*, const void*));
int cmpare(const void* p1, const void* p2)
{return strcmp(((Peo*)p1)->name, ((Peo*)p2)->name);
}void SortContact(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(Peo), cmpare);
}
//保存信息到文件
void SaveContact(Contact* pc)
{FILE* pf = fopen("contact.txt", "wb");	//二进制读文件if (pf == NULL){perror("SaveContact");return;}//写信息到文件int i = 0;for (i = 0; i < pc->sz; i++){//fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);fwrite(pc->data + i, sizeof(Peo), 1, pf);}fclose(pf);pf = NULL;
}

contact.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30#define DATA_MAX 100#define DEFAULT_SZ 3		//默认容量
#define DEFAULT_INC 2		//扩容量typedef struct Peo		//个人信息结构体
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}Peo;
typedef struct Contact
{Peo* data;//存放数据int sz;		//记录信息人数int capacity;//记录的是通讯录的当前容量
}Contact;//初始化通讯录
//void InitContact(Contact* pc);//动态版本的初始化
void InitContact(Contact* pc);//增加联系人
void AddContact(Contact* pc);//显示所有的联系人
void ShowContact(const Contact* pc);//删除联系人
void DelContact(Contact* pc);//查找联系人
void FindContact(Contact* pc);//修改联系人
void ModifyContact(Contact* pc);//排序联系人
void SortContact(Contact* pc);//销毁通讯录
void DestroyContact(Contact* pc);//保存信息到文件
void SaveContact(Contact* pc);//加载文件信息到通讯录
void LoadContact(Contact* pc);

以上就是利用三章知识点结合做的小项目——通讯录;

文中不足之处还望指点,感激不尽

 

相关文章:

【C语言】——通讯录(静态-动态增长-文件储存)

目录 前言&#xff1a; 一&#xff1a;整体框架 关于通讯录结构体的创建 二&#xff1a;通讯录的功能实现&#xff08;静态&#xff09; 2.1初始化通讯录 2.2增加联系人 2.3打印通讯录 2.4删除联系人 2.5 查找联系人 2.6修改联系人 2.7排序联系人 三&#xff1a;通…...

win10安装nginx及简单使用(命令)

下载 下载地址&#xff1a;http://nginx.org/en/download.html 使用 解压 更改配置 conf目录下nginx.conf 修改为未被占用的端口&#xff0c;地址改成你的地址 server {# 监听端口 listen 9010;# 地址 server_name 127.0.0.1;# 静态资源location / {root html;i…...

【农业生产系统模型】基于R语言APSIM模型进阶应用与参数优化、批量模拟实践技术

随着数字农业和智慧农业的发展&#xff0c;基于过程的农业生产系统模型在模拟作物对气候变化的响应与适应、农田管理优化、作物品种和株型筛选、农田固碳和温室气体排放等领域扮演着越来越重要的作用。APSIM (Agricultural Production Systems sIMulator)模型是世界知名的作物生…...

金融数学方法:梯度下降法

1.算法介绍 梯度下降法是一种常用的优化算法&#xff0c;其通过沿着梯度下降的方向迭代寻找局部极小值。如果沿着梯度上升的方向迭代&#xff0c;就可以找到极大值。 在梯度下降法中&#xff0c;我们首先需要选择一个初始点 x 0 x_0 x0​作为起始位置&#xff0c;然后计算当前位…...

1031 查验身份证

一.问题&#xff1a; 一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下&#xff1a; 首先对前17位数字加权求和&#xff0c;权重分配为&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&#xff0c;8&#xff0c;4&#xf…...

如何共享 Android 不同模块的构建配置

最近想重新梳理学习一遍 Android 的各个知识点&#xff0c;于是新建了一个 AndroidStudy 项目仓库&#xff0c;打算每个知识块新建 1 个 module。 类似这样&#xff1a; AndroidStudy (Root Project) ├─app (Module0) ├─CustomView (Module1) ├─KotlinCoroutines (Modul…...

atlas运维中遇到的问题

1、java.lang.NoClassDefFoundError&#xff1a;javax/ws/rs/core/Link$Builder 主要原因&#xff1a;jsr311-api包中javax.ws.rs.core包中没有Link类&#xff0c;而Atlas以HBase作为元数据存储&#xff0c;HBase本身使用的为javax.ws.rs-api包中的core包&#xff0c;其中有Lin…...

06-React的路由

06-React的路由 1.相关理解 1).SPA的理解 单页Web应用&#xff08;single page web application&#xff0c;SPA&#xff09;。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过ajax请求获取, 并在前端异步展现。…...

虹科方案 | 加州理工学院利用HK-TrueNAS开展地震研究

一、客户背景 加州理工学院(CalTech)是世界顶尖的理工类科学研究型学府之一。加州理工学院地震实验室是加州理工学院地质与行星科学部(GPS)的一个分支机构&#xff0c;成立于1921年&#xff0c;自20年代以来一直是世界地震学研究中心&#xff0c;并且几十年来一直是媒体对大地…...

宝塔面板部署express以及MySql项目

第一次在宝塔面板上部署express和MySql项目&#xff0c;部署过程一直跑不通接口&#xff0c;特此记录一下。 在部署的时候&#xff0c;建议第一步把数据库MySql给跑通&#xff0c;中间好多原因是由于数据库的原因给引起的。 一.连接数据库 &#xff08;1&#xff09;在宝塔面…...

联盟链学习笔记-网络的创建

联盟链学习笔记 初始网络 下图是初始网络网络N的参考图 排序服务 在定义 网络 N 的时候&#xff0c;第一件事情就是定义一个 排序服务O4。O4 最初被配置并且由组织 R4 的一个管理员来启动&#xff0c;并且由 R4 管理。配置 NC4 包含了描述网络管理能力初始集合的规则。最初在…...

System.Drawing.Common.Bitmap跨平台的替代方案

使用SkiaSharp SkiaSharp是Skia Graphics Library的.Net跨平台实现&#xff0c;它可以在Windows&#xff0c;macOS&#xff0c;Linux&#xff0c;iOS&#xff0c;Android和其他平台上使用。 例如需要Linux版&#xff0c;则安装第一个和第四个&#xff1a; 以下是使用SkiaShar…...

深入理解 Java 泛型

没有泛型是怎样的 了解点 Java 历史的都知道,泛型是从 JDK 1.5 版本添加的特性,在 JDK1.5 之前,Java 很多特性都是没有的例如:泛型、注解、自动装箱和拆箱、可变参数。在介绍泛型之前,我们先来看看,如果没有泛型的世界是怎么样的。 假设有一个 List,我只想把 String 类…...

【基础篇】七、Flink核心概念

文章目录 1、并行度2、并行度的设置3、算子链4、禁用算子链5、任务槽6、任务槽和并行度的关系 1、并行度 要处理的数据量很多时&#xff0c;可以把一个算子的操作&#xff08;比如前面demo里的flatMap、sum&#xff09;&#xff0c;"复制"多份到多个节点&#xff0c…...

06-Scala面向对象

面向对象编程 ​ Scala是一门完全面向对象的语言&#xff0c;摒弃了Java中很多不是面向对象的语法。 ​ 虽然如此&#xff0c;但其面向对象思想和 Java的面向对象思想还是一致的 Scala包 1&#xff09;基本语法 Scala中基本的package包语法和 Java 完全一致 例如&#xf…...

【设计模式】单例模式、“多例模式”的实现以及对单例的一些思考

文章目录 1.概述2.单例模式实现代码2.1.饿汉式单例2.2.懒汉式单例2.3.双检锁单例2.4.静态内部类单例2.5.枚举单例 3.对单例的一些思考3.1.是否需要严格的禁止单例被破坏&#xff1f;3.2.懒汉式真的比饿汉式更佳吗&#xff1f;3.3.单例存在的问题 4.其他作用范围的单例模式4.1.线…...

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目 如图所示 我导入了一个git项目后&#xff0c;菜单栏出现了一个git按钮 找不到 导入git项目的按钮了 方式1、 通过idea设置 打开全局设置 如下图 把git先改为none&#xff0c;保存 保存后就可以看到 VCS按钮 导入…...

泛在电力物联网的关键技术与未来发展策略-安科瑞黄安南

摘要: 文章分析了泛在电力物联网的内涵及其主要特征&#xff0c;针对泛在电力物联网的建设目标、基本构架以及关键技术与未来发展策略进行综合探讨&#xff0c;期待得到专业人士的指点。 关键词: 泛在电力物联网&#xff0c; 网络规划&#xff0c; 网络发展 随着能源革命的不…...

iWall:支持自定义的Mac动态壁纸软件

iWall Mac是一款动态壁纸软件&#xff0c;它可以使用任何格式的漂亮视频&#xff08;无须转换&#xff09;、图片、动画、Flash、gif、swf、程序、网页、网站做为您的动态壁纸、动态桌面&#xff0c;并且可以进行交互。 这款软件功能多、使用简单、体积小巧、不占用资源、运行…...

【Docker 内核详解】namespace 资源隔离(四):Mount namespace Network namespace

【Docker 内核详解 - namespace 资源隔离】系列包含&#xff1a; namespace 资源隔离&#xff08;一&#xff09;&#xff1a;进行 namespace API 操作的 4 种方式namespace 资源隔离&#xff08;二&#xff09;&#xff1a;UTS namespace & IPC namespacenamespace 资源隔…...

STM32简介

STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器&#xff0c;常应用在嵌入式领域如&#xff1a; 智能车&#xff08;用stm32做寻迹小车&#xff0c;读取光电传感器或者摄像头数据&#xff0c;然后驱动电机前进和转弯&#xff09;&#xff1b; 无人机&#xff08;用stm3…...

Yum安装JDK11

一、安装命令 &#xff1a; yum install java-11-openjdk二、执行以下命令来查看 JDK 11 的安装信息&#xff1a; yum list installed | grep java-11-openjdk三、找到 JDK 11 的软件包名称&#xff08;使用以下命令来查询软件包的安装位置&#xff09;&#xff1a; rpm -ql…...

[HNCTF 2022 WEEK2]ez_ssrf题目解析

这题主要是引入ssrf这个漏洞攻击&#xff0c;本质上没有更深入的考察 本题是需要我们去伪造一个ssrf的请求头去绕过 题目开始给了我们信息让我们去访问index.php fsockopen函数触发ssrf fsockopen() 函数建立与指定主机和端口的 socket 连接。然后&#xff0c;它将传入的 bas…...

OpenFOAM: twoPhaseEulerFoam解读

twoPhaseEulerFoam全解读之一(转载) 本系列将对OpenFOAM-2.1.1 中的 twoPhaseEulerFoam 求解器进行完全解读&#xff0c;共分三部分&#xff1a;方程推导&#xff0c;代码解读&#xff0c;补充说明。本篇进行方程推导&#xff0c;详细介绍如果从双流体模型出发得到 twoPhaseEu…...

ffmpeg跨平台arm编译-ubuntu

目录 1. 安装必要的编译器2. 安装必要的依赖项3. 配置编译选项4. 编译安装 1. 安装必要的编译器 32位系统&#xff1a; sudo apt-get update sudo apt-get install gcc-arm-linux-gnueabihf sudo apt-get install g-arm-linux-gnueabihf64位系统&#xff1a; sudo apt-get u…...

Vue 网络处理 - axios 异步请求的使用,请求响应拦截器

目录 一、axiox 1.1、axios 简介 1.2、axios 基本使用 1.2.1、下载核心 js 文件. 1.2.2、发送 GET 异步请求 1.2.3、发送 POST 异步请求 1.2.4、发送 GET、POST 请求最佳实践 1.3、请求响应拦截器 1.3.1、拦截器解释 1.3.2、请求拦截器的使用 1.3.3、响应拦截器的使用…...

单目3D目标检测——MonoDLE 模型训练 | 模型推理

本文分享 MonoDLE 的模型训练、模型推理、可视化3D检测结果。 模型原理&#xff0c;参考我这篇博客&#xff1a;【论文解读】单目3D目标检测 MonoDLE&#xff08;CVPR2021&#xff09;_一颗小树x的博客-CSDN博客 源码地址&#xff1a;https://github.com/xinzhuma/monodle 目…...

CSS悬停卡片翻转明信片效果源码附注释

运行效果演示: HTML页面代码: <!DOCTYPE html> <html lang="en" > <head>...

使用kaliber与imu_utils进行IMU、相机+IMU联合标定

目录 1 标定工具编译 1.1 IMU标定工具 imu_utils 1.2 相机标定工具 kaliber 2 标定数据录制 3 开始标定 3.1 IMU标定 3.2 相机标定 3.3 相机IMU联合标定 4 将参数填入ORBSLAM的文件中 1 标定工具编译 1.1 IMU标定工具 imu_utils 标定IMU我们使用imu_utils软件进行标定…...

统一观测丨使用 Prometheus 监控 SQL Server 最佳实践

作者&#xff1a;啃唯 SQL Server 简介 SQL Server 是什么&#xff1f; Microsoft SQL Server 是 Microsoft 推出的关系型数据库解决方案&#xff0c;支持企业 IT 环境中的各种事务处理、商业智能和分析应用程序。Microsoft SQL Server 是市场领先的数据库技术之一。 SQL S…...

凡科网站模板/又一病毒来了比新冠可怕

前言 之前我有整理过一系列文章“支付功能如何测试&#xff1f;”&#xff0c;“抖音直播要如何测试”&#xff0c;“微信红包如何测试”&#xff0c;很多学生说是及时雨&#xff0c;帮助了他们的测试面试&#xff0c;需要的同学可以点击查看&#xff08;附上文章链接&#xf…...

做asp动态网站制作流程/建站软件可以不通过网络建设吗

栈与队列就像一对兄弟一样&#xff0c;学习的时候可以一块学习。 栈的特点&#xff1a;先进后出 队列的特点&#xff1a;先进先出 一、头文件 栈的头文件 #include<stack> 队列的头文件 #include<queue> 二、定义 栈的定义&#xff1a;stack<TYPE> s; 队列…...

怎么选择合肥网站建设/福州百度快速优化

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1811 思路&#xff1a;先处理‘‘&#xff0c;全部合并为同一个节点&#xff0c;然后在拓扑排序就可以了。。。 拓扑排序知识&#xff1a; *如果一次入队入度为零的点大于1则说明拓扑排序序列不唯一*如果排序的…...

一个企业做网站的意义/2022百度搜索风云榜

使用php下载图片的时候遇到md5问题, 源图片通过http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png下载,原图和curl获取到图片源时的md5一致,但使用php中的fwrite后就不行.问sf的朋友们: 如何用PHP保存图片的时候使得md5值不变!代码如:/*** 加载图片**/$save_d…...

长沙网站建设哪家靠谱/郑州见效果付费优化公司

String.prototype.charAt()str.charAt(index)返回字符串中指定位置的字符。字符串中的字符从左向右索引&#xff0c;第一个字符的索引值为 0&#xff0c;最后一个字符(假设该字符位于字符串 stringName 中)的索引值为 stringName.length - 1。如果指定的 index 值超出了该范围&…...

做素材网站存储/百度sem代运营

最佳答案//index下标从0开始public static int[] remove(int[]ary,int index){int[]array new int[ary.length-1]; //返回数组int flag 0; //作为标识&#xff0c;表示是否已删除index位置处的值,0表示未到//满足以下条件&#xff0c;返回nullif(arynull||ary.length<1||i…...