动态内存分配:malloc、calloc、realloc(超详解析,多维度分析,小白一看就懂!!!!)

news2024/11/28 22:46:52

目录

一、前言

二、动态内存的简单介绍

🍉什么是动态内存分配

🍎为什么要使用动态内存分配 

三、动态内存函数的介绍和拓展 

🍋malloc()函数 

🍊free()函数 

🍌calloc()函数

🍇realloc()函数

四、常见动态内存分配的错误

五、共勉


一、前言

在学习动态内存分配时,感觉这些动态分配没什么用,也就没在意跳过去了,直到碰到数据结构和一些需要动态数组的题目时才知道,动态内存分配的重要性。这次专门花了一早上的时间来学习了动态内存分配,并将它分享出来,希望对大家有帮助哦!!!!

二、动态内存的简单介绍

🍉什么是动态内存分配

知识点1:

🔑目前在我们平时写代码的过程中接触最多的就是在栈空间上开辟连续的空间:

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

🔑此时我们需要注意在栈空间上的开辟空间的特点:

▶空间开辟的大小是固定的。
▶数组在声明时必须指定数组的长度,在编译时会开辟并分配其所需要的内存空间。

知识点2:

所谓动态内存分配(Dynamic Memory Allocation) 就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

🍎为什么要使用动态内存分配 

知识点1:
 🔑之前学习了数组,数组的元素储存在内存中连续位置。在声明数组时必须要指定数组的元素个数,即数组空间大小在声明时已经确定了但是需存放的元素个数常常在运行时才能知道(取决于输入的数据)。

🔑此时应用栈去申请内存空间的缺点就出现了:

1. 当输入元素个数大于数组声明的元素个数时会带来意想不到错误

2. 当输入元素个数小于数组声明的元素个数时会带来内存空间的浪费

3.数组大小不能动态调整

💡 总结:有时我们需要的空间大小在程序运行的时候才能知道,这时在数组编译时开辟空间的方式就不能满足了,这时我们就需要动态内存开辟来解决问题。

三、动态内存函数的介绍和拓展 

🍋malloc()函数 

知识点1:
🔑malloc()函数的头文件:#include <stdlib.h>

🔑malloc()函数的声明:

 函数声明的解释:
size_t 表示无符号类型       size:表示申请分配的内存大小,单位为字节

▶ 返回值:申请成功返回该空间起始地址,申请失败返回NULL指针,因为不知道申请的空间要存放什么类型数据所以返回void*类型

🔑malloc()函数的功能介绍

malloc 是C语言提供的一个动态内存开辟的函数,该函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。具体情况如下:

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

▶ 如果开辟失败,则返回一个 NULL 指针。

▶ 如果开辟失败,则返回一个 NULL 指针。

▶ 如果 size 为 0(开辟0个字节),malloc 的行为是标准未定义的,结果将取决于编译器。

🔑注意:

1. malloc返回值有可能是NULL指针,使用前需要检查
2. malloc申请的空间并没有被初始化


🔑代码举例说明:

     用malloc()来创建一个 数组。可以在程序运行时使用malloc()请求一个存储块,另外还需要一个指针来存放该块在内存中的位置。

int * ptd;
ptd = (int * ) malloc (30 * sizeof(int));
if (ptd == NULL) //空间申请失败则退出
{
	return -1; 
}

代码解释:

▶ 这段代码请求30个 int类型 值的空间,并且把ptd指向该空间所在位置。
▶ 注意: ptd是作为指向一个 int类型值 的指针声明的,而不是指向30个 int类型 值的数据块的指针。

🍊free()函数 

知识点1:
🔑 free()函数的头文件:#include <stdlib.h>

🔑 free()函数的声明:

  函数声明的解释:

 ptr : 指向先前用malloc、calloc或realloc分配的内存块的指针

🔑 free()函数的功能:

释放申请的动态内存分配的空间(即malloc、calloc、realloc函数申请的空间)具体情况:

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

▶ 如果参数 ptr 是 NULL 指针,那么 free 将不会执行任何动作。

🔑注意事项:
▶ 使用完之后一定要记得使用 free 函数释放所开辟的内存空间。

▶ 使用指针指向动态开辟的内存,使用完并 free 之后一定要记得将其置为空指针,防止越界访问。

    原因:free()函数只会释放ptr指向空间的值,但ptr本身不会被置空。
 

🔑代码举例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//申请10个int类型大小空间,10 * sizeof(int)相对于sizeof(40)更具有移植性
	//由于malloc返回值为void*类型,所以强制类型转换为int*类型
	int n; // 开辟空间数  举例为 10
	printf("请输入想开辟的 int 数组大小\n");
	scanf("%d", &n);
	int* p = (int*)malloc(n * sizeof(int));
	if (p == NULL) 
	{
		exit(EXIT_FAILURE);   //p 现在指向有 n 个元素的数组
	}
	int i = 0;
	for (i = 0; i < 10; i++) //打印这10个元素
	{
		printf("%d ", *(p + i));
	}
	printf("\n");
	for (i = 0; i < 10; i++) //对数组元素赋值
	{
		p[i] = i;    // 此时可以将 指针 p 看作数组名
	}
	for (i = 0; i < 10; i++) //打印这10个元素
	{
		printf("%d ", *(p + i));
	}
	printf("\n");
	free(p); //释放p所指向动态内存分配的空间
	p = NULL;//将p置为NULL指针,防止访问一个已释放的空间
	return 0;
}

运行结果:

请输入想开辟的 int 数组大小:
10
-842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451
0 1 2 3 4 5 6 7 8 9

代码解释:

▶ 开始 指针 p 指向 int 类型 开辟的40个字节空间,并没有赋值,所以输出的值都是随机的。

 exit()函数。该函数的原型在 stdlib.h 中,用来在内存分配失败时结束程序

   值 EXIT_FAILURE 也在这个头文件中定义。标准库提供了两个保证能够在所有操作系统       下工作的返回值:
   
EXIT SUCCESS(或者,等同于0)指示程序正常终止;
   EXIT_FAILURE指示程序异常终止。

知识点2:内存泄露
大家是否有跟我一样的想法,目前我们知道了动态内存的开辟函数 malloc() ,之后便出现了释放函数 free(),我有点好奇,在我开辟函数之后,我不去释放,你能把我怎样呢?

抱着这样的想法,我做了一个实验:

#include<stdio.h>
#include<malloc.h>

void gobble (double ar[], int n);

int main()
{ 
	double glad[2000];
	int i;
	
   for(i = 0; i<100000000; i++)
  {
		gobble(glad, 2000);
  }
}

void gobble(double ar[], int n)
{
	double *temp = (double *) malloc(n*sizeof(double)) ;
	
//	free(temp);/*忘记使用*/    //我就皮,我就用
}

代码解释:
▶ 第一次调用gobble()时,它创建了指针temp,并使用malloc()为之分配16000字节        的内存(设double是8个字节)。
    假定我们如暗示的那样没有使用free()。
    当函数终止时,指针temp作为一个自动变量消失了。
    但它所指向的16000个字节的内存仍旧存在。
    我们无法访问这些内存,因为地址不见了。
    由于没有调用free(),不可以再使用它了。

 

▶ 第二次调用gobble(),它又创建了一个temp,再次使用malloc()分配16000个字节        的内存。
   第一个16000字节的块已不可用,因此malloc()不得不再找一个l6000字节的块。
  当函数终止时,这个内存块也无法访问,不可再利用。

▶ 但循环执行了1000次,因此在循环最终结束时,已经有1600万字节的内存从内存池中移        走。事实上,在到达这一步前,程序很可能已经内存溢出了。

这类问题被称为内存泄漏(memory leak)可以通过在函数末尾处调用free()防止该问题出现。

🍌calloc()函数

知识点1:
🔑calloc()函数的头文件:#include <stdlib.h>

🔑calloc()函数的声明:

 🔑解释函数声明:
▶ num:元素个数

▶ size: 元素大小

▶ 返回值:申请成功返回该空间起始地址,申请失败返回NULL指针,因为不知道申请的空间要存放什么类型数据所以返回void*类型。

🔑calloc()函数的功能:
calloc函数与malloc函数功能一样,区别主要在于calloc会对分配的空间初始化为0,另外它们请求内存大小的方式不同。

🔑验证malloc()函数与calloc()函数的区别:
   malloc()函数:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    // malloc
    int* p = (int*)malloc(40); // 开辟40个空间
    if (p == NULL) 
	{
		exit(EXIT_FAILURE);   //p 现在指向有 10 个元素的数组
	}
    int i = 0;
    for (i = 0; i < 10; i++)
        printf("%d ", *(p + i));
    free(p);
    p = NULL;
 
    return 0;
}

 运行结果:

// 随机的 10 个值 

 calloc()函数:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    // calloc
    int* p = (int*)calloc(10, sizeof(int)); // 开辟10个大小为int的空间,40
   if (p == NULL) 
	{
		exit(EXIT_FAILURE);   //p 现在指向有 10 个元素的数组
	}
    int i = 0;
    for (i = 0; i < 10; i++)
        printf("%d ", *(p + i));
    free(p);
    p = NULL;
 
    return 0;
}

运行结果:

0 0 0 0 0 0 0 0 0 0

🔑总结:

说明 calloc 会对内存进行初始化,把空间的每个字节初始化为 0 。如果我们对于申请的内存空间的内容,要求其初始化,我们就可以使用 calloc 函数来轻松实现。

🍇realloc()函数

知识点1:
🔑realloc()函数的头文件:#include <stdio.h>

🔑realloc()函数的声明:

 🔑声明的解释:

▶ ptr:指向先前用malloc、calloc或realloc分配的内存块的指针

▶ size:动态内存空间新大小,单位为字节

▶ 返回值:返回调整后空间的起始地址,调整失败返回NULL指针

 🔑realloc()函数的功能:
让动态内存管理更加灵活。用于重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小,可以对动态开辟的内存进行大小的调整。

🔑realloc()函数调整内存的 4 中情况:(看图解)
▶ 情况一:在原有的基础上扩大空间

 原有空间之后有足够大的空间。

 ▶ 情况二:原有空间之后没有足够大的空间。

 原空间之后没有足够多的空间满足扩展需求,在内存上另外寻找一个适合大小的来连续空间来使用,并将原空间数据先复制过来然后释放空间。这样函数返回的是一个新空间的内存地  址

▶ 情况三:缩小原有的空间

原空间尾部的部分空间被释放,剩余空间数据依旧保留。

▶ 情况四:
 

🔑代码演示:
realloc()调整函数大小:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int* p = (int*)calloc(10, sizeof(int));
    if (p == NULL)
    {
        exit(EXIT_FAILURE);   //p 现在指向有 10 个元素的数组
    }
    // 使用
    int i = 0;
    for (i = 0; i < 10; i++) {
        *(p + i) = 5;
    }
    // 此时,这里需要p指向的空间更大,需要20个int的空间
    // realloc 调整空间
    p = (int*)realloc(p, 20 * sizeof(int)); // 调整为20个int的大小的空间
    // 释放
    free(p);
    p = NULL;
}

疑问: 刚才提到的第四种情况,如果 realloc 找不到合适的空间,就会返回空指针。我们想让它增容,他却存在返回空指针的危险,这怎么行?

🔑代码优化:

#include <stdio.h>
#include <stdlib.h>
 
int main() 
{
    int* p = (int*)calloc(10, sizeof(int));
    if (p == NULL)
    {
        exit(EXIT_FAILURE);   //p 现在指向有 n 个元素的数组
    }
    // 使用
    int i = 0;
    for (i = 0; i < 10; i++) 
    {
        *(p + i)  = 5;
    }
    // 此时,这里需要 p 指向的空间更大,需要 20 个int的空间
    // realloc 调整空间
    int* ptmp = (int*)realloc(p, 20*sizeof(int));
    // 如果ptmp不等于空指针,再把p交付给它
    if (ptmp != NULL) 
    {
        p = ptmp;
    }
 
    // 释放
    free(p);
    p = NULL;
    return 0;
}

🔑代码演示全过程;

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		exit(EXIT_FAILURE);   //p 现在指向有 10 个元素的数组
	}
	int i = 0;
	for (i = 0; i < 10; i++) //对数组元素赋值
	{
		*(p + i) = i;
	}
	int* ptr = (int *)realloc(p, 20 * sizeof(int)); //对动态内存大小进行调整
	if (ptr == NULL) //调整失败并不影响原本p指向空间
	{
		printf("空间调整失败\n");
	}
	else
	{
		p = ptr; //调整成功,p指向调整后空间起始地址
		ptr = NULL;
		for (i = 10; i < 20; i++) //对数组元素赋值
		{
			*(p + i) = i;
		}
		for (i = 0; i < 20; i++) //打印数组元素
		{
			printf("%d ", *(p + i));
		}
	}
	free(p); //释放p所指向动态内存分配的空间
	p = NULL;//将p置为NULL指针,防止访问一个已释放的空间
	return 0;
}

运行结果:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

知识点2: 

有趣的是,其实你可以把 realloc 当 malloc 用:

// 在要调整的内存地址部分,传入NULL:
int* p = (int*)realloc(NULL, 40); // 这里功能类似于malloc,就是直接在堆区开辟40个字节

四、常见动态内存分配的错误

 知识点1:使用 free 释放一块动态开辟内存的一部分

 错误代码演示:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int* p = (int *)malloc(10*sizeof(int));
     if (p == NULL)
    {
        exit(EXIT_FAILURE);   //p 现在指向有 10 个元素的数组
    }
    int i = 0;
    for (i = 0; i < 5; i++) {
        *p++ = i; // p指向的空间被改变了
    }
 
    free(p);
    p = NULL;
  
    return 0;
}

错误原因分析:

 此时free(p)出现了大问题,释放的是后面的空间。不能从一块动态开辟的内存空间的某一部分释放,必须从头开始释放。

代码更新:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int* p = (int *)malloc(10 * sizeof(int));
    if (p == NULL)
    {
        exit(EXIT_FAILURE);   //p 现在指向有 10 个元素的数组
    }
    int* ptd = p;    //提前将 p 指针与 ptd 指针进行替换
    int i = 0;
    for (i = 0; i < 5; i++) {
        *ptd++ = i; // ptd指向的空间被改变了
    }
    free(p);
    p = NULL;
    return 0;
}

知识点2:
 问题:💬 下列代码存在什么问题?请指出问题并做出相应的修改。
 

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

💡 参考答案:str 传给 GetMemory 函数时为值传递,所以 GetMemory 函数的形参 p 是 str 的一份临时拷贝。在 GetMemory 函数内部动态开辟的内存空间的地址存放在了 p 中,并不会影响 str。所以当 GetMemory 函数返回之后, str 仍然是 NULL,导致 strcpy 拷贝失败。其次,随着 GetMemory 函数的返回,形参 p 随即销毁并且没有及时的使用 free 释放,从而导致动态开辟的100个字节存在内存泄露问题。根据经验,程序会出现卡死的问题。

修改代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// ↓ 修改返回类型为char*
char* GetMemory(char *p) {
    p = (char*)malloc(100);
    return p; // 将p带回来
}
 
void Test() {
    char *str = NULL;
    str = GetMemory(str); // 用str接收,此时str指向刚才开辟的空间
    strcpy(str, "hello world"); // 此时copy就没有问题了
    printf(str);
    // 用完之后记得free,就可以解决内存泄露问题
    free(str);
    str = NULL; // 还要将str置为空指针
}
 
int main() {
    Test();
 
    return 0;
}

运行结果:

  hello world

五、共勉

 以下就是我对动态内存分配的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对数据结构-------顺序表的理解,请持续关注我哦!!!!! 

 

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

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

相关文章

UDP套接字编程详解

UDP 是OSI&#xff08;Open System Interconnection&#xff0c;开放式系统互联&#xff09; 参考模型中一种无连接的传输层协议。 UDP协议与TCP协议一样用于处理数据包。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点&#xff0c;也就是说&#xff0c;当报文发送之…

【状语从句练习题】综合训练

1. 改正错误 1.第二个 either 改为or 2.后面的 he plays 去掉&#xff0c;不必要的重复 3.but 去掉 4.cold 后 and 5.I went out. 加 个 I. 6.第一个 will 去掉&#xff0c;get 变为 ges 7.so 去掉 8.去掉第二个 either 9.去掉后面的 I need 10.Although/but 去掉一个 11.后…

【JavaSE】类和对象——上

文章目录1. 类的定义1.1 什么是类1.2 如何定义类2. 类的实例化3. this关键字3.1 this访问成员变量和成员方法3.2 构造方法及this()我们给类初始化的方法有&#xff1a;3.2.1 就地初始化3.2.2 使用 set 方法赋值3.2.3 使用构造方法4. 如何便捷的打印对象中属性1. 类的定义 1.1 什…

【Pytorch Lighting】第 1 章:PyTorch Lightning adventure

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

数据中心通识

文章目录一 数据中心定义特点二 机房定义内部物品物理环境三 服务器定义外型分类与PC相比的优点超线程技术固态硬盘和机械硬盘四 网络定义OSI模型局域网的拓扑结构TCP/IP协议常见端口号IP地址介绍、格式、分类、子网掩码DNS三层交换机五 存储格式化缓存RAID技术存储体系架构IP-…

二叉树的前中后序遍历(递归与迭代)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;Java数据结构 格言&#xff1a;目之所及皆为回忆&#xff0c;心之所想皆为过往 目录 简介 前序遍历 递归法 迭代法 中序遍历 递归法 迭代法 后序遍历 递归法 迭代法 简介 前面学习二叉树的时候&#xff0c;已经学过…

渗透测试 | 域名信息收集

0x00 前言 信息收集可以说是在渗透测试中最重要的一部分&#xff0c;上文对 IP 信息收集做了一个简要的叙述&#xff0c;认识了 CDN 技术和网络空间搜索引擎。但是很多网站的主站因为访问流量过大的原因通常会使用 CDN 技术&#xff0c;同时也可以有效防止 DDOS 攻击。在域名信…

前端面经 强缓存与协商缓存

前端面经 强缓存与协商缓存 图片多来自第三方平台 文章目录前端面经 强缓存与协商缓存适用场合浏览器缓存的过程缓存规则强缓存&#xff08;本地缓存&#xff09;协商缓存缓存分为两种&#xff1a;强缓存和协商缓存&#xff0c;根据响应的header内容来决定 获取资源形式状态码…

【C++】二叉搜索树

前言 hi~大家好呀&#xff0c;欢迎点进我的C学习笔记~ 我的前一篇C笔记链接~ 【C】多态_柒海啦的博客-CSDN博客 本篇需要用到的基础二叉树C语言实现链接~ 用c语言实现一个简单的链表二叉树_柒海啦的博客-CSDN博客_c语言建立二叉树链表 我们知道&#xff0c;查找一个数据会有很多…

数据库基本操作

目录 数据库操作 创建数据库 查看数据库 选择数据库 删除数据库 注释 数据表操作 创建数据表 查看数据表 查看数据表 查看数据表的相关信息 修改数据表 修改数据表名称 修改表选项 查看表结构 查看数据表的字段信息 查看数据表的创建信息 查看数据表结构 修…

linux进程间通信之共享内存

目录 一&#xff0c;共享内存原理 二&#xff0c;创建共享内存 1&#xff0c;shmget创建共享内存 2&#xff0c;shmat挂接共享内存 3&#xff0c;shmdt取消挂接共享内存 4&#xff0c;shmctl删除共享内存 三&#xff0c;代码使用 1,com.hpp 2&#xff0c;ipc_client.c…

Allegro基本规则设置指导书之Physical Region

Allegro基本规则设置指导书之Physical Region 下面介绍基本规则设置指导书之Physical Region 空白的地方创建一个Region 给新建的Region匹配一个规则,所有区域里面的Physical相关的都按照Region的规则来 当部分网络想按照本身的规则来匹配,可以创建region-Class 然后匹配…

目标检测算法——医学图像开源数据集汇总(附下载链接)

关注”PandaCVer“公众号 深度学习Tricks&#xff0c;第一时间送达 目录 1.血细胞图像数据 2.眼病深度学习数据集 3.皮肤病数据集 4.膝关节 X 射线图像数据集 小海带整理不易&#xff0c;小伙伴们记得一键三连喔&#xff01;&#xff01;&#xff01; >>>一起交流…

VisualSVN 是 Visual Studio 的专业级 Subversion 集成插件

用于 Visual Studio 的 VisualSVN 专业且无缝的 Subversion 集成。 专业级 Subversion 集成 VisualSVN 是 Visual Studio 的专业级 Subversion 集成插件。 VisualSVN 的主要优点是&#xff1a; 无与伦比的可靠性&#xff1a; Visual Studio 永远不会因为 VisualSVN 而崩溃或挂…

保护鲸鱼动物网页设计作业 静态HTML宠物主题网页作业 DW鲸鱼网站模板下载 大学生简单动物网页作品代码 个人网页制作 学生个人网页

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

2022阿里云栖大会,顶尖科技趋势峰会和全链路元宇宙体验

2022年的11月3日-5日是阿里巴巴云栖大会的日子&#xff0c;地点在云栖小镇&#xff0c;本人有幸报名参加了5日那场&#xff0c;因为5日是周六。秉着打工人工作日需要搬砖&#xff0c;因为“公司离不开我”&#xff0c;哈哈哈&#xff0c;实际上是每天满满的工作量。所以只能选择…

一文彻底搞懂协程(coroutine)是什么,值得收藏

什么是协程 我们可以简单的认为&#xff1a;协程就是用户态的线程&#xff0c;但是上下文切换的时机是靠调用方&#xff08;写代码的开发人员&#xff09;自身去控制的。 同时&#xff0c;协程和用户态线程非常接近&#xff0c;用户态线程之间的切换不需要陷入内核&#xff0…

NYIST(计科ACMTC)第三次招新赛题解

A题 原文, 原比赛B题 牛客练习赛104【出题人题解】 - 知乎 直接输出 输入的数 就可以了 B题 C题 找到分别处理"无留陀的化身"坐标轴的x轴和y轴, 组合成无留陀的坐标, 再遍历求纳西妲的坐标, 相减即可 /* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿…

ROS小工具学习与使用

ROS小工具学习与使用 rqt的使用 rqt_bag工具 rqt_bag <your bagfile> #使用rqt_bag查看你的rosbag例如&#xff1a;可以查看第一帧GPS的rawdata信息&#xff0c;如下图&#xff1a; 参考文献&#xff1a; 1、http://wiki.ros.org/rqt_bag 2、rosbag与rqt_bag的常用 rq…

Nacos学习笔记

视频学习指路&#xff1a; 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 Nacos nacos注册中心的搭建 1.下载nacos的安装包&#xff0c;github地址&#xff1a;https://github.com/alibaba/nacos&…