通讯录实现【C语言】

目录

前言

一、整体逻辑分析

二、实现步骤

1、创建菜单和多次操作问题

2、创建通讯录

3、初始化通讯录

4、添加联系人

5、显示联系人

6、删除指定联系人

​7、查找指定联系人

8、修改联系人信息

9、排序联系人信息

三、全部源码


前言

我们上期已经详细的介绍了自定义类型,本期我们来用学过的知识来做个小项目来练习练习。本期我们将用C语言实现通讯录静态版!后期介绍了动态内存管理和文件操作我们将会在此版本的基础上进行优化改进!

一、整体逻辑分析

我们还和以前实现三子棋和扫雷小项目一样,先对整体工程的逻辑尽可能详细的梳理,否则一开就是一顿狂敲,最后一走发现全是Bug这样就不好了!我们一开始尽可能的分析清楚,后面即使出现了问题也能快速确定!本期还是和往期一样采用多文件编程!OK,我们下面一起来梳理一下这个小项目的基本实现逻辑:

1、创建菜单和多次操作问题

2、创建通讯录

3、通讯录的初始化以及增删查改等操作

二、实现步骤

1、创建菜单和多次操作问题

我们期望当我们进行对通讯录操作时可以给我们在进行操作前给一个菜单功能我们操作!考虑到后面还要多次操作通讯录(增删查改等)我们结合起来很快想到用do..while循环处理最为合理,这里以前写过两三遍了我们直接上代码:

#include"contact.h"void menu()
{printf("*****************************************\n");printf("********* 1. add     2. del    **********\n");printf("********* 3. search  4. modify **********\n");printf("********* 5. show    6. sort   **********\n");printf("********* 0. exit              **********\n");printf("*****************************************\n");
}void test()
{int input = 0;do{menu();printf("请选择操作数:> ");scanf("%d", &input);switch (input){case 1://addbreak;case 2://delbreak;case 3://searchbreak;case 4://modifybreak;case 5://showbreak;case 6://sortbreak;case 0:printf("退出成功!\n");break;default:printf("选择数非法!\n");break;}} while (input);
}int main()
{test();return 0;
}

看效果:

2、创建通讯录

我们在对通讯录进行各种操作前先得有个通讯录吧!通讯录的本质还是描述一个人的属性例如:姓名、年龄、性别、电话、住址等!这些都是不同的类型,我们很容易想到用结构体就能解决!但这只是描述一个人,你的通讯录不可能只有一个人吧应该是有很多个!而这些联系人又是同一类型,因此采用结构体数组来创建通讯录!

typedef struct PeoInfo
{char name[20];int age;char sex[5];char tele[15];char addr[20];
}PeoInfo;

这就是描述一个人基本属性的结构体!当创建好了这个结构体后,我们就可以在test.c这个文件中do..while循环那里可以创建结构体数组来作为通讯录了!

但这样写会有个问题就是,当你存入或删除联系人后想打印出来看看是此时通讯录中的联系人时应该打印多少?我们还想不知道。所以这里我们还得再定义一个变量sz来记录通讯录的大小!

其实我们发现,sz不仅是可以记录通讯录的大小,而且增加联系人的时候只需要增加到sz位置即可,增加一个sz++,当删除一个sz--;这样其实 sz和通讯录是绑定在一起的,我们不妨在对通讯录进行一层封装,把他也封装成一个结构体,一个成员是PeoInfo结构体数组,一个是记录通讯录大小的sz:

typedef struct PeoInfo
{char name[20];int age;char sex[5];char tele[15];char addr[20];
}PeoInfo;typedef struct Contact
{PeoInfo data[100];int sz;
}Contact;

然后再在test.c文件中创建即可!

OK!这个创建通讯录记好了!其实这里还可已在稍微优化一下:我们发现两个结构体中都出现了大量的常数,我们万一后期需求有变,这些都得改!因此为了后期修改方便,我们把这些都改成#define的常量,后期修改起来容易!这里你可能会说上期不是介绍了枚举吗,这里正好是多个常量枚举不是更好吗?这里枚举确实可以达到目的,但枚举是在没开始前就能列举出来所有可能,我们这个可不是!所以,这里不用枚举!

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 15
#define ADDR_MAX 20
#define MAX 100typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;

这样才是当前逻辑下的最优代码!

3、初始化通讯录

当我们创建好了通讯录后我们先对其进行一个初始化!把结构体数组的每个元素都初始化为0,通讯录大小也置为0!因为我们要改变结构体的内容所以应该传地址!我们这里采用的是memset这个函数直接初始化为0,也可以用个循环来初始化!不了解memset的点击memset

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

4、添加联系人

我们前面已经说过了,只需要在sz的位置增加即可!但要考虑通讯录满的情况!

void AddContact(Contact* pc) 
{assert(pc);//通讯录已满if (pc->sz == 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);pc->sz++;printf("添加成功!\n");
}

OK,我们下面先来写一个显示联系人,来验证一下是否添加成功!

5、显示联系人

显示联系人就是把通讯录中的联系人打印在控制台!

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

OK,我们来看看是否添加成功以及显示联系人!

OK,添加联系人和显示联系人都成功了!说明我们上面逻辑没有问题!

6、删除指定联系人

我们输入要删除的人的姓名,进行查找,找到了删除,否则输出没有此联系人!注意考虑通讯录为空的情况!这里提到了查找,这个查找和通讯录的那个查找有点不一样,这个是查找后返回下标即可,那个是还要打印联系人信息功能不一样。因此我们单独在封装一个函数!

//查找要删除的人并返回下标
int FindContact(const Contact* pc, const char* name)
{for (int 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] = { 0 };printf("请输入要删除人的姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){//删除for (int i = pos; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人!\n");}else{printf("没有此联系人!\n");}
}

这里要注意的是比较字符串要用strcmp,不能用 == 这个我们在字符串函数和内存函数那一期详细介绍过!另外注意删除的时候那里下标越界问题!

看效果:

 7、查找指定联系人

查找指定联系人还是先按指定方式进行查找, 找到了打印,否则输出没有此联系人!这里显示一个联系人的这个里后面修改联系人也可能要用所以我们为了方便把他封装成一个函数后面直接调用即可!


//显示单个联系人信息
void Print(const Contact* pc, int pos)
{assert(pc);printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}//查找指定联系人
void Search(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找联系人姓名:> ");scanf("%s", name);int pos = -1;//初始化为-1表示没有此联系人for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){pos = i;//找到了break;}}if (pos != -1){Print(pc, pos);}else{printf("没有此联系人!\n");}
}

其实还可以在简洁一点,上面已经实现了FindContact我们可以用一下:

void Search(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找联系人姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){Print(pc, pos);}else{printf("没有此联系人!\n");}
}

看效果:

8、修改联系人信息

修改联系人信息这块就有很多可能,比如只修改一项例如名字或性别等,也有可能修改多项例如名字、年龄等,也有可能得全部修改这几种情况。当我们要修改之前群殴我们能还是期望有一个菜单供我们选择,当修改完一项后我们可能还要继续修改。基于此我们采用和test.c文件中得do...while循环+菜单!

//修改联系人信息菜单
void menu1()
{system("cls");printf("*****************************************\n");printf("********* 1. name     2. age   **********\n");printf("********* 3. sex      4. tele  **********\n");printf("********* 5. addr     6. all   **********\n");printf("********* 0. exit              **********\n");printf("*****************************************\n");
}//修改名字
void ModName(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人姓名:> ");scanf("%s", pc->data[ret].name);printf("修改成功!\n");
}//修改年龄
void ModAge(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人年龄:> ");scanf("%d", &pc->data[ret].age);printf("修改成功!\n");
}//修改性别
void ModSex(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人性别:> ");scanf("%s", &pc->data[ret].sex);printf("修改成功!\n");
}//修改电话
void ModTele(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人电话:> ");scanf("%s", &pc->data[ret].tele);printf("修改成功!\n");
}//修改住址
void ModAddr(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人住址:> ");scanf("%s", &pc->data[ret].addr);printf("修改成功!\n");
}void ModAll(Contact* pc, int ret)
{assert(pc);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 ModContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("通讯录为空,无法修改!\n");return;}char name[NAME_MAX] = { 0 };printf("请输入要修改系人姓名:> ");scanf("%s", name);//判断是否有该联系人int ret = FindContact(pc, name);//有该联系人if (ret != -1){int n = 0;do{menu1();printf("请选择修改内容:> ");scanf("%d", &n);//修改switch (n){case 1:ModName(pc,ret);break;case 2:ModAge(pc, ret);break;case 3:ModSex(pc, ret);break;case 4:ModTele(pc, ret);break;case 5:ModAddr(pc, ret);break;case 6:ModAll(pc, ret);break;case 0:printf("修改结束!\n");break;default:printf("选择数非法!\n");break;}} while (n);}else{printf("没有此联系人!\n");}
}

看效果:(小编做了清屏)

修改前:

 修改后:

OK,还是比较成功的!我们再来进行对他实现一下排序!

9、排序联系人信息

我们上面已经实现了通讯录的增删查改的基本功能!我们想让他再有一个排序功能,比如按名字排序,或年龄排序!我们在指针进阶那块介绍过回调函数,这里我们用qsort进行对通讯录排序!我们期望还是和上面一样一开始有个菜单选择!


//排序菜单
void menu2()
{system("cls");printf("**********************************\n");printf("***** 1. name    2. age **********\n");printf("**********************************\n");
}//名字比较函数
int cmp_name(const void* str1, const void* str2)
{//return strcmp(((PeoInfo*)str1)->name, ((PeoInfo*)str2)->name);return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}//名字排序
void SortName(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{//return ((PeoInfo*)str1)->age - ((PeoInfo*)str2)->age;return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//年龄排序
void SortAge(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}//排序联系人信息
void SortContact(Contact* pc)
{assert(pc);//判断为空if (pc->sz == 0){printf("通讯录为空,无法排序!\n");Sleep(3000);system("cls");return;}menu2();int n = 0;printf("请选择排序方式:> ");scanf("%d", &n);//排序switch (n){case 1:SortName(pc);system("cls");printf("排序成功!\n");break;case 2:SortAge(pc);system("cls");printf("排序成功!\n");break;default:printf("选择数非法!\n");Sleep(3000);system("cls");break;}
}

看效果:

排序前(年龄):

 排序后(年龄):

排序前(名字):

 排序后(名字):

OK,实现了排序!

三、全部源码

 contact.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 15
#define ADDR_MAX 20
#define MAX 100typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;//初始化通讯录
void InitContact(Contact* pc);//添加联系人
void AddContact(Contact* pc);//显示联系人
void ShowContact(const Contact* pc);//删除联系人
void DelContact(Contact* pc);//查找指定联系人
void Search(const Contact* pc);//修改联系人
void ModContact(Contact* pc);//排序联系人信息
void SortContact(Contact* pc);

contact.c

#include"contact.h"//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}//增加联系人
void AddContact(Contact* pc) 
{assert(pc);//通讯录已满if (pc->sz == MAX){printf("通讯录已满,无法添加!\n");Sleep(2000);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);pc->sz++;printf("添加成功!\n");Sleep(1000);
}//显示联系人
void ShowContact(const Contact* pc)
{assert(pc);printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");for (int i = 0; i < pc->sz; i++){printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}//查找要删除的人并返回下标
int FindContact(const Contact* pc, const char* name)
{for (int 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");Sleep(2000);return;}char name[NAME_MAX] = { 0 };printf("请输入要删除人的姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){//删除for (int i = pos; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人!\n");Sleep(1000);}else{printf("没有此联系人!\n");Sleep(2000);}
}//显示单个联系人信息
void Print(const Contact* pc, int pos)
{assert(pc);printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}//查找指定联系人
void Search(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找联系人姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){Print(pc, pos);}else{printf("没有此联系人!\n");Sleep(2000);system("cls");}
}//修改联系人信息菜单
void menu1()
{system("cls");printf("*****************************************\n");printf("********* 1. name     2. age   **********\n");printf("********* 3. sex      4. tele  **********\n");printf("********* 5. addr     6. all   **********\n");printf("********* 0. exit              **********\n");printf("*****************************************\n");
}//修改名字
void ModName(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人姓名:> ");scanf("%s", pc->data[ret].name);
}//修改年龄
void ModAge(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人年龄:> ");scanf("%d", &pc->data[ret].age);
}//修改性别
void ModSex(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人性别:> ");scanf("%s", &pc->data[ret].sex);
}//修改电话
void ModTele(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人电话:> ");scanf("%s", &pc->data[ret].tele);
}//修改住址
void ModAddr(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人住址:> ");scanf("%s", &pc->data[ret].addr);
}void ModAll(Contact* pc, int ret)
{assert(pc);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);
}//修改联系人
void ModContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("通讯录为空,无法修改!\n");Sleep(2000);system("cls");return;}char name[NAME_MAX] = { 0 };printf("请输入要修改系人姓名:> ");scanf("%s", name);//判断是否有该联系人int ret = FindContact(pc, name);//有该联系人if (ret != -1){int n = 0;do{menu1();Print(pc, ret);printf("请选择修改内容:> ");scanf("%d", &n);//修改switch (n){case 1:ModName(pc,ret);break;case 2:ModAge(pc, ret);break;case 3:ModSex(pc, ret);break;case 4:ModTele(pc, ret);break;case 5:ModAddr(pc, ret);break;case 6:ModAll(pc, ret);break;case 0:printf("修改结束!\n");Sleep(2000);system("cls");break;default:printf("选择数非法!\n");Sleep(2000);system("cls");break;}} while (n);}else{printf("没有此联系人!\n");Sleep(2000);system("cls");}
}//排序菜单
void menu2()
{system("cls");printf("**********************************\n");printf("***** 1. name    2. age **********\n");printf("**********************************\n");
}//名字比较函数
int cmp_name(const void* str1, const void* str2)
{//return strcmp(((PeoInfo*)str1)->name, ((PeoInfo*)str2)->name);return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}//名字排序
void SortName(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{//return ((PeoInfo*)str1)->age - ((PeoInfo*)str2)->age;return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//年龄排序
void SortAge(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}//排序联系人信息
void SortContact(Contact* pc)
{assert(pc);//判断为空if (pc->sz == 0){printf("通讯录为空,无法排序!\n");Sleep(3000);system("cls");return;}menu2();int n = 0;printf("请选择排序方式:> ");scanf("%d", &n);//排序switch (n){case 1:SortName(pc);system("cls");printf("排序成功!\n");break;case 2:SortAge(pc);system("cls");printf("排序成功!\n");break;default:printf("选择数非法!\n");Sleep(3000);system("cls");break;}
}

test.c

#include"contact.h"void menu()
{printf("*****************************************\n");printf("********* 1. add     2. del    **********\n");printf("********* 3. search  4. modify **********\n");printf("********* 5. show    6. sort   **********\n");printf("********* 0. exit              **********\n");printf("*****************************************\n");
}void test()
{int input = 0;Contact con;InitContact(&con);do{menu();printf("请选择操作数:> ");scanf("%d", &input);switch (input){case 1:AddContact(&con);system("cls");break;case 2:DelContact(&con);system("cls"); break;case 3:system("cls");Search(&con);break;case 4:ModContact(&con);break;case 5:system("cls");ShowContact(&con);break;case 6:SortContact(&con);break;case 0:printf("退出成功!\n");break;default:printf("选择数非法!\n");break;}} while (input);
}int main()
{test();return 0;
}

OK,本期分享就到这里!好兄弟,我们下期再见!

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

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

相关文章

Java SpringBoot Vue ERP系统

系统介绍 该ERP系统基于SpringBoot框架和SaaS模式&#xff0c;支持多租户&#xff0c;专注进销存财务生产功能。主要模块有零售管理、采购管理、销售管理、仓库管理、财务管理、报表查询、系统管理等。支持预付款、收入支出、仓库调拨、组装拆卸、订单等特色功能。拥有商品库存…

ubuntu设置共享文件夹成功后却不显示找不到(已解决)

1.首先输下面命令查看是否真的设置成功共享文件夹 vmware-hgfsclient如果确实已经设置过共享文件夹将输出window下共享文件夹名字 2.确认自己已设置共享文件夹后输入下面的命令 //如果之前没有命令包则先执行sudo apt-get install open-vm-tools sudo vmhgfs-fuse .host:/ /mn…

十六、Spring Cloud Sleuth 分布式请求链路追踪

目录 一、概述1、为什么出出现这个技术&#xff1f;需要解决哪些问题2、是什么&#xff1f;3、解决 二、搭建链路监控步骤1、下载运行zipkin2、服务提供者3、服务调用者4、测试 一、概述 1、为什么出出现这个技术&#xff1f;需要解决哪些问题 2、是什么&#xff1f; 官网&am…

spss---如何使用信度分析以及案例分析

信度分析 问卷调查法是教育研究中广泛采用的一种调查方法&#xff0c;根据调查目的设计的调查问卷是问卷调查法获取信息的工具&#xff0c;其质量高低对调查结果的真实性、适用性等具有决定性的作用。 为了保证问卷具有较高的可靠性和有效性&#xff0c;在形成正式问卷之 前&…

CLion:最好用的c/c++编写工具(最详细安装教程)

目录 一.前言介绍 1.下载安装 1.1右上角点击下载 1.2选择自己操作系统&#xff0c;然后点击下载 1.3选择next 1.4 更改路径 1.5D盘最好 1.6 按照我的选择配置环境 1.7install安装 1.8 安装完成 2、mingw64安装 2.1下载资源压缩包 2.2mingw64放入到合适的位置&#xff0c;…

Redis五大基本数据类型及其使用场景

文章目录 **一 什么是NoSQL&#xff1f;****二 redis是什么&#xff1f;****三 redis五大基本类型**1 String&#xff08;字符串&#xff09;**应用场景** 2 List&#xff08;列表&#xff09;**应用场景** 3 Set&#xff08;集合&#xff09;4 sorted set&#xff08;有序集合…

高级艺术二维码制作教程

最近不少关于二维码制作的&#xff0c;而且都是付费。大概就是一个好看的二维码&#xff0c;扫描后跳转网址。本篇文章使用Python来实现&#xff0c;这么简单花啥钱呢&#xff1f;学会&#xff0c;拿去卖便宜点吧。 文章目录 高级二维码制作环境安装普通二维码艺术二维码动态 …

【LVS】2、部署LVS-DR群集

LVS-DR数据包的流向分析 1.客户端发送请求到负载均衡器&#xff0c;请求的数据报文到达内核空间&#xff1b; 2.负载均衡服务器和正式服务器在同一个网络中&#xff0c;数据通过二层数据链路层来传输&#xff1b; 3.内核空间判断数据包的目标IP是本机VIP&#xff0c;此时IP虚…

SASS 学习笔记

SASS 学习笔记 总共会写两个练手项目&#xff0c;成品在 https://goldenaarcher.com/scss-study 可以看到&#xff0c;代码在 https://github.com/GoldenaArcher/scss-study。 什么是 SASS SASS 是 CSS 预处理&#xff0c;它提供了变量&#xff08;虽然现在 CSS 也提供了&am…

C++ 面向对象三大特性——继承

✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C 继承 ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;面向对象三大特性的&#xff0c;封装&#xff0c;继承&#xff0c;多态&#xff…

【数仓建设系列之一】什么是数据仓库?

一、什么是数据仓库&#xff1f; 数据仓库(Data Warehouse&#xff0c;简称DW)简单来讲&#xff0c;它是一个存储和管理大量结构化和非结构化数据的存储集合&#xff0c;它以主题为向导&#xff0c;通过整合来自不同数据源下的数据(比如各业务数据&#xff0c;日志文件数据等)…

MySQL- sql语句基础

文章目录 1.select后对表进行修改&#xff08;delete&#xff09;2.函数GROUP_CONCAT()3.使用正则表达式3.DATE_FORMAT()4.count() 加条件 1.select后对表进行修改&#xff08;delete&#xff09; 报错&#xff1a;You can’t specify target table ‘Person’ for update in …

proteus结合keil-arm编译器构建STM32单片机项目进行仿真

proteus是可以直接创建设计图和源码的&#xff0c;但是源码编译它需要借助keil-arm编译器&#xff0c;也就是我们安装keil-mdk之后自带的编译器。 下面给出一个完整的示例&#xff0c;主要是做一个LED灯闪烁的效果。 新建工程指定路径&#xff0c;Schematic,PCB layout都选择默…

【Docker】 使用Docker-Compose 搭建基于 WordPress 的博客网站

引 本文将使用流行的博客搭建工具 WordPress 搭建一个私人博客站点。部署过程中使用到了 Docker 、MySQL 。站点搭建完成后经行了发布文章的体验。 WordPress WordPress 是一个广泛使用的开源内容管理系统&#xff08;CMS&#xff09;&#xff0c;用于构建和管理网站、博客和…

大数据平台运维实训室建设方案

一、概况 本实训室的主要目的是培养大数据平台运维项目的实践能力,以数据计算、分析、挖掘和可视化的案例训练为辅助。同时,实训室也承担相关考评员与讲师培训考试、学生认证培训考试、社会人员认证培训考试、大数据技能大赛训练、大数据专业课程改革等多项任务。 实训室旨在培…

无人机跟随一维高度避障场景--逻辑分析

无人机跟随一维高度避障场景--逻辑分析 1. 源由2. 视频3. 问题3.1 思维发散3.2 问题收敛 4. 图示4.1 水平模式4.2 下坡模式4.3 上坡模式4.4 碰撞分析 5. 总结5.1 一维高度避障场景5.2 业界跟随产品5.3 APM集成跟随示意图一&#xff1a;示意图二&#xff1a;示意图三&#xff1a…

Java算法_ 验证二叉搜索树(LeetCode_Hot100)

题目描述&#xff1a; 给你一个二叉树的根节点 &#xff0c;判断其是否是一个有效的二叉搜索树。root 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 获得…

【TypeScript】tsc -v 报错 —— 在此系统上禁止运行脚本

在 VS Code 终端中执行 tsc -v &#xff0c;报错 —— 在此系统上禁止运行脚本 然后 windows x &#xff0c;打开终端管理员&#xff0c;出现同样的问题 解决方法&#xff1a; 终端&#xff08;管理员&#xff09;执行以下命令&#xff1a; 出现 RemoteSigned 则代表更改成功…

开发一个文生图的功能

文章目录 效果开发环境原理核心代码代码仓库问题效果 开发环境 Python 3.10PyCharm原理 借助开源项目stable-diffusion,通过该项目封装python库diffusers,可以轻易的实现文生图的功能。 关于更多diffusers的功能请访问:https://huggingface.co/docs/diffusers/index 核心代…

【数据结构与算法】十大经典排序算法-归并排序

&#x1f31f;个人博客&#xff1a;www.hellocode.top &#x1f3f0;Java知识导航&#xff1a;Java-Navigate &#x1f525;CSDN&#xff1a;HelloCode. &#x1f31e;知乎&#xff1a;HelloCode &#x1f334;掘金&#xff1a;HelloCode ⚡如有问题&#xff0c;欢迎指正&#…