c语言实现通讯录

news/2024/5/6 20:50:06/文章来源:https://blog.csdn.net/qq_68695298/article/details/126755461

目录标题

  • 通讯录的介绍
  • 通讯录的准备
  • 通讯录的初始化
  • 通讯录的添加
  • 通讯录的打印
  • 通讯录的查找并打印
  • 通讯录的删除
  • 通讯录的排序
  • 通讯录的修改
  • 通讯录的改善
  • 动态通讯录的实现
  • 以文件的形式存储

通讯录的介绍

通讯录想必大家都应该不陌生,我们在手机里面都会有通讯录里面记录着我们各个亲人,各个朋友的联系方式,这个通讯里面往往都不止一个电话,还有这个电话的所有者的名字,他的性别他的年龄等等,那么我们这里就要用c语言来实现这个通讯录,并且我们这里不仅仅能够实现存储数据的功能我们还可以实现通讯录的增加,删除,查找,排序,打印等等功能,那么我们这里就以三种不同的形式来实现这个通讯录。

通讯录的准备

首先我们这里的每一个人都是一个元素,但是这个元素中还含有不同的元素,姓名,年龄,性别,电话号码等,所以我们这里就得创建一个结构体将这些不同的元素合成一个整体,那么我们这里的代码就如下:

struct PeoInfo
{char name[20];int age;char sex[10];char tele[12];char addr[30];
};

我们这里的结构体就是这样,但是我们这里还需要对其进行一下改进,因为我们在之后的操作中会对这里的数组大小进行修改,但是等我们代码多的时候改的话它就又不方便了,所以我们这里就采用标识符的形式来代替这里的数字,这样我们在改的时候就会集中一点也不用到处去找了,那么我们的代码就如下:

#include<stdio.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TELE 12
#define MAX_ADDR 30
typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
} PeoInfo;

好每个元素的类型我们就创建好了,那么我们这里的第一种实现的方式就是静态的形式来实现,所以我们这里就得创建一个数组来存储这里的每个元素,因为这里的元素的类型是结构体的类型,所以我们这里的数组也是一个结构体数组,并且我们这里还得创建一个变量用来记录我们这里数组中的元素个数,那么我们这里就将这两个东西放到一个结构体里面这样我们以后就好进行处理,那么我们的代码就如下:

typedef struct contact
{PeoInfo data[MAX];//存放人的信息int count;//当前已有的人数
}contact;

好我们这里的结构体就创建好了,那么我们这里的准备工作就完成了,那么我们接下来就得实现各个函数,来逐步完成我们的通讯录。

通讯录的初始化

我们这个初始化里面做的事就是将结构体里面的count变量初始化为0,并且将这个数组里面的每个字节全部都初始化为0,然后因为我们这个函数里面的操作会改变这个结构体里面的内容,所以我们这个函数的参数就是一个结构体的指针,又因为我们在初始化之前我们肯定是在main函数里面创建了一个结构体,所以我们这里传过来的参数肯定不会是一个空指针,所以我们这里首先得对其进行判断一下,以免传过来的是一个空指针,判断完之后我们就得将这个结构体里面的count的值赋值为0,那我们这里的最后一步就是将这个数组里面的每一个字节全部都初始化为0,那这里我们就可以用我们的memeset这个函数来实现这个功能,那么我们的代码就如下:

void InitContact(contact* pc)
{assert(pc);pc->count = 0;memset(pc->data, 0, sizeof(pc->data));
}

通讯录的添加

好我们将通讯录的初始化实现之后,我们就要往这个通讯录里面添加数据进去,我们这个函数也是得对这个函数里面内容进行改变,所以这里函数的参数就是一个结构体的指针:

void AddContact(contact* pc)

函数的参数完成之后我们就得实现一下这个函数体里面的内容,首先我们还是得判断一下这个参数是否为空,然后这里既然是增加数据的话,我们这里是不是得判断一下这个函数还能不能添加数据啊,如果我们这里的count等于MAX的话,我们是不是就得打印一下数据已满,然后在退出这个函数啊,那么我们这里的函数的实现就如下:

void AddContact(contact* pc)
{assert(pc);if (pc->count == MAX){printf("数据已满,无法添加\n");return;}
}

好!判断完能不能插入数据之后我们就得来插入数据,因为我们这里的参数是一个结构体的指针,所以我们这里就可以直接根据这个指针来改变我们这里结构体里面的值,又因为我们这里是一个结构体的数组,所以我们这里添加数据的时候是不是得按照顺序来一顺添加啊,那我们又如何知道添加数据的位置呢?那这里我们就可以根据count的值来找到数组中的位置,因为我们count的值一开始是0,而我们数组的下标也是从0开始,然后我们每次插入数据之后都会将count的值加1,所以我们在插入的时候还是可以根据count的值来插入数据,因为数组中第二个元素的下表就是1 ,那么这样以此类推的话,我们发现根据这里的conut的值来插入数据是没有什么错误的,那么我们插入数据的代码就是这样:

void AddContact(contact* pc)
{assert(pc);if (pc->count == MAX){printf("数据已满,无法添加\n");return;}printf("请输入名字:>");scanf("%s", pc->data[pc->count].name);printf("请输入年龄:>");scanf("%d", &(pc->data[pc->count].age));printf("请输入性别:>");scanf("%s", pc->data[pc->count].sex);printf("请输入电话:>");scanf("%s", pc->data[pc->count].tele);printf("请输入地址:>");scanf("%s", pc->data[pc->count].addr);pc->count++;printf("增加成功\n");}

通讯录的打印

我把元素添加进去之后我们就得将这个数据打印出来看看,那么这里我们就来实现这么一个打印函数,因为我们之前说过我们的结构体在传参的时候就算不改变里面的元素但是我们还是得传一个指针过去,因为这样做的效率就非常的高,不会消耗多余的内存,那么我们的代码就如下:

void ShowContact(contact* pc)

函数的声明我们知道了,那么接下来我们就实现这个函数,因为我们这里的元素不止一个,所以我们这里得创建一个循环来打印我们这里的数据,那么我们这里就创建一个变量i,将他的初始值赋值为0,然后我们就根据这个变量的值来访问这个结构体数组中的每个元素,然后我们每循环一次都将这个变量的值加一,那么我们这个循环结束条件就是当i>=count的时候,然后我们再在循环里面添加一个打印的函数,用这个函数打印我们的结构体里面的每一个值,那么这里我们的代码就如下:

void ShowContact(contact* pc)
{assert(pc);int i = 0;printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");for (i = 0; i < pc->count; i++){printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}

那么我们这里的三个函数就写完了,我们可以写写代码来测试一下我们这里的代码写的对不对:

#include"contact.h"
int main()
{contact pc;InitContact(&pc);AddContact( &pc);AddContact( &pc);ShowContact(&pc);return 0;
}

那么我们这就运行一下并且输入一些数据进去:
在这里插入图片描述
那么这么看的话我们这里实现的三个函数就是正确的。

通讯录的查找并打印

我们平时在打电话的时候是不是经常会用到查找这个功能,比如说根据电话来查找,根据姓名来查找等等,那么我们这里也来实现这个功能,我们这里的函数声明就是这样:

void SearchContact(Contact* pc)

那么我们这里就以名字的形式来查找联系人,首先我们得创建一个字符数组,然后再把我们要查找的人的姓名放到这个字符数组里面,

void SearchContact(contact* pc)
{assert(pc);char name[MAX_NAME] = { 0 };printf("请输入你想要查找的名字->");scanf("%s", name);
}

然后我们再以这个字符数组里面的内容来依次查找我们这里的结构体数组里面的每个元素,那么我们这里是一个遍历的过程,并且这里比较的元素还是一个字符串的类型,那么我们这里就不能单单的使用等于号来进行比较,我们得用这么一个函数:strcmp,这个函数是专门用来比较字符串的,我们来看看这个函数的介绍:

在这里插入图片描述

我们发现这个函数的作用就是用来比较两个字符串,如果两个字符串相等这个函数返回来的值就是0,如果不相等的话就返回一个不为0的值,那么我们这里就可以根据这个0来做文章,我们可以循环遍历使用这个函数来比较,如果比较的结果为0的话,我们这里就结束循环,并且返回这个元素所在数组中的位置,那么这个查找的功能我们以后在其他的函数我们也会用到所以我们这里就将其直接分装成一个函数我们的代码就如下:

int FindByName(contact* pc, char name[])
{assert(pc);int i = 0;for (i = 0; i < pc->count; i++){if (0 == strcmp(pc->data[i].name, name)){return i;}}return -1;
}

好我们这个函数如果没有找到就会返回一个-1,那么我们在SearchContact
这个函数里面根据这个返回值来打印一些数据出来,如果这个函数返回-1的话我们就打印没有找到该联系人,如果是其他值的话我们就根据这个值来找到数组中的对应值元素,再将这个元素中的数据打印出来那么我们这里的代码就是这样:

void SearchContact(contact* pc)
{assert(pc);char name[MAX_NAME] = { 0 };printf("请输入你想要查找的名字->");scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("没有找到该联系人\n");return;}else{printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}
}

我们来测试一下这个代码:

#include"contact.h"
int main()
{contact pc;InitContact(&pc);AddContact( &pc);AddContact( &pc);SearchContact(&pc);return 0;
}

那么我们这个代码的运行结果如下:
在这里插入图片描述
那么这里我们就可以看到我们该函数的实现是正确的。

通讯录的删除

既然我们的查找实现了,我们这里的删除就非常好实现首先我们得判断一下我们这里的通讯录还能不能删除,当我们的通讯录一个元素都没有的时候我们这里就不能在删除的,然后再根据我们的查找函数找到这个要删除的元素所在的位置,又因为我们这里是删除任意位置的元素并且元素之间的储存是连续的,所以我们这里就直接将这个元素后面的元素依次覆盖前面的元素,那么这里我们就得使用一个循环来完成这个过程,然后再将count的值减减就是我们这个删除的过程,那么我们的代码就如下:

void DelContact(Contact* pc)
{char name[MAX_NAME] = { 0 };assert(pc);int i = 0;if (pc->count == 0){printf("通讯录为空,没有信息可以删除\n");return;}printf("请输入要删除人的名字:>");scanf("%s", name);//删除//1. 查找int pos = FindByName(pc, name);if (pos == -1){printf("要删除的人不存在\n");return;}//2. 删除for (i = pos; i < pc->count-1; i++)//因为下面是i+1,所以我们这里的是小于count-1,而不是count避免越界。{pc->data[i] = pc->data[i + 1];}pc->count--;printf("删除成功\n");
}

那么这里可能有小伙伴们说啊,那我们之前的那个多出来的位置的元素还需要管吗?我们需要将他全部置为0吗?那么我们这里说是没必要的,因为我们这里的count的值减去了一个1,而我们在打印或者增加元素的时候是根据count的值来执行的,所以我们这里就不用担心打印这个多余的数据,因为再增加新的元素的时候我们就会将新进来的数据覆盖掉原来多余的数据,打印的时候也会因为count的值减一而不会再打印一遍多余的数据出来。那么我们这里就可以再来测试一下这个函数的实现是否正确:

#include"contact.h"
int main()
{contact pc;InitContact(&pc);AddContact( &pc);AddContact( &pc);ShowContact(&pc);DelContact(&pc);AddContact(&pc);ShowContact(&pc);return 0;
}

在这里插入图片描述
那么这里就是我们代码的执行结果,大家可以看到一开始gaochang是在第二个位置,然后我们把第一个位置的元素给删除了,然后再添加chengshikang进去,那么我们这时按照来说来说的话gaochang是在第一个位置,而chengshikang是在第二个位置,那么我们这里打印出来看的话也确实是这样的,那这么看的话我们的代码实现就是正确的。

通讯录的排序

我们手机里面的通讯录里面的信息并不是杂乱无章的排序的,而是以以某种规律排序,比如说按照abcdefgxyjk等这样的顺序来排序的,那么我们这里也来实现一下这个类似的功能,我们按照字符串的大小来进行排序,那么这里我们就得用到qsort这个函数,然后qsort所需要的比较的方法就得用到strcmp函数来进行比较,那么这里我们就得来看看这两个函数的介绍:

在这里插入图片描述
在这里插入图片描述
那么我们这个函数就需要4个参数,第一个参数就是第一个元素的地址,第二个元素就是要比较的元素,第三个元素就是每个元素的大小,第四个元素就是我们比较的方法,那么这里他对比较的方法还有一定的约束,说这个比较的方法的返回值是一个整数,如果这个比较函数返回的是一个负数的话,他就会把第一个参数放到前面,相反如果是大于0的数的话,这里就会把第一个元素放到后面,那么我们这里就可以再来看看strcmp这个函数的介绍:
在这里插入图片描述
我们这里就只用观察这个函数的返回值,我们发现这里好像有那么点类似,他说如果第一个参数小于第二个参数的话就返回一个小于0的数,如果大于的话就返回一个大于0的数,那么这里是不是就刚好和我们的qsort所需要的类型是一样的,那么我们这里就可以直接将这个strcmp的返回值作为比较函数的返回,依次来实现我们的比较函数,那么我们这里的函数实现代码就是这样的:

int cmp_peo_by_name(const void* e1, const void* e2)
{return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(contact* pc)
{assert(pc);qsort(pc->data, pc->count, sizeof(PeoInfo), cmp_peo_by_name);printf("排序成功\n");
}

通讯录的修改

有时候我们在使用通讯录的时候会对一些信息进行修改,比如说有个哥们要搬家了,我得把他的地址从北京改成武汉等等,那么我们这里就得增加一个修改的功能,那么我们要修改一个元素的内容,那第一步是不是就是找到这个人在哪里,等找到之后我们就根据这个元素的下标来访问这个元素的内部元素,再对其一一修改啊,那这里的思路非常的简单我们就直接看代码:

void ModifyContact(contact* pc)
{assert(pc);char name[MAX_NAME] = { 0 };printf("请输入要修改人的名字:>");scanf("%s", name);//1. 查找int pos = FindByName(pc, name);if (pos == -1){printf("要修改的人不存在\n");return;}printf("要修改的人的信息已经查找到,接下来开始修改\n");//2. 修改printf("请输入名字:>");scanf("%s", pc->data[pos].name);printf("请输入年龄:>");scanf("%d", &(pc->data[pos].age));printf("请输入性别:>");scanf("%s", pc->data[pos].sex);printf("请输入电话:>");scanf("%s", pc->data[pos].tele);printf("请输入地址:>");scanf("%s", pc->data[pos].addr);printf("修改成功\n");
}

通讯录的改善

那么看到这里我们的通讯录就实现完成了,但是这里我们还得将其进一步的完善,因为我们在测试的时候是我们程序员自己添加代码进去的 但是使用者们不会自己添加啊,所以我们这里就得添加一个菜单进去,然后使用者就可以根据这个菜单来自行选着对应的功能,那么我们这里就是一个老套路了,创建一个循环在循环里面再添加一个switch语句,然后再根据我们的寻找来执行不同的函数功能,我们的代码就如下:

int main()
{contact con;InitContact(&con);int input = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 0:printf("退出通讯录\n");break;case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:SearchContact(&con);break;case 4:ModifyContact(&con);break;case 5:ShowContact(&con);break;case 6:SortContact(&con);break;default:printf("选择错误请重新选择\n");break;}} while (input);return 0;
}

动态通讯录的实现

我们上面的实现的通讯录存在着一个问题就是如果我们的放进去的元素过多的话,我们之前的数组装不下怎么办呢?那是不是只能我们手动的修改代码啊,那么我们这里就是一个比较难受的缺陷,所以我们这里就对这个通讯录进行一下修改改成一个动态的能够自行的扩容的形式,那么这里我们就得用到动态内存开辟里面的内容,我们来看看realloc这个个函数的介绍:
在这里插入图片描述
这个函数需要两个参数一个是地址,另外一个是你要开辟的新空间的大小,那么这里的地址就是一个你已经开辟的动态内存,也可以是一个空指针,如果是空指针的话这个函数的作用就和malloc是一模一样的,因为我们这个函数的返回值是一个指针这个指针指向的是我们动态开辟的地址,那么我们就得将这里的结构体进行一下修改,将那个数组改成一个指针,并且我们这里还得加一个变量用来记录我们这里的容量那么我们的代码就如下:

typedef struct contact
{PeoInfo* data;//存放人的信息int count;//记录当前通讯录中实际人的个数int capacity;//当前通讯录的容量
}contact;

我们这里的结构体就发生了修改,那么我们这里的结构体就发生了修改,那么我们这里的初始化的函数就也得发生一下修改:我们这个初始化就得将这里的指针先赋值为一个已经开辟好的一段动态内存的地址,因为我们这里没有一个元素所以将count的值赋值为0,因为我们这里已经指向了一个已经开辟好的内存空间,所以我们这里就得将capacity的值赋值为那个空间所能装下的元素的个数那么我们修改之后的代码就如下:

int InitContact(contact* pc)
{assert(pc);pc->count = 0;pc->data = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (pc->data == NULL){printf("InitContact::%s\n", strerror(errno));return 1;}pc->capacity = DEFAULT_SZ;return 0;
}

好我们这里的初始化函数修改之后,还得将添加元素的函数进行一下修改,那么我们这里的修改就得加一个东西上去就是看我们这里的内存还是否足够,如果不够的话我们这里就得扩容,那什么情况下是足够的呢?是不是就是当count的值和capacity的值相等的时候就是足够的啊,那么我们这里就单独的写一个函数用来判断是否需要增容,在这个函数里面我们就先用if语句来判断一下count的值和capacity的值是否相等,如果相等我们就来进行扩容,因为realloc这个函数扩容可能成功也可能失败,所以我们这里就先创建一个执政来接受一下这个返回值,如果扩容成功了我们就将这个指针的值复制到我们结构体里面的那个指针并将这个结构体里面的capacity的值变成新的容量,如果这个指针为空的话,我们这里就打印一下这里扩容失败,那么我们这个检查函数的实现就如下:

void CheckCapacity(Contact* pc)
{if (pc->count == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){printf("AddContact::%s\n", strerror(errno));return;}else{pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");}}
}

我们检查函数实现之后我们的增加函数就非常好的实现,因为我们的数组名就是数组首元素的地址,而我们这里的指针也是首元素的地址,所以我们这里不需要做出过大的改动,直接加一个检查函数上去,并将判断满了的if语句删除掉就可以了

void AddContact(Contact* pc)
{assert(pc);//增容CheckCapacity(pc);//printf("请输入名字:>");scanf("%s", pc->data[pc->count].name);printf("请输入年龄:>");scanf("%d", &(pc->data[pc->count].age));printf("请输入性别:>");scanf("%s", pc->data[pc->count].sex);printf("请输入电话:>");scanf("%s", pc->data[pc->count].tele);printf("请输入地址:>");scanf("%s", pc->data[pc->count].addr);pc->count++;printf("增加成功\n");
}

那么这里的增加函数完成了之后,我们就只剩下最后一个步,就是添加一个函数上去,因为我们这里是动态申请的空间,所以我们这个空间在不用之后就得释放掉,那么我们这里就得创建一个函数来释放我们这里的函数,那这个释放的过程就是将这里的动态开辟的空间释放掉,然后将这个指针初始化为空再将这两个整型变量的值赋值为0,这就是我们释放函数所要做的事,那么我们的代码就如下:

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

那这个函数我们就得放到突出通讯的那个选项里面,这里我们就将这个通讯录修改完了。

以文件的形式存储

大家在运行这个代码的时候不知道发现一个问题没有就是我们这里每次运行这个函数的时候都得重新输入数据,那我们这里能不能将代码修改一下,让其能够我们在运行结束的时候自动的将数据存储起来,然后等我们在运行的时候就将数据拿出来打印到我们的屏幕上面去呢?那么这里就得用到我们在文件上面学的知识,在我们文件结束的时候我们就将这个数组中的所有元素的内容都放到我们的文件里面去,等再运行程序的时候我们就将这个文件里面的内容再打印出来,那么我们这里就专门创建一个函数出来:首先以写的形式打开一个文件,然后我们再用fwirte函数将这个数组中的内容输出进文件里面,那么我们这里就来看看这个函数的基本介绍:
在这里插入图片描述
那么这个函数就有4个参数,第一个是一个指针也就是源数据的地址,第二个是每个元素的大小,第三个就是有多少个元素,第四个就是输出到哪个文件里面去,那么这里就简单了我我们直接将这里的元素个数写为1,然后放到一个循环里面,这个循环的次数就是我们这里的元素的个数,那么我们的代码就如下:

void SaveContact(const Contact* pc)
{assert(pc);FILE* pfWrite = fopen("contact.txt", "w");if (pfWrite == NULL){perror("SaveContact");return;}//写文件-二进制的形式int i = 0;for (i = 0; i < pc->count; i++){fwrite(pc->data+i, sizeof(PeoInfo), 1, pfWrite);}fclose(pfWrite);pfWrite = NULL;
}

这个将数据输出到我们的文件里面这个函数实现之后,我们就得在开头实现将文件里面内容打印出来,那么这里的打印并不是简单的打印,我们还得对这些数据进行操作,所以更准确的说是我们得将这些数据提取出来,放到外面开辟的动态空间里面去,那么我们这里就可以用到这么一个函数:fread,我们来看看这个函数的介绍:
在这里插入图片描述
那么咋眼一看好像也没有什么变化,那么这里第一个参数的意思就是将文件里面的数据提取出来放到我们这个指针所指向的空间里面去,那么我们这里就单独创建一个函数,在这个函数里面创建一个结构体的变量,然后我们这里每读到一个元素,就将这个元素放到我们这个结构体变量里面去,再将这个结构体变量赋值给我们的动态开辟的地址里面去,再将这个结构体里面的conut的值加一,但是这里要注意的一点就是我们这里每次循环都得检查一下我们这里的内存够不够,然后我们在将这个整个函数放到我们的初始化函数里面去,那么我们的代码实现就如下:

void LoadContact(contact* pc)
{FILE* pfRead = fopen("contact.txt", "r");if (pfRead == NULL){perror("LoadContact");return;}PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pfRead) == 1){CheckCapacity(pc);pc->data[pc->count] = tmp;pc->count++;}fclose(pfRead);pfRead = NULL;
}int InitContact(contact* pc)
{assert(pc);pc->count = 0;pc->data = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (pc->data == NULL){printf("InitContact::%s\n", strerror(errno));return 1;}pc->capacity = DEFAULT_SZ;//加载文件的信息到通讯录中LoadContact(pc);return 0;
}

那么这里我们的通讯录实现就完成了。
点击此处获取代码

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

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

相关文章

爬虫数据可视化前的环境准备(已安装python环境前提下)

一、requests请求库安装 在桌面右键打开终端输入:pip install requests 二、Beautiful Soup解析库安装 终端输入:Beautiful Soup 4安装:pip install bs4 lxml安装:pip install lxml三、matplotlib安装下载miniconda下载地址:https://docs.conda.io/en/latest/miniconda.ht…

CF102411 ICPC 2019-2020 North-Western Russia Regional Contest题解

A Accurate Movement 签到 M Managing Difficulties 签到 B Bad Treap 已知\(y=\sin(x)\),要求给出数组\(a[n]\),满足\(\forall i,j\in[1,n],a[i]\neq a[j]\),都有\(\sin(a[i])\neq \sin(a[j])\)。 这里又一种不怎么玄的写法,就是我们找到一个整数\(x\),\(sin(x)\)非常非常…

计算机的概述

计算机是由硬件系统(hardware system)和软件系统(software system)两部分组成的。硬件系统电源电源是电脑中不可缺少的供电设备,它的作用是将220V交流电转换为电脑中使用的5V、12V、3.3V直流电,其性能的好坏,直接影响到电脑其他设备工作的稳定性,进而会影响整机的稳定性…

AXI MCDMA 仿真与工作流程分析

说明 关于背景知识,可以先看 https://www.cnblogs.com/xingce/p/16386108.html 引用一段官方的说明,AXI MCDMA存在的主要目的是为了节约资源,我们想要使用这个模块的主要目的也是为了降低资源消耗,从而可以将系统部署在更小面积的FPGA芯片上,当然,具体的效果还需要进一步…

软件定义网络第一次作业,问题与解决方法

软件定义网络第一次作业,问题与解决方法 实验结果截图:实验总结: 1.若使用VMware Workstation Pro。 版本最好使用20.04版本,网络较稳定且兼容性好。且22.04版本可能无法安装Vmware tools。 2.遇到网络无法访问,可尝试换源。 3.若需要压缩包,可在虚拟机中下载,或从电脑拖…

【kali】一款黑客们都在使用的操作系统

&#x1f495;&#x1f495;&#x1f495; 博主昵称&#xff1a;摆烂阳&#x1f495;&#x1f495;&#x1f495; &#x1f970;博主主页跳转链接 &#x1f469;‍&#x1f4bb;博主研究方向&#xff1a;web渗透测试 、python编程 &#x1f4c3; 博主寄语&#xff1a;希望本篇文…

共享单车需求量登记分类及影响因素分析——基于机器学习模型的比较分析

全文链接&#xff1a;http://tecdat.cn/?p28519 作者&#xff1a;Yiyi Hu 近年来&#xff0c;共享经济成为社会服务业内的一股重要力量。作为共享经济的一个代表性行业&#xff0c;共享单车快速发展&#xff0c;成为继地铁、公交之后的第三大公共出行方式。但与此同时&…

【笔记】Python网络爬虫与信息提取

实战&#xff1a;总结知识点疫情爬虫Re正则表达式Re库的使用scrapy爬虫框架介绍Scrapy常用命令网络爬虫技术亮点&#xff1a;1、采用requests发送请求&#xff0c;获取响应2、采用BeautifulSoup4解析页面数据3、采用正则表达式 提取不规则字符串4、采用json模块处理json格式数据…

Java架构师常见基础面试题(附答案)

随着每日确诊病例人数的减少以及治愈患者人数增多&#xff0c;随着这场抗“疫”战争即将以胜利告终&#xff0c;接踵而来的是企业复工、金三银四求职高峰季的来临。有很多Java工程师想要把握住这个机会&#xff0c;实现升职加薪、成为Java架构师。但你知道企业在招聘面试时会提…

证件照换底色

阅读原文 如有侵权,请联系立即删除。 5种方法轻松给证件照换底色不同底色的证件照有着不同的用途。如白底的证件照一般用于身份证、港澳通行证等用途;而蓝底的证件照则用于工作证、简历等。例如我们需要提供蓝色背景的证件照,而手头只有白色背景的证件照,该怎么办呢?其实我…

开学季征文丨来大学已两年,我还有几个两年?

&#x1f44b;写在前面 大家好&#xff0c;我是陈橘又青&#xff0c;一名双非本科大学生&#xff0c;计算机科学与技术专业&#xff0c;最近因为疫情的原因&#xff0c;开学以来一直在家里上网课&#xff0c;也不是很忙&#xff0c;所以我想借着这次开学季征文活动&#xff0c;…

羧基化聚苯乙烯-二氧化硅复合材料/季铵化壳聚糖掺杂荷正电聚苯乙烯微球的制备步骤

今日小编为大家分享了羧基化聚苯乙烯-二氧化硅复合材料/季铵化壳聚糖掺杂荷正电聚苯乙烯微球的制备步骤&#xff0c;一起来看&#xff01; 羧基化聚苯乙烯-二氧化硅复合超疏水涂层的制备方法,其特征在于包括如下步骤&#xff1a; (聚苯乙烯种子微球的制备;羧基修饰的聚苯乙烯微…

【控制】滑模控制,小例子,有程序有结果图

目录滑模控制的一点笔记和看法1【控制】滑动模型控制&#xff08;Sliding Mode Control&#xff09;2【控制】滑模控制&#xff0c;小例子&#xff0c;有程序有结果图3【控制】滑模控制&#xff0c;滑模面的选择文章目录1 问题描述2 滑模控制器设计2.1 滑模面选择2.2 控制器设计…

麻了,别再为难软件测试员了

前言 有不少技术友在测试群里讨论&#xff0c;近期的面试越来越难了&#xff0c;要背的八股文越来越多了,考察得越来越细&#xff0c;越来越底层&#xff0c;明摆着就是想让我们徒手造航母嘛&#xff01;实在是太为难我们这些测试工程师了。 这不&#xff0c;为了帮大家节约时…

hive中使用iceberg表格式时锁表总结

1. 原因 写入iceberg表时,会在hive_locks表中插入一条记录,表示该表正在被写入(hive中的独占锁)当数据插入完成后,会自动删除该条记录。 2. 出现场景 (1)在同时往同一个iceberg表中写入数据时,会出现Retrying task after failure: Waiting for lock之类的警告信息 如果有…

Docker 环境 Nacos2 MySQL8

本文介绍 docker 环境下安装并单机运行 Nacos2,使用 docker 环境下的 MySQL 8 存储数据。本文介绍 docker 环境下安装并单机运行 Nacos2,使用 docker 环境下的 MySQL 8 存储数据。 1 拉取镜像 1.1 创建目录 在硬盘上创建 nacos 的有关目录: mkdir -p /Users/yygnb/dockerMe/…

FPGA之旅设计99例之第十三例-----FPGA在OLED上显示DHT11数据

一. 简介 这是FPGA之旅设计的第十三例啦&#xff0c;本例是一个综合性的例程&#xff0c;基于OLED屏幕显示&#xff0c;和DHT11温湿度采集&#xff0c;将DHT11采集到的温湿度显示到OLED屏幕上。 在开始本例之前&#xff0c;先补充一下&#xff0c;在上例中&#xff0c;代码中…

Webpack 打包 - 14. html压缩

这里使用 html-webpack-plugin 插件压缩 html 文件。 1.文件结构 2.代码 index.html<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>webpack</title> </head> <body> <!--这里…

《Hyperspectral Image Classification With Deep Feature Fusion Network》论文笔记

论文题目《Hyperspectral Image Classification With Deep Feature Fusion Network》 论文作者:Weiwei Song, Shutao Li, Leyuan Fang,Ting Lu 论文发表年份:2018 网络简称:DFFN 一、本文提出的挑战 1.由于光谱混合和光谱特征空间变异性的存在,HSIs通常具有非常复…