【C语言】动态内存分配

即使行动导致错误,却也带来了学习与成长;不行动则是停滞与萎缩。💓💓💓

目录

•🌙知识回顾

🍋知识点一:为什么要有动态内存分配

🍋知识点二:malloc和free

 • 🌰1.malloc

 • 🌰2.free

🍋知识点二:calloc和realloc 

  • 🌰1.calloc

• 🌰1.realloc

🍋知识点三:常见的动态内存的错误 

• 🌰1.对NULL指针的解引用操作

​编辑• 🌰2.对动态开辟空间的越界访问

​编辑• 🌰3.对非动态开辟内存的free释放

​编辑• 🌰4.使用free释放一块动态开辟内存的一部分

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

​编辑• 🌰6.动态开辟内存忘记释放(内存泄露)

🍋知识点四:动态内存经典笔试题分析

 • 🌰1.题目1

​编辑

 • 🌰2.题目2

 • 🌰3.题目3

 • 🌰4.题目4

🍋知识点四:柔性数组 

 • 🌰1.柔性数组的特点

​编辑 • 🌰2.柔性数组的使用

​编辑 • 🌰2.柔性数组的优势

•🌙SumUp 结语


•🌙知识回顾

亲爱的友友们大家好!💖💖💖,我们紧接着要进入一个新的内容,就是动态内存的管理与分配,上两篇文章我们详细解析了C语言中的自定义类型,包括结构、联合和枚举,希望大家能够掌握并应用~

    

今天这篇文章给大家带来的是C语言中动态内存分配的知识,这是后面我们学习数据结构经常用到的,必须熟练掌握,希望大家好好学习,为后续数据结构打下基础,也希望可以给大家带来帮助。

  

👇👇👇
💘💘💘知识连线时刻(直接点击即可)

  🎉🎉🎉复习回顾🎉🎉🎉

        自定义类型结构体详细讲解

        自定义类型联合和枚举讲解超详细

博主主页传送门:愿天垂怜的博客

🍋知识点一:为什么要有动态内存分配

我们学习了这么久的C语言,也掌握了开辟空间的方式有:

	int a = 10;//在栈空间开辟了4个字节char arr[10] = { 0 };//在栈空间开辟了10个字节的连续空间

但是上面的两种开辟空间的方式有两个特点:

🔥空间开辟大小是固定的。

🔥数组在声明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整。

比如我需要描述一个班级学生的数学成绩,我创建了一个有30的元素的数组 int math[30] ,看似没什么问题,但是数组空间已经不能更改了,如果班级人数为35人,那这个数组就不够了,如果班级是20个人,空间又多余了,容易造成浪费。

所以对于空间的需求,不仅仅是固定不变的。有时候我们需要的空间大小在程序运行的时候才能知道,那数组编译时开辟空间的方式就不能满足了。

由此,C语言引入了动态内存的开辟,让程序员可以自己申请和释放内存,就比较灵活了。

而动态内存开辟包括三个部分:申请、使用、释放。

🍋知识点二:malloc和free

 • 🌰1.malloc

C语言提供了一个动态内存开辟的函数:

void* malloc (size_t size);

这个函数向内存申请了一块连续可用的空间,并返回指向这块空间的指针。

🔥如果开辟成功,则返回一个指向开辟好的空间的指针。

🔥如果开辟失败,则返回一个 NULL 指针,因此malloc的返回值一定要做检查。

🔥返回值类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候由使用者自己来决定。

🔥如果参数 size 单位是字节,如果size为0,malloc的行为是标准未定义的,取决于编译器。

举例:

#include <stdio.h>
#include <stdlib.h>
int main()
{int* p = (int*)malloc(20);//开辟20个字节的空间return 0;
}

 注意:指针变量p的类型是 int* 型,所以malloc开辟后的空间需要进行强制类型转换。 

那malloc开辟空间在内存的什么地方呢?

可以看到,内存分为这几个区域:栈区、堆区、静态区、常量区和代码区,不同区域所存储的数据不同,由malloc申请的内存在内存的堆区。

💯代码演示:

#include <stdio.h>
#include <stdlib.h>
int main()
{int* p = (int*)malloc(20);//开辟20个字节的空间if (p == NULL)//判断申请是否成功{perror("malloc");return 1;}for (int i = 0; i < 5; i++){*(p + i) = i + 1;}for (int i = 0; i < 5; i++){printf("%d ", *(p + i));//1 2 3 4 5}return 0;
}

 注意malloc是在头文件 <stdlib.h> 中声明的。

 • 🌰2.free

C语言提供了另外一个函数free,专门用来做动态内存的释放和回收的,函数原型如下:

void free (void* ptr);

我们再内存中用malloc开辟了动态内存,当我们使用完毕后应该会还给操作系统,正所谓有借有还,再借不难~

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

🔥如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。

🔥如果参数 ptr 是 NULL 指针,则函数什么事情都不做。

malloc和free的声明都在 <stdlib.h> 头文件中。

💯代码演示:

#include <stdio.h>
#include <stdlib.h>
int main()
{int n = 0;scanf("%d", &n);int* p = (int*)malloc(n * sizeof(int));if (p == NULL){perror("malloc");return 1;}for (int i = 0; i < n; i++){*(p + i) = 0;}free(p);//释放p = NULL;//释放后p是野指针,需要置为NULLreturn 0;
}

🍋知识点二:calloc和realloc 

  • 🌰1.calloc

C语言还提供了一个函数叫做calloc,calloc函数也是用来动态内存分配,函数原型如下:

void* calloc(size_t num, size_t size);

🔥函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。

🔥与函数malloc的区别只在于calloc会在返回地址之前把之前申请的空间的每个字节都初始化为0。

举例:

#include <stdio.h>
#include <stdlib.h>
int main()
{int* p1 = (int*)malloc(5 * sizeof(int));int* p2 = (int*)calloc(5, sizeof(int));return 0;
}

上述p1、p2利用malloc和calloc所开辟的空间大小是一样的,但p2返回时会在返回地址之前把之前申请的空间的每个字节都初始化为0,也就是calloc比malloc多了一步初始化。

在使用上大同小异。

💯代码演示:

#include <stdio.h>
#include <stdlib.h>
int main()
{int* p2 = (int*)calloc(5, sizeof(int));if (p2 == NULL){perror("calloc");return 1;}//使用//...free(p2);p2 = NULL;return 0;
}

• 🌰1.realloc

有时我们会发现过去申请的空间太小了,或有时候又会觉得我们申请的空间过大了,那为了合理的使用内存,我们需要对内存的大小做出灵活的调整,就有了realloc函数,原型如下:

void* realloc (void* ptr, size_t size);

 🔥 ptr 是要调整的内存地址, size 是调整时候的新大小,返回值为调整之后内存的起始位置。

🔥这个函数在调整原内存空间的基础上,还可能会将原来内存中的数据移动到新空间。

💯代码演示:

#include<stdio.h> 
int main()
{int* p = (int*)malloc(5 * sizeof(int));//20//1 2 3 4 5if (p == NULL){perror("malloc");return 1;}//使用for (int i = 0; i < 5; i++){*(p + i) = i + 1;}//希望将空间调整为40个字节realloc(p, 40);return 0;
}

上面realloc函数在调整内存空间的时候是存在两种情况的:

🎉🎉🎉情况1:原有空间之后有足够大的空间🎉🎉🎉

这种情况扩容为40个字节,后面尚未分配的空间足够20个字节的大小,那直接从后面的空间中使用20个字节,然后返回起始地址 ptr 就可以了。

🎉🎉🎉情况2:原有空间之后没有足够大的空间🎉🎉🎉

但如果是这种情况,后面尚未分配的空间没有20个字节,会在堆区上寻找一块新的空间,并且大小为40个字节,同时将原有的数据拷贝一份到新的空间,同时释放旧的空间,此时返回的是新空间的地址 new 而非 ptr。

由于上述的两种情况,在使用realloc函数的时候就需要更加注意。

💯代码演示:

#include<stdio.h> 
int main()
{int* p = (int*)malloc(5 * sizeof(int));//20if (p == NULL){perror("malloc");return 1;}//使用for (int i = 0; i < 5; i++){*(p + i) = i + 1;}//希望将空间调整为40个字节int* ptr = (int*)realloc(p, 40);if (ptr != NULL)//调整成功{p = ptr;//对p进行后续操作for (int i = 5; i < 10; i++){*(p + i) = i + 1;}for (int i = 0; i < 10; i++){printf("%d ", *(p + i));}}else//调整失败{perror("realloc");free(p);p = NULL;}return 0;
}

如果大家能够读懂上面的代码,相信对动态内存分配的四个函数都已经理解深刻了。

🍋知识点三:常见的动态内存的错误 

• 🌰1.对NULL指针的解引用操作

void test()
{int* p = (int*)malloc(INT_MAX);*p = 20;//如果p的值是NULL,就会有问题free(p);
}

对于任何动态内存的开辟(malloc、calloc),都有可能开辟失败,如果开辟失败将会返回空指针,如果我们不加以检查,就会造成对空指针的解引用,实际上malloc是不能开辟 INT_MAX 这么大的一个空间的,所以我们一定要进行检查,正确格式如下:

void test()
{int* p = (int*)malloc(INT_MAX);if (p == NULL){perror("malloc");return 1;}else{*p = 20;//此时p不为空指针free(p);}
}

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

void test()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){exit(EXIT_FAILURE);//退出程序}for (i = 0; i <= 10; i++){*(p + i) = i;//当i是10的时候越界访问}free(p);
}

 上面我们开辟了一个40个字节大小的空间,能够放入10个 int 型的整数,但是在for循环中我们给空间赋值了11位整数,这样会造成动态开辟空间的越界访问,程序将会崩溃

注意:程序执行到exit语句将会直接退出程序,执行到return语句将会直接退出当前函数。

• 🌰3.对非动态开辟内存的free释放

void test()
{int a = 10;int* p = &a;free(p);//ok?
}

大家可以返回去看看free函数的介绍,其中说明了如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。上面p指向的并不是动态开辟的空间,不应该使用free也不需要使用free(程序会崩溃),因为对于局部变量而言,具有自动存储期的变量在进入作用域时创建,出作用域时销毁。

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

void test()
{int* p = (int*)malloc(100);p++;free(p);//p不再指向动态内存的起始位置
}

p++之后,不再指向动态内存的起始位置,而是跳过了一个 int 后的位置

 在使用free释放空间的时候,一定要把空间的起始位置传递给free,不能随便传入一个地址,或从半途中来释放其中的一部分,这是不行的,否则程序会崩溃

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

void test()
{int* p = (int*)malloc(100);free(p);free(p);//重复释放
}

p申请了100字节大小的空间,但是却对这块空间释放了两次,这是不行的,程序也会崩溃。但如果在第一次释放后将p置为 NULL ,那就不会又问题了,因为如果free函数的参数是 NULL 指针,则函数什么事情都不做。

• 🌰6.动态开辟内存忘记释放(内存泄露)

void test()
{int* p = (int*)malloc(100);if (NULL != p){*p = 20;}
}
int main()
{test();while (1);
}

p申请了100个字节大小的空间,但是却忘记了将其释放,这会造成内存泄露,在 test 函数中没有释放,那出了这个函数就连释放的机会也没有了,也就是这块内存再也找不见了,没有还给操作系统。

所以我们再平常写代码的时候尽量要做到谁申请的资源谁去释放,或者给别人去用。如果不去释放,程序结束后,也会由操作系统来自动回收。

🍋知识点四:动态内存经典笔试题分析

 • 🌰1.题目1

#include <stdio.h>
#include <stdlib.h>
void GetMemory(char* p)
{p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}
int main()
{Test();return 0;
}

请问运行 Test 函数会由什么样的结果?  

有些人认为:创建字符指针并置为 NULL ,传参给 GetMemory函数,将p修改为指向动态开辟100个字节大小空间的指针,并将字符串"hello wolrd"拷贝给str。

但真的是这样吗?

其实由这张图我们就能很清楚地发现,我们传过去的是指针变量,而且是想修改这个指针变量自身的值,接收指针变量的p只是str的一份临时拷贝,对形参的修改并不会影响到实参,所以str还是 NULL ,而p出了函数后就会被销毁。形成了对 NULL 指针的访问,即非法访问。想要修改传过去的参数,就应该传它的地址,即传址调用

上面代码的两个问题:

🔥p是形参变量,出了函数变被销毁,而p指向的是动态申请的内存,这样就会造成内存泄露

🔥str指针变量中依然是 NULL 指针,如果要拷贝,就会发生内存的非法访问,可能导致程序崩溃

💯正确代码:

#include <stdio.h>
#include <stdlib.h>
void GetMemory(char** p)//二级指针接收
{*p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(&str);//想要修改str,就要传str的指针strcpy(str, "hello world");printf(str);free(str);str==NULL;
}
int main()
{Test();return 0;
}

 • 🌰2.题目2

返回栈空间地址的问题

#include <stdio.h>
#include <stdlib.h>
char* GetMemory(void)
{char p[] = "hello world";return p;
}
void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}
int main()
{Test();return 0;
}

请问运行 Test 函数会由什么样的结果?

题目大体的意思是想将字符指针str指向字符数组“hello world”然后打印出这个数组,但上面代码是实现不了预期功能的。

由与数组p在函数内部,属于局部变量,所以它的作用域范围只有它创建到函数结束这一段,而出了这个函数p就会被销毁,p就会被还给操作系统,而这块空间有没有被别人改掉,里面到底存放了什么就不从而知了,所以str并不能正确的指向字符数组,而结果将会是乱码

我们再看看另外一个同样是存在返回栈空间地址问题的代码:

#include <stdio.h>
#include <stdlib.h>
void Test(void)
{int n = 100;return &n;
}
int main()
{Test();return 0;
}

这个代码也是相同的问题,可以自己分析以下。

 • 🌰3.题目3

#include <stdio.h>
#include <stdlib.h>
void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}
void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);
}
int main()
{int* p = Test();return 0;
}

请问运行 Test 函数会由什么样的结果?

这段代码和我们之前题目1优化的版本其实是相似的,唯一还有个问题就是堆上申请的空间没有主动释放,所以会造成内存泄露

正确代码和题目1类似,大家可以参照自己改改,其实就多了一步释放,也是非常简单的。

 • 🌰4.题目4

#include <stdio.h>
#include <stdlib.h>
void Test(void)
{char* str = (char*)malloc(100); strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}
int main()
{Test();return 0;
}

这段代码在拷贝后释放了str,但是大家请注意,free是释放str指向的空间,本质上是放弃了str指向的空间的使用权限,但是str中依然保存着前面malloc申请的100个字节的起始地址。也就是说,还是会执行if语句中的内容,会将world拷贝到str的空间上,但是str指向的空间已经不属于当前程序的空间了,若坚持拷贝,就形成了非法访问内存,程序可能崩溃

因此,为了避免出现野指针的相关问题,free(str)后应该将其置为 NULL 。

🍋知识点四:柔性数组 

 也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。

C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做【柔性数组】成员。

我们从定义中提取出关键信息:

🔥结构体中,最后一个成员。

🔥最后一个成员是数组,数组没有指定大小。

这样的数组才叫做柔性数组。

例如:

struct S
{char c;int i;int arr[];//柔性数组//或int arr[0]
};

 • 🌰1.柔性数组的特点

🔥结构体中的柔性数组成员前面必须有至少一个其他成员。

🔥sizeof 返回的这种结构体大小不包括柔性数组的内存。

🔥包含柔性数组成员的结构体用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。

💯代码1:

#include <stdio.h>
struct S
{int i;int arr[];
};
int main()
{printf("%zd\n", sizeof(struct S));//结果为4return 0;
}

 • 🌰2.柔性数组的使用

#include <stdio.h>
#include <stdlib.h>
struct S
{int n;int arr[];
};
int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));if (ps == NULL){perror("malloc");return 1;}ps->n = 100;for (int i = 0; i < 5; i++){ps->arr[i] = 1;}//调整空间struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 10 * sizeof(int));if (ptr != NULL){ps = ptr;}//使用...//释放free(ps);ps = NULL;return 0;
}

这段代码看着很长,其实很多都是咱再上面讲过的一些格式,柔性数组柔性再什么地方,我们看图说话:

也就是说,我们可以用realloc来调整柔性数组的大小,而n的大小是sizeof(struct S)不变的,变化的是k*sizeof(int)中的k。 

我们也可以用指针的方式实现数组的柔性变化:

#include <stdio.h>
#include <stdlib.h>
struct S
{int n;int *arr;
};
int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S) + 5 * sizeof(int));if (ps == NULL){perror("ps: malloc");return 1;}ps->arr = (int*)malloc(5 * sizeof(int));if (ps->arr == NULL){perror("ps->arr: malloc");return 1;}//使用ps->n = 100;for (int i = 0; i < 5; i++){ps->arr[i] = i;}//调整数组大小int* ptr = (int*)realloc(ps->arr, 10 * sizeof(int));if (ptr != NULL){ps->arr = ptr;}//使用...//释放free(ps->arr);ps->arr = NULL;free(ps);ps = NULL;return 0;
}

也就是说,arr如果是个指针,那么它指向的内容也是可以动态开辟的,就可以在不使用柔性数组的情况下实现数组的柔性变化。

两种方式都是可以的。  

 • 🌰2.柔性数组的优势

上面两种方案,柔性数组的方式有什么优势呢?

🔥方便内存释放

如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并且把整个结构体返回给用户,用户调用free可以释放结构体,但是用户可能并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并且返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

🔥有利于访问速度

连续的内存有益于提高访问速度,也有益于减少内存碎片(其实也没多高了,反正都跑不了要用作偏移量的加法来寻址)。

扩展阅读:🎉🎉🎉C语言结构体里的成员数组和指针🎉🎉🎉

•🌙SumUp 结语

C语言动态内存管理的学习到这里就结束啦~后面就会进入文件操作的学习。在这里希望大家能够将前面的C语言的的基础知识进行回顾复习,使整个纯C学习是连贯的,这样更加利于我们的学习和理解以及继续拓展。

 

如果大家觉得有帮助,麻烦大家点点赞,如果有错误的地方也欢迎大家指出~

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

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

相关文章

shell脚本,删除30天以前的日志,并将日志推送到nas,但运行出现/bin/bash^M。

删除30天以前的日志 将日志推送到nas中&#xff0c;然后删除pod中的日志 pod挂载到本地 运行出现/bin/bash^M 1、删除30天以前的日志&#xff1a; #! /bin/bash# 定义源日志目录 LOG_DIR/home/log/ # 删除日志 find $LOG_DIR -type f -name "*.log" -mtime 30 -exec…

2024年五一杯高校数学建模竞赛(C题) 建模解析| 冲击地压危险预测 |小鹿学长带队指引全代码文章与思路

我是鹿鹿学长&#xff0c;就读于上海交通大学&#xff0c;截至目前已经帮200人完成了建模与思路的构建的处理了&#xff5e; 本篇文章是鹿鹿学长经过深度思考&#xff0c;独辟蹊径&#xff0c;通过滑动平均法解决冲击地压危险预测问题。实现综合建模。独创复杂系统视角&#xf…

在做题中学习(48):朴素的二分查找

. - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a; 暴力求解 for循环中&#xff0c;从nums[0]枚举到nums[n-1]&#xff0c;依次判断&#xff0c;返回 target的值。 时间复杂度 : O(N) :因为要遍历一遍数组 解法二&#xff1a;二分查找 因为此数组为有序的…

Mybatis进阶(动态SQL)

文章目录 1.动态SQL1.基本介绍1.为什么需要动态SQL2.基本说明3.动态SQL常用标签 2.环境搭建1.新建子模块2.删除不必要的两个文件夹3.创建基本结构4.父模块的pom.xml5.jdbc.properties6.mybatis-config.xml7.MyBatisUtils.java8.MonsterMapper.java9.MonsterMapper.xml10.测试Mo…

如何将安卓手机投屏到Windows 10电脑上

诸神缄默不语-个人CSDN博文目录 我之所以要干这个事是为了用手机直播的时候在电脑上看弹幕…… 文章目录 1. 方法一&#xff1a;直接用Win10内置的投影到此电脑2. 方法二&#xff1a;用AirDroid Cast投屏到电脑上 1. 方法一&#xff1a;直接用Win10内置的投影到此电脑 在设置…

C++ 多态详解

文章目录 1. 多态的概念2. 多态的定义及实现2.1 多态的构成条件2.2 虚函数2.3 虚函数的重写2.3.1 虚函数重写的两个例外 2.4 C11 override 和 final2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 多态的原理3.1 虚函数表3.2多态的原理 4. 单继承和多继承关系的虚函数表4.1 单继…

docker安装【zookeeper】【kafka】【provectuslabs/kafka-ui】记录

目录 1.安装zookeeper:3.9.2-jre-172.安装kafka:3.7.03.安装provectuslabs/kafka-ui &#xff08;选做&#xff09;新环境没有jdk&#xff0c;安装jdk-17.0.10备用 mkdir -p /export/{data,apps,logs,conf,downloads}cd /export/downloadscurl -OLk https://download.oracle.…

新品发布!无人机装调检修实训系统

近年&#xff0c;我国密集出台相关产业政策&#xff0c;推动低空经济从探索走向发展&#xff0c;根据新华网数据&#xff0c;2030年低空经济规模有望达2万亿。无人机专业属于跨学科的综合性专业&#xff0c;其中装调检测技术是无人机教培的重要组成部分。 天途推出无人机装调检…

Apache SeaTunnel k8s 集群模式 Zeta 引擎部署指南

SeaTunnel提供了一种运行Zeta引擎(cluster-mode)的方法&#xff0c;可以让Kubernetes在本地运行Zeta引擎&#xff0c;实现更高效的应用程序部署和管理。在本文中&#xff0c;我们将探索SeaTunnel k8s运行zeta引擎(cluster-mode模式)的更多信息&#xff0c;了解如何更好地利用Ze…

HTML:元素分类

HTML&#xff1a;元素分类 概述块级元素&#xff08;Block-level Elements&#xff09;内联元素&#xff08;Inline Elements&#xff09;替换元素&#xff08;Replaced Elements&#xff09;表单元素&#xff08;Form Elements&#xff09; 概述 HTML&#xff08;HyperText M…

Docker容器:网络模式与资源控制

目录 一、Docker 网络模式 1、Docker 网络实现原理 2、Docker 网络模式概述 2.1 Host 模式 2.2 Container 模式 2.3 None 模式 2.4 Bridge 模式 2.5 自定义网络&#xff08;user-defined network&#xff09; 3、配置 docker 网络模式 3.1 查看网络基础命令 3.1.1 查…

css利用transform:skew()属性画一个大屏的背景斜面四边形特效

在工作工程中需要写一个如下的大屏背景&#xff0c;是由几个斜面做成的效果 使用css transform function中的skew()方法实现画其中一个斜面&#xff0c;然后调整背景色实现 写一个div <div class"skew_container test-2"><div class"skew_container_it…

【python笔记】datafram的时间动态可视化 pyecharts地图

import pandas as pd# 假设DataFrame是这样的&#xff1a; df pd.DataFrame({ year: [2014, 2015, 2016, 2014, 2015, 2016, 2014, 2015, 2016], province: [广东省, 广东省, 河南省, 湖南省, 北京市, 北京市, 上海市, 新疆维吾尔自治区, 上海市], values: [100, 150, 75…

Servlet文件嵌套<script>来显示提示框而出现乱码的解决方案

主要出现的原因就是编码不统一导致无法解析对话框中的字符串 我的解决方案: 使用 URL 的编码格式&#xff0c;然后再使用js中的decodeURIComponent函数解析URL编码的字符串&#xff0c;并且恢复其原始字符串内容 将你写的传统的编码格式改为 PrintWriter out resp.getWriter(…

多目标应用:MSSA多目标樽海鞘优化算法求解无人机三维路径规划(MATLAB代码)

一、无人机多目标优化模型 无人机三维路径规划是无人机在执行任务过程中的非常关键的环节&#xff0c;无人机三维路径规划的主要目的是在满足任务需求和自主飞行约束的基础上&#xff0c;计算出发点和目标点之间的最佳航路。 1.1路径成本 无人机三维路径规划的首要目标是寻找…

YOLOV8 pycharm

1 下载pycharm 社区版 https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows 2 安装 3 新建 4 选择 文件-> setting 配置环境变量 5 添加conda 环境

基本STL使用

一 、关于vector 在STL中有一个称为vector的数据结构&#xff0c;可以用来代替数组。 定义Book特性 private:vector<string> shelf_books;Notic : 类中不能使用类似的定义&#xff1a;vector<sttring> shelf_boos( 10 ); 定义Book方法 public:void setName(str…

5.C++动态内存管理(超全)

目录 1 .C/C 内存分布 2. C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free 3. C内存管理方式 3.1 new/delete操作内置类型 3.2 new和delete操作自定义类型 3.3 operator new函数 3.4 定位new表达式(placement-new) &#xff08;了解&#xff09; 4. 常…

Java 基础重点知识-(Java 语言特性、数据类型、常见类、异常)

文章目录 Java 语言特性形参和实参的区别是什么?值传递和引用传递的区别?Java 是值传递还是引用传递?final 的作用是什么?final finally finalize 有什么不同?static 的作用是什么?static 和 final 的区别是什么? Java 数据类型Java基本数据类型有几种? 各占多少位?基…

【MySQL精炼宝库】数据库的约束 | 表的设计 | 聚合查询 | 联合查询

目录 一、数据库约束 1.1 约束类型&#xff1a; 1.2 案例演示&#xff1a; 二、表的设计 2.1 一对一: 2.2 一对多: 2.3 多对多: 2.4 内容小结&#xff1a; 三、新增 四、查询 4.1 聚合查询&#xff1a; 4.1.1 聚合函数&#xff1a; 4.1.2 GROUP BY子句&#xff1a…