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

【C语言】动态内存管理基础知识——动态通讯录,如何实现通讯录容量的动态化

引言

动态内存管理的函数有:malloc,calloc,ralloc,free,本文讲解动态内存函数和使用,如何进行动态内存管理,实现通讯录联系人容量的动态化,对常见动态内存错误进行总结。

        

 158c3f50b199454985017a51dbef9841.png               ✨ 猪巴戒:个人主页✨

               所属专栏:《C语言进阶》

        🎈跟着猪巴戒,一起学习C语言🎈

目录

引言

为什么存在动态内存分配

malloc

动态内存空间位置

 内存泄漏问题

free

calloc   

realloc 

realloc如何开辟动态内存空间

动态版本的通讯录

常见动态内存错误

1.对NULL空指针进行解引用

2.对动态开辟空间的越界访问

3.对非动态开辟的内存使用free释放

4.使用free释放动态开辟内存的一部分

5.对同一块动态内存多次释放

6.动态开辟内存忘记释放(内存释放)

动态通讯录的实现



为什么存在动态内存分配

int main()
{int arr[20] = {0};//整形数组开辟20个元素,就是80个字节。return 0;
}

1.空间开辟大小是固定的

2.数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

如果我们开辟的空间不够,那么进行修改会比较麻烦。如果开辟的空间较大,那么所占据的空间又会很大。那么有没有一种方法可以用多少空间就开辟多大的内存呢?

这个时候就有了动态内存开辟。


malloc

动态内存函数的头文件  <stdlib.h>

void* malloc (size_t size)

a066e21521c34f6e966d7c58c5b1d1fb.png

申请内存块,

size

就是我们要申请的字节大小。当然,我们的内存是有限的,不是想要申请多少内存就可以申请多少内存。

返回值

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。

开创的空间放回地址是void*类型,使用的时候记得要强制类型转换。

所以我们在使用malloc函数时,要检测返回值p是否是空指针。

#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include<stdio.h>
int main()
{int arr[10] = { 0 };//动态内存开辟int* p = (int*)malloc(40);if (p == NULL)      //检测返回的p是不是空指针。{printf("%s\n", strerror(errno));return 1;}//使用动态内存int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放free(p);    //常常搭配malloc、calloc、realloc使用,后面会讲到p = NULL;return 0;
}

f8d11f8a978c45c9a26e6b479d12acb3.png

         

动态内存空间位置

 动态内存函数是在堆区开辟内存空间的。我们一般的局部变量、形式参数都是存放在栈区。

2a755d6571ce4bc28cdd42725109c2d3.png

         

 内存泄漏问题

什么是内存泄漏?

我们创建的局部变量,数据会在函数结束时释放。

动态内存空间存放临时使用的数据,这些数据不必等到函数结束时释放,而是需要时随时开辟,不需要时,随时释放。动态开辟的内存使用完是要进行释放的,如果不对内存进行释放,那么开辟的动态内存就会被之前的数据占据,这部分的内存就无法使用,相当于丢失了内存。因此我们把这类问题叫做内存泄漏

下面的代码如果吧进行释放,那么就会一直占据内存空间。

858d90982a85432cbc47bdc0798a0ef1.png

 通过释放动态内存,内存可以被重新调用

9a8aa7cd08754d5db41e8a501d5ee008.png

最后我们加了一步,p = NULL,p的内存空间已经被释放了还给操作系统了,但是p还是原来的地址,我们通过p就会使用到一个已经释放的内存,这就会导致野指针问题。为了避免这种情况,我们将p的地址去掉就可以了。

17cef251579d40c797c86392201a90f2.png

        

free

void free (void* ptr)

free函数是专门用来释放动态开辟的内存。

  • 如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数ptr 是NULL指针,则函数什么事都不做。

free函数只能释放动态内存开辟的空间,如果释放其他空间,就会报错。

#include <stdlib.h>
int main()
{int a = 0;int* p = &a;free(p);p = NULL;return 0;
}

da583dd28bf24bd482fa2e8067931150.png

        

calloc   

void* calloc (size_t num, size_t size)

f79aadb251314d11839bd0058f502487.png

num 

开辟空间元素的个数

size

空间中每个元素的大小。

  •  函数的功能为num个大小为size 的元素开辟一块空间,并且把空间的每个字节初始化为0
  • callocmalloc的区别在于calloc在放回地址之前把申请的空间的每个字节初始化为全0。

下面的例子就是解释:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));if (p == NULL){printf("%s\n", strerror(errno));}//打印int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}//释放free(p);p = NULL;return 0;
}

a523a57b3c8a4aae938562d1611e95f6.png

        

realloc 

void* realloc (void* ptr, size_t size)

2843916f62db4e2b8fceee1671efeb18.png

ptr

要调整的空间的起始位置。

size

  • realloc函数的出现让动态内存管理更加灵活。
  • 有时我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间豁达了,那为了合理的内存,我们一定对内存的大小做灵活的调整。那realloc函数可以做到对动态开辟内存大小的调整。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{int* p = (int*)malloc(40);if (p == NULL){printf("%s\n", strerror(errno));}//使用int i = 0;for (i = 0; i < 10; i++){*(p + i) = i + 1;}//扩容int* ptr =  realloc(p, 80);if (ptr != NULL)  //这里不直接将新的地址赋给p,是因为realloc有可能开辟失败返回空指针。后面详细讲{p = ptr;}for(i=0;i<10;i++){printf("%d ", *(p + i));}//释放free(p);p = NULL;return 0;
}

88f1530abbf448fbb5a1f45dc2e8873f.png

        

realloc如何开辟动态内存空间

realloc在调整内存空间的是存在两种情况。

第一种情况,原空间之后有足够大的空间。当要进行调整的内存空间后面有多余的40个字节空间,那么就可以直接开辟向后面开辟40个字节的空间,然后放回起始位置的地址,这里指的是0的地址。

5de786ff5e05407c92d31f2e1c575847.png

698f0ff7ee3441a580545c584564081e.png

第二种情况原空间之后没有足够大的空间。要调整的内存空间后面不足以存放40个字节的空间,那么就要重新找到一个新的地址(可以存放80个字节)开辟,开辟成功后返回起始位置的地址。

注意:如果需要开辟的空间过大,是会开辟失败的,开辟失败,realloc返回空指针,所以要检查空指针。

这里把realloc开辟的空间换成8000,来实现第二种情况。

1ad74892b124494c959288e26152895b.png e2a52b304f504866a715c4e5bcbbefb8.pngf4bc4b17e6db40799be54b0eb0d8fc7e.png

         

动态版本的通讯录

动态:

要实现通讯录容量的动态化,要实现两个功能

1.通讯录默认能存放3个人的信息

2.如果空间不够了,就增加空间,每次增加2个人的空间

静态:

原来的通讯录的信息由结构体组成的数组,来存放信息,设置的是100人的信息。

1.当没有100人的信息时,会造成空间上的浪费。

2.当超过100人的信息时,又无法自动扩容,如果想要扩容要手动改变最大存放的空间。

原通讯录的代码:

有兴趣可以学习通讯录的实现http://t.csdnimg.cn/UbT9I

 存放数据的改变

首先把存放联系人信息的结构体给大家看看

typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;

原来存放联系人的信息是通过数组data[100],这样的数组的空间是固定的,是一开始设置的最大容量。

typedef struct Contact
{PeoInfo data[MAX];int count;//记录当前通讯录中实际人数的个数
}Contact;

不以数组的形式进行存放,以数组改成地址,但是地址也可以像数组一样访问数据。data是联系人的起始地址,如果想要访问第二个人,就是*(data+1),等于data[1]。

count是当前使用了多少个联系人的空间.

capacity记录的是现在存放联系人的容量是多大。因为当每次容量不够时,就增加空间,每次增加2个人的空间。也就是每次count == capacity的时候,capacity就要加2.

typedef struct Contact
{PeoInfo* data;int count;//记录当前通讯录中实际人数的个数int capacity;
}Contact;

1.初始化的改变

assert函数,用来检验空指针,如果为空指针,就会报错。

参数pc,是创立的struct Contact结构体变量的地址,这里是传址调用,作用就是改变原来的数据。

原通讯录是存放100个联系人的数组,将100个联系人的数据初始化为0。

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

动态通讯录要实现开辟3个联系人的空间,并将它们进行初始化。 既要开辟空间,又要进行初始化,我们想到calloc函数。

malloc是单纯地开辟空间,realloc是既开辟空间,并进行初始化。mallocrealloc地区别就在于是否对开辟的空间初始化。

开辟3个联系人空间,calloc进行开辟,将地址传给pc->data.将记录联系人的容量传给capacity.

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

 2.增加联系人

参数pc,是创立的struct Contact结构体变量的地址,这里是传址调用,作用就是改变原来的数据。

动态内存管理,通过pc->data[count]可以进行数据的输入。最重要的是实现通讯录容量的动态化。

count表示已经使用的联系人数量,capacity表示联系人的总容量。

当count == capacity时,就要动态开辟内存,对容量进行增容。

CheckCapacity为自定义增容函数,我们要实现增容的功能。

realloc重新开辟内存块,实现内存的动态化。realloc返回的起始地址不能直接传给data,因为动态内存的开辟有可能失败,失败传回空指针。

capacity增加2,最后提示增容成功。

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

将整体的代码呈现在文章末尾。

        

常见动态内存错误

        

1.对NULL空指针进行解引用

如果开辟的空间过大,malloc有可能开辟失败,开辟失败就会返回空指针。如果直接对p进行解引用,就会产生问题。

#include <stdlib.h>
int main()
{int* p = (int*)malloc(40);*p = 20;return 0;
}

正确解决方法: 

在开辟动态内存后对p进行检验,是否为空指针。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{int* p = (int*)malloc(40);if (p == NULL){printf("%s\n", strerror(errno));return 1;}*p = 20;free(p);p = NULL;return 0;
}

        

2.对动态开辟空间的越界访问

我们只开辟了10个字节的空间,但是访问,从0到10,10算进去的话就是11个元素,这里访问越界了,就会出问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{int* p = (int*)malloc(40);if (p == NULL){printf("%s\n", strerror(errno));return 1;}//使用int i = 0;for (i = 0; i <= 10;i++){p[i] = i;}free(p);p = NULL;return 0;
}

正确解决方法: 

一定要注意我们开辟的空间是否和访问的空间是一样的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{int* p = (int*)malloc(40);if (p == NULL){printf("%s\n", strerror(errno));return 1;}//使用int i = 0;for (i = 0; i < 10;i++){p[i] = i;}free(p);p = NULL;return 0;
}

        

3.对非动态开辟的内存使用free释放

free只能够释放动态开辟的内存,不能够随意去使用函数。

#include <stdlib.h>
int main()
{int a = 10;int* p = &a;//....free(p);p = NULL;return 0;
}

ec2893e717184b06857487260a7a58de.png

        

4.使用free释放动态开辟内存的一部分

free做不到释放动态内存的一部分,如果要释放要将整个动态内存进行释放。

#include <stdlib.h>
int main()
{int* p = (int*)malloc(40);if (p = NULL){return 1;}int i = 0;for (i = 0; i < 10; i++){*p = i;p++;}free(p);p = NULL;return 0;
}

正确解决方法: 

不改变p的位置,对p进行释放。使用p的话,通过:

*(p+i) = i;

        

5.对同一块动态内存多次释放

free的二次使用,第二次使用的动态内存空间已经还给操作系统了,但是还能对p进行操作,就是野指针问题。

#include <stdlib.h>
int main()
{int* p = (int*)malloc(40);free(p);//....free(p);return 0;
}

正确解决方法: 

避免free的二次使用,或者将p转化为空指针。

#include <stdlib.h>
int main()
{int* p = (int*)malloc(40);free(p);p = NULL;free(p);return 0;
}

        

6.动态开辟内存忘记释放(内存释放)

看看下面的例子:

如果flag = 5的话,那么后面free函数就会跳过,动态开辟的内存就不能释放。

#include <stdio.h>
#include <stdlib.h>
void test()
{int* p = (int*)malloc(100);int flag = 0;scanf("%d", &flag);if (flag == 5){return;}free(p);p = NULL;
}
int main()
{test();return 0;
}

动态通讯录的实现

 contact.h

头文件:用来对函数的声明

#pragma once#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>#define DEFAULT_SZ 3
#define INC_SZ 2
#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;int count;//记录当前通讯录中实际人数的个数int capacity;
}Contact;//初始化通讯录
int InitContact(Contact* pc);//销毁通讯录
void DestroyContact(Contact* pc);//增加联系人到通讯录
void AddContact(Contact* pc);//打印通讯录中信息
void ShowContact(const Contact* pc);//删除联系人的信息
void DelContact(Contact* pc);//查找指定联系人
void SeachContact(Contact* pc);//修改指定联系人
void ModifyContact(Contact* pc);//排序通讯录中的内容
//按照名字来排序
void SortContact(Contact* pc);

contact.c

源文件:函数的实现和定义

#define _CRT_SECURE_NO_WARNINGS#include "contact.h"//动态版本
int InitContact(Contact* pc)
{assert(pc);pc->count = 0;pc->data =(int*) calloc(DEFAULT_SZ, sizeof(PeoInfo));if (pc == NULL){printf("InitContact::%s\n", strerror(errno));return 1;}pc->capacity = DEFAULT_SZ;return 0;
}void DestroyContact(Contact* pc)
{assert(pc);free(pc->data);pc->data = NULL;
}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 1;}else{pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");}}
}
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");
}void ShowContact(const 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);}
}static 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;
}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; i++){pc->data[i] = pc->data[i + 1];}pc->count--;
}void SeachContact(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;}//2.打印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);}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");
}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");
}

test.c

通讯录主脉络:

#define _CRT_SECURE_NO_WARNINGS#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");}
int main()
{int input = 0;Contact con;//初始化通讯录:模块化初始化InitContact(&con);//只能传地址,进行修改do{menu();printf("请选择:》");scanf("%d", &input);switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:SeachContact(&con);break;case 4:ModifyContact(&con);break;case 5:ShowContact(&con);break;case 6:SortContact(&con);break;case 0:DestroyContact(&con);printf("退出通讯录\n");break;default:printf("选择错误\n");}} while (input);return 0;
}

相关文章:

【C语言】动态内存管理基础知识——动态通讯录,如何实现通讯录容量的动态化

引言 动态内存管理的函数有&#xff1a;malloc,calloc,ralloc,free,本文讲解动态内存函数和使用&#xff0c;如何进行动态内存管理,实现通讯录联系人容量的动态化&#xff0c;对常见动态内存错误进行总结。 ✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》…...

Centos9(Stream)配置Let‘s Encrypt (免费https证书)

1. 安装snap&#xff0c;用来安装certbot&#xff1a; sudo dnf install epel-release sudo dnf upgrade sudo yum install snapd sudo systemctl enable --now snapd.socket sudo ln -s /var/lib/snapd/snap /snap snap install core snap refresh core 2. 安装 certbot命令…...

Spring之事务(2)

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…...

嵌入式科普(5)ARM GNU Toolchain相关概念和逻辑

一、目的/概述 二、资料来源 三、逻辑和包含关系 四、Arm GNU Toolchain最常用的命令 嵌入式科普(5)ARM GNU Toolchain相关概念和逻辑 一、目的/概述 对比高集成度的IDE(MDK、IAR等)&#xff0c;Linux开发需要自己写Makefile等多种脚本。eclipse、Visual Studio等需要了解预处…...

Elasticsearch:什么是文本分类?

文本分类定义 - text classification 文本分类是一种机器学习&#xff0c;它将文本文档或句子分类为预定义的类或类别。 它分析文本的内容和含义&#xff0c;然后使用文本标签为其分配最合适的标签。 文本分类的实际应用包括情绪分析&#xff08;确定评论中的正面或负面情绪&…...

指针(3)

C语言昂&#xff0c;指针昂&#xff0c;最喜欢的一集&#xff0c;小时候学这一课我直接取地址了。上一篇博客给大家讲解了不同类型的指针变量的大小&#xff0c;今天来给大家讲解一下根据其所产生的一些性质。&#xff08;往期回顾&#xff1a;指针&#xff08;2&#xff09;-C…...

外汇天眼:我碰到外汇投资骗局了吗?学会这5招,轻松识别外汇诈骗黑平台!

近年来外汇市场因为交易量大、流动性大、不容易被控盘、品种简单、风险相对低等特色&#xff0c;因此吸引不少投资人青睐&#xff0c;成为全球金融市场的热门选择。 然而&#xff0c;市面上充斥许多诈骗集团设立的黑平台&#xff0c;也打着投资外汇的名义行骗&#xff0c;不免会…...

一文解析子网掩码和默认网关,成为网络设置达人

随着互联网的普及&#xff0c;越来越多的人开始接触并使用电脑和网络。然而&#xff0c;对于很多初学者来说&#xff0c;网络设置中的子网掩码和默认网关是两个相对陌生的概念。今天&#xff0c;我们就来深入解析这两个概念&#xff0c;让你轻松掌握网络设置技巧&#xff01; …...

二分查找法详解(6种变形)

前言 在之前的博客中&#xff0c;我给大家介绍了最基础的二分查找法&#xff08;没学的话点我点我&#xff01;&#xff09; 今天我将带大家学习二分法的六种变形如何使用&#xff0c;小伙伴们&#xff0c;快来开始今天的学习吧&#xff01; 文章目录 1&#xff0c;查找第一个…...

uniapp uview 页面多个select组件回显处理,默认选中

<view class"add-item column space-around" click"selectClick(1)"><text class"w-s-color-3 f-28">商品分类</text><view class"w-100 space-between"><!-- 第一个参数为你的单选数组&#xff0c;第二个…...

linux中playbook的控制语句

本章主要介绍 playbook中的控制语句。 使用 when 判断语句 block-rescue判断 循环语句 一个play中可以包含多个task&#xff0c;如果不想所有的task全部执行&#xff0c;可以设置只有满足某个 条件才执行这个task&#xff0c;不满足条件则不执行此task。本章主要讲解when 和 …...

MongoDB介绍

一、MongoDB介绍 1.1 mongoDB介绍 MongoDB 是由C语言编写的&#xff0c;是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下&#xff0c;添加更多的节点&#xff0c;可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB …...

再看参数校验

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 写一个接口&#xff0c…...

计算机存储术语: 扇区,磁盘块,页

扇区(sector) 硬盘的读写以扇区为基本单位。磁盘上的每个磁道被等分为若干个弧段&#xff0c;这些弧段称之为扇区。硬盘的物理读写以扇区为基本单位。通常情况下每个扇区的大小是 512 字节。linux 下可以使用 fdisk -l 了解扇区大小&#xff1a; $ sudo /sbin/fdisk -l Disk …...

解决IDEA编译/启动报错:Abnormal build process termination

报错信息 报错信息如下&#xff1a; Abnormal build process termination: "D:\Software\Java\jdk\bin\java" -Xmx3048m -Djava.awt.headlesstrue -Djava.endorsed.dirs\"\" -Djdt.compiler.useSingleThreadtrue -Dpreload.project.path………………很纳…...

Jetpack DataStore

文章目录 Jetpack DataStore概述DataStore 对比 SP添加依赖库Preferences DataStore路径创建 Preferences DataStore获取数据保存数据修改数据删除数据清除全部数据 Proto DataStore配置AndroidStudio安装插件配置proto文件创建序列化器 创建 Proto DataStore获取数据保存数据修…...

在Portainer创建Nginx容器并部署Web静态站点实现公网访问

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…...

泛微e-cology XmlRpcServlet文件读取漏洞复现

漏洞介绍 泛微新一代移动办公平台e-cology不仅组织提供了一体化的协同工作平台,将组织事务逐渐实现全程电子化,改变传统纸质文件、实体签章的方式。泛微OA E-Cology 平台XmRpcServlet接口处存在任意文件读取漏洞&#xff0c;攻击者可通过该漏洞读取系统重要文件 (如数据库配置…...

当下流行的直播技术demo演示

nginx-http-flv-module&#xff08;更新不是很频繁&#xff09; SRS: https://ossrs.net/lts/zh-cn/&#xff08;独立官网&#xff0c;目前最新稳定版version5&#xff09; 基于SRS搭建直播demo演示&#xff1a; 一、搭建流媒体服务器 参见官网&#xff1a;https://ossrs.ne…...

Zabbix自动发现并注册已安装agent的主机

先在被监控主机上安装好zabbix-agent 然后登录zabbix网页 点击发现动作后会出现第三步 然后编辑操作&#xff0c;发现后加入到主机组群 然后编辑发现规则 然后就可以在主机列表中看到被发现的主机。...

Jtti:linux搭建开源ldap服务器的方法

搭建开源LDAP服务器是一种用于集中管理用户身份认证和授权信息的方法。在Linux系统上&#xff0c;OpenLDAP是一个流行的开源LDAP实现&#xff0c;可以用于搭建LDAP服务器。以下是搭建OpenLDAP服务器的基本步骤&#xff1a; 步骤一&#xff1a;安装OpenLDAP 安装OpenLDAP软件包&…...

Gazebo GUI模型编辑器

模型编辑器 现在我们将构建我们的简单机器人。我们将制作一个轮式车辆&#xff0c;并添加一个传感器&#xff0c;使我们能够让机器人跟随一个斑点&#xff08;人&#xff09;。 模型编辑器允许我们直接在图形用户界面 &#xff08;GUI&#xff09; 中构建简单的模型。对于更复…...

pycharm运行正常,但命令行执行提示module不存在的多种解决方式

问题描述 在执行某个测试模块时出现提示&#xff0c;显示自定义模块data不存在&#xff0c;但是在PyCharm下运行正常。错误信息如下&#xff1a; Traceback (most recent call last):File "/run/channelnterface-autocase/testcases/test_chanel_detail.py", line 2…...

GBASE南大通用GBase 8a ODBC的安装文件

GBASE南大通用GBase 8a ODBC 体系结构是基于五个组件&#xff0c;在下图中所示&#xff1a; GBase 8a ODBC 体系结构图  应用 应用是通过调用 ODBC API 实现对 GBase 数据访问的程序。应用使用标准的 ODBC 调用与驱动程序管理器通信。应用并不关心数据存储在哪里&#xff…...

重新配置torch1.8 cuda11.1 torchtext0.9.0虚拟Pytorch开发环境

这里写目录标题 起因发现选择安装cuda 11.1核对下自己的显卡是否支持下载该版本的CUDACUDA下载地址CUDA安装过程 在anaconda中创建一个虚拟环境1.以下是环境的配置过程2.查看虚拟环境列表3.激活虚拟环境 安装torch和torchtext包的过程1.输入下面这句代码&#xff0c;就可以直接…...

【动画图解】一次理清九大排序算法!面试官问到再也不慌!

排序算法 交换排序 冒泡排序快速排序 插入排序 直接插入排序希尔排序 选择排序 简单选择排序堆排序 归并排序基数排序桶排序 一、冒泡排序 冒泡排序是一种简单的交换排序算法&#xff0c;以升序排序为例&#xff0c;其核心思想是&#xff1a; 从第一个元素开始&#xff0c…...

组播地址段及其作用

作用 组播(Multicast)传输:在发送者和每一接收者之间实现点对多点网络连接。如果一台发送者同时给多个的接收者传输相同的数据&#xff0c;也只需复制一份的相同数据包。它提高了数据传送效率。减少了骨干网络出现拥塞的可能性。 地址段 组播协议的地址在 IP 协议中属于 D 类…...

Vue+ElementUI前端添加展开收起搜索框按钮

1、搜索框添加判断 v-if"advanced" <el-form-item label"创建日期" v-if"advanced"><el-date-pickerv-model"daterangeLedat"size"small"style"width: 240px"value-format"yyyy-MM-dd"type&q…...

速盾网络:sdk游戏盾有什么作用?

速盾cdn是一款非常优秀的CDN加速服务&#xff0c;它能够帮助游戏开发者们提升游戏的性能和稳定性。其中&#xff0c;速盾cdn的sdk游戏盾是其一项非常实用的功能&#xff0c;它能够为游戏提供更加稳定和快速的网络连接。 首先&#xff0c;让我们来了解一下什么是sdk游戏…...

理解BeEF的架构

BeEF的组件和工作原理BeEF&#xff08;The Browser Exploitation Framework&#xff09;是一款用于浏览器渗透测试和漏洞利用的强大工具。它由多个组件组成&#xff0c;这些组件协同工作以实现对受害者浏览器的控制和攻击。本文将深入探讨BeEF的各个组件和其工作原理&#xff0…...

wordpress站内301/qq刷赞网站推广

这一周我们小组进行了JSON转换和数据库动态转换以及用户界面的编写等工作&#xff0c;我负责编写用户查看发布信息界面和申请发布界面。遇到的问题有element ui的card组件分页和表单数据与页面数据一起传到后端。   发布信息以el-card的形式展现在页面上&#xff0c;结合el-r…...

点击最高的模板网站/搜索引擎优化主要包括

先说下我这个有啥好处 主要是能够自定义设置裁剪图片的比例.比如 :今天产品 给你说裁剪 成16:9 的图片. 你做好了 OK 明天 产品又和你说 裁剪成10:7 的图片 ,你是不是要吐血, 我这里只要设置一行代码就可以改变裁剪的比例.OK 还是老规矩 先上效果图 看看啥样子好了 不扯其他的了…...

汽车之家网站是谁做的/公司员工培训内容有哪些

1、遇到不想回答的问题&#xff0c;直视对方的眼睛&#xff0c;微笑、沉默。- 2、走路抬头挺胸&#xff0c;心情不好时&#xff0c;不想跟人招呼&#xff0c;点头微笑&#xff0c;径直走过。- 3、请记得&#xff0c;好朋友的定义是&#xff1a;你混的好&#xff0c;他打心眼里为…...

公司自己的网站叫什么/网站搭建需要什么技术

本文就来看看在Spring Boot中MyBatis要如何使用。 工程创建 首先创建一个基本的Spring Boot工程&#xff0c;添加Web依赖&#xff0c;MyBatis依赖以及MySQL驱动依赖&#xff0c;如下&#xff1a; 最简单的SpringBoot整合MyBatis教程 创建成功后&#xff0c;添加Druid依赖&#…...

阿里云心选建站/seo技术教程博客

01 chromium较全的开关选项说明 https://peter.sh/experiments/chromium-command-line-switches/ 很多命令行开关项在这个文件中 src\chrome\common\chrome_switches.cc02 如何取消一些不感兴趣的工程 https://blog.csdn.net/dopi/article/details/27662959...

做美国市场哪个网站好/百度影音在线电影

【问题】 在进入docker镜像后&#xff0c;我们一般缺少vim&#xff0c;需要安装&#xff0c;但是在更新的过程中往往会卡在working 的进度为0上。 【解决方法】 mv /etc/apt/sources.list /etc/apt/sources.list.bak echo "deb http://mirrors.163.com/debian/ jessie …...