驾驭代码的无形疆界:动态内存管理揭秘

news2024/11/27 17:48:27

目录

1.:为什么要有动态内存分配

2.malloc和free

2.1:malloc

 2.2:free

3.calloc和realloc

3.1:calloc

3.1.1:代码1(malloc)

3.1.2:代码2(calloc)

3.2:realloc

3.2.1:原地扩容

3.2.2:异地扩容

3.2.3:代码1(原地扩容)

3.2.3:代码2(异地扩容)

4:常见的动态内存的错误

4.1:对NULL指针的解引用操作

4.2:对动态开辟空间的越界访问

4.3:对非动态开辟的内存使用free释放

4.4:使用free释放动态开辟内存的一部分

4.5:对同一块动态内存多次释放

4.6:对动态内存忘记释放(内存泄漏)

5:动态内存经典笔试题分析

5.1:题目1(问运行test函数有什么样的结果)

5.1.1:改法1:传二级指针

5.1.2:改法2:以return的形式返回

5.2:题目2(问运行test函数有什么样的结果)

5.3:题目3(问运行test函数有什么样的结果)

5.3.1:修改后

5.4:题目4(问运行test函数有什么样的结果)

5.4.1:修改后

6:C/C++程序的内存开辟区域划分


嘿嘿,uu们, 今天咱们来详细剖析动态内存管理,好啦,废话不多讲,开干!


1.:为什么要有动态内存分配

通过之前的学习,我们已经掌握的内存开辟方式有

//在栈区上开辟四个字节.
int value = 25;
//在栈空间上开辟40个字节的连续空间.
int arr[10] = {0};

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

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

2.在C99之前,数组在声明的时候,必须指定数组的长度,数组空间⼀旦确定了大小不能调整
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候 才能知道,那么数组的编译时开辟空间的⽅式就不能满足了.
那么C语言引入了动态内存开辟,让我们能够自己开辟和释放空间,这样子的话,就相对来讲比较灵活了.

2.malloc和free

2.1:malloc

C语言提供了一个动态内存开辟的函数, 我们首先来看看官方的解释

void* malloc (size_t size);

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

​​​​​1: 如果开辟成功,则返回⼀个指向开辟好空间的指针.
2: 如果开辟失败,则返回⼀个NULL指针, 因此malloc的返回值⼀定要做检查。
3:返回值的类型是 void*, 所以malloc函数并不知道开辟空间的数据类型,因此具体在使⽤的时候由使用者自己来决定.
4:如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器.   

 2.2:free

当我们自己向内存空间申请了空间后,在使用完后要对其进行释放与回收,那么C语言提供了另外一个函数free,专门用来针对动态内存的释放与回收的.

void free (void* ptr);
free函数⽤来释放动态开辟的内存。
如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数 ptr NULL指针,那么该函数什么事都不做.
PS:malloc和free在使用时需要包含stdlib.h头文件.
了解了malloc和free函数后,我们来看个例子.
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	//申请一块空间,用来存放10个整型*/
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		//p[i];
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}

	/*
	* 由于p指针还会指向原本的地址,此时如果不赋为空指针的话, 那就是野指针了
	* 释放ptr所指向的动态内存
	*/
	free(p);
	p = NULL;
	return 0;
}

3.calloc和realloc

3.1:calloc

C语言还提供了一个函数叫做calloc,calloc函数也可以用来进行动态内存分配,我们来看看其原型

 void* calloc (size_t num, size_t size);

第一个参数是:元素的个数.

第二个参数是:元素占据内存空间的大小. 

  • 该函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节都初始化为0.
  • 与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0.        

了解了calloc函数后,我们来看个例子

3.1.1:代码1(malloc)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	//申请一块空间,用来存放10个整型*/
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		//p[i];
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}

	/*
	* 由于p指针还会指向原本的地址,此时如果不赋为空指针的话, 那就是野指针了
	* 释放ptr所指向的动态内存
	*/
	free(p);
	p = NULL;
	return 0;
}

3.1.2:代码2(calloc)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	//申请一块空间,用来存放10个整型*/
	int* p = (int*)calloc(10,4);
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		//p[i];
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}

	/*
	* 由于p指针还会指向原本的地址,此时如果不赋为空指针的话, 那就是野指针了
	* 释放ptr所指向的动态内存
	*/
	free(p);
	p = NULL;
	return 0;
}

3.2:realloc

  • realloc函数的出现让动态内存管理更加灵活
  • 有时候我们会发现过去申请的空间过小或者过大了,那么为了合理的分配内存,我们就会对内存的大小做出灵活的调整.那么realloc函数就可以对动态开辟的内存进行调整.

  • 第一个参数ptr为要调整的起始内存地址.
  • 第二个参数size为调整之后新大小.
  • 返回值为调整之后的内存起始地址.
  • realloc函数在调整原内存空间大小的基础上,还会将原来内存中的数据拷贝到新的空间.
  • realloc在调整内存空间存在两种情况
    • First:原有空间有足够大的空间那么会原地扩容.
    • Second:原有空间之后没有足够的空间,那么会异地扩容.

3.2.1:原地扩容

当是情况1的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

3.2.2:异地扩容

当是情况2的时候,原有空间之后没有⾜够多的空间时,扩展的方法是:在堆空间上另找⼀个合适大小的连续空间来使用。这样函数返回的是⼀个新的内存地址.

综合上述的两种情况,那么realloc函数的使用就要略微注意一些.

3.2.3:代码1(原地扩容)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = calloc(10, sizeof(int));
	if (NULL == p)
	{
		perror("molloc");
		return 1;
	}
	printf("\n");
	/*
	* 原有空间足够则在原有的空间进行扩展
	* 如果原有空间后面的空间不足够,则realloc函数会在堆区重新开辟一块足够的空间
	*/
	int* ptr = (int*)realloc(p, 20 * sizeof(int));
	if (ptr != NULL)
	{
		p = ptr;
	}
	return 0;
}

3.2.3:代码2(异地扩容)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = calloc(10, sizeof(int));
	if (NULL == p)
	{
		perror("molloc");
		return 1;
	}
	printf("\n");
	/*
	* 原有空间足够则在原有的空间进行扩展
	* 如果原有空间后面的空间不足够,则realloc函数会在堆区重新开辟一块足够的空间
	*/
	int* ptr = (int*)realloc(p, 1000 * sizeof(int));
	if (ptr != NULL)
	{
		p = ptr;
	}
	return 0;
}

4:常见的动态内存的错误

4.1:对NULL指针的解引用操作

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	//不对返回值作判断,就可能使用NULL指针,对空指针进行解引用
	int* p = (int*)malloc(INT_MAX);
	*p = 20;
	return 0;
}

上面的代码,由于动态开辟的内存过大,那么因此开辟空间是失败的,那么malloc开辟空间失败的话,就会返回NULL指针.那么此时再对其进行解引用操作的话,就会发生对NULL指针的解引用操作.

4.2:对动态开辟空间的越界访问

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = calloc(10, sizeof(int));
	if (NULL == p)
	{
		perror("calloc");
		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);
	p = NULL;
	return 0;
}

上述代码则发生对动态开辟空间的越界访问,在开辟空间的时候,是只开辟了数量为10个,大小为4字节的空间,但是在赋值和打印的时候,对第11个空间进行了访问,那么则发生了对动态开辟空间的越界访问.

4.3:对非动态开辟的内存使用free释放

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int a = 10;
	int* p = &a;

	//对非动态内存开辟进行释放
	free(p);
	p = NULL;
	return 0;
}

上面的代码则发生对非动态开辟的内存使用了free释放,指针变量p指向的是变量a,指向的区域是栈区,而动态开辟的内存是在堆区,因此发生了对非动态开辟的内存使用了free释放.

4.4:使用free释放动态开辟内存的一部分

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = calloc(10, sizeof(int));
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	int i = 0;
	//赋值
	for (i = 0; i < 5; i++)
	{
		*p = i;
		p++;
	}
	// 0 1 2 3 4 0 0 0 0
	//此时p指向第六个位置

	free(p);
	p = NULL;
	return 0;
}

上述的代码是发生了对动态开辟的内存只释放了一部分.

4.5:对同一块动态内存多次释放

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = malloc(40);
	if (NULL == p)
	{
		return 1;
	}
	free(p);


	free(p);
	return 0;
}

上述代码则发生了对同一块动态内存多次释放,对于动态开辟的内存只能够释放一次,这就好比,我们日常去住酒店,当我们退了酒店房间后,是不能够再一次退酒店房间的.

4.6:对动态内存忘记释放(内存泄漏)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void test()
{
	int* p = (int*)malloc(40);
	if (3)
	{
		return;
	}
	free(p);
	p = NULL;
}

int main()
{
	test();
	return 0;
}

总结:忘记释放不再使用的动态开辟的空间会造成内存泄漏

切记:动态开辟的空间一定要正确释放.

5:动态内存经典笔试题分析

5.1:题目1(问运行test函数有什么样的结果)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void GetMemory(char* p)
{
	//这个形参出了函数之后就会被销毁外加返回类型为void
	//malloc开辟的空间没有释放,因此发生了内存泄漏
	p = (char*)malloc(100);
}

void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	//发生对空指针的解引用操作,导致了程序崩溃
	strcpy(str, "hello world");
	printf(str);
}

int main()
{
	Test();
	return 0;
}

5.1.1:改法1:传二级指针

//改法1
 #define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.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);
	free(str);
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

5.1.2:改法2:以return的形式返回

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//改法2,以return返回的形式
char* GetMemory()
{
	char* p = (char*)malloc(100);
	return p;
}

void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	strcpy(str, "hello world");
	printf(str);
	//开辟了动态内存之后要进行释放并且置为NULL,因为此时str还会指向原本的地址,如果不放置为NULL,那就是野指针了
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

5.2:题目2(问运行test函数有什么样的结果)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
char* GetMemory(void)
{
	//为局部变量,出了函数就被销毁了
	 char p[] = "hello world";
	//返回的是地址值
	return p;
}
void Test(void)
{
	char* str = NULL;
	//str非法访问了空间,此时str为野指针
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();
	return 0;
}

5.3:题目3(问运行test函数有什么样的结果)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.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()
{
	Test();
	return 0;
}

5.3.1:修改后

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//修改后
void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}

void Test()
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

5.4:题目4(问运行test函数有什么样的结果)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void Test()
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");

	//释放了开辟动态内存空间后,指针str还是会指向原本的值,因此此时str为野指针
	free(str);

	if (str != NULL)
	{
		//对野指针的非法访问
		strcpy(str, "world");
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}

5.4.1:修改后

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//修改
void Test()
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");

	/*
	* 释放了开辟动态内存空间后, 指针str还是会指向原本的值, 因此此时str为野指针,
	释放了以后要对其进行置NULL
	*/
	free(str);
	str = NULL;
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}

6:C/C++程序的内存开辟区域划分

  • 1.栈区(stack):在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内存容量有限。 栈区主要存放运行函数⽽分配的局部变量、函数参数、返回数据、返回地址等。
  • 2.堆区(heap):⼀般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。
  • 3. 数据段(静态区):存放全局变量、静态数据。程序结束后由系统释放。
  • 4. 代码段:存放函数体(类成员函数和全局函数)的⼆进制代码。

好啦,uu们,动态内存管理这部分滴详细知识博主就讲到这里啦,如果uu们觉得博主讲的不错的话,请动动你们滴小手给博主点点赞,你们滴鼓励将成为博主源源不断滴动力,同时也欢迎大家来指正博主滴错误~

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

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

相关文章

AR 眼镜之-充电动画定制-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 充电动画 1. &#x1f531; 技术方案 1.1 方案介绍 1.2 实现方案 关机充电动画 亮屏/锁屏充电动画 2. &#x1f4a0; 关机充电动画 2.1 关机充电动画核心处理类与路径 2.2 实现细节 步骤一&#xff1a;1&#xff09;定制 …

Javascript前端面试基础5【每日更10】

let与var的区别 let命令不存在变量提升&#xff0c;如果在let前使用&#xff0c;会导致报错&#xff08;var存在变量提升&#xff09;如果块区中存在let和const命令&#xff0c;就会形成封闭作用域不允许重复声明&#xff0c;因此&#xff0c;不能在函数内部重新声明参数 m…

Pcl读取stl文件,并转换成pcd文件,同时显示stl模型和pcd点云

由于不同版本的pcl兼容范围不一样&#xff0c;这里有2个版本的代码&#xff0c;里面的文件路径需要实际情况修改即可&#xff0c;希望对您有所参考或帮助 pcl1.8.1和vs2015版本代码 #include <iostream> #include <pcl/io/io.h> #include <pcl/io/pcd_io.h>…

序列化与反序列化的本质

1. 将对象存储到本地 假如有一个student类&#xff0c;我们定义了好几个对象&#xff0c;想要把这些对象存储下来&#xff0c;该怎么办呢 from typing import List class Student:name: strage: intphones: List[str] s1 Student("xiaoming",10,["huawei&quo…

大模型微调部署实战及类GPT工具的高效使用

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委&#xff0c;编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二…

《RMT: Retentive Networks Meet Vision Transformers》CVPR2024

论文&#xff1a;RMT: Retentive Networks Meet Vision Transformers - AMiner 摘要 这篇论文探讨了将Retentive Network&#xff08;RetNet&#xff09;的概念引入到计算机视觉领域&#xff0c;并与Vision Transformer结合&#xff0c;提出了一种新的模型RMT&#xff08;Ret…

牛津剑桥等发现:AI 训 AI 惨遭投毒 9 次大崩溃

【新智元导读】9 次迭代后&#xff0c;模型开始出现诡异乱码&#xff0c;直接原地崩溃&#xff01;牛津、剑桥等机构的一篇论文登上了 Nature 封面&#xff0c;称合成数据就像近亲繁殖&#xff0c;效果无异于投毒。有无破解之法&#xff1f;那就是 —— 更多使用人类数据&#…

护眼灯有没有护眼的效果?一文揭秘用护眼灯到底好不好

护眼灯有没有护眼的效果&#xff1f;在现在这个时代&#xff0c;无论是在学习还是办公&#xff0c;都很难离开一款好用的台灯&#xff0c;所以&#xff0c;为了避免会挑选到质量不好的台灯&#xff0c;我们应该要先避开一些网红小品牌&#xff0c;优先选择有专业技术支持的&…

ClickHouse 24.6 版本发布说明

本文字数&#xff1a;14127&#xff1b;估计阅读时间&#xff1a;36 分钟 作者&#xff1a;ClickHouse team 本文在公众号【ClickHouseInc】首发 又到了发布新版本的时间&#xff01; 发布概要 本次ClickHouse 24.6 版本包含了23个新功能&#x1f381;、24项性能优化&#x1f6…

maven介绍 搭建Nexus3(maven私服搭建)

Maven是一个强大的项目管理工具&#xff0c;它基于项目对象模型&#xff08;POM&#xff1a;Project Object Model&#xff09;的概念&#xff0c;通过XML格式的配置文件&#xff08;pom.xml&#xff09;来管理项目的构建 Maven确实可以被视为一种工程管理工具或项目自动化构…

使用flutter做圆形进度条 (桌面端)

前言 最近收到一个需求&#xff0c;需要使用flutter 来做一个圆形进度条&#xff0c;这可难倒我了&#xff0c;毕竟我是做前端的&#xff0c;flutter 之前接触的也少&#xff0c;但没办法&#xff0c;既然需求有了&#xff0c;也得硬着头皮上了&#xff0c;先来看看做的效果。…

简过网:大学生考公,一定要先好好看看这篇文章!

大家好&#xff0c;我是简过网&#xff0c;今天这篇文章我们来聊聊关于大学生考公的那些事儿&#xff0c;希望能给大学生们一点点的帮助&#xff01; 首先&#xff0c;可能有朋友会问了&#xff0c;大学生一般从什么时候开始备考公务员呢&#xff0c;在这里小编建议大家从大三…

《昇思25天学习打卡营第24天|基于MindSpore通过GPT实现情感分类》

基于MindSpore通过GPT实现情感分类 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mind…

yolov5-7环境搭建训练自己的模型

1.下载代码 git clone https://github.com/ultralytics/yolov5 # clone可以切到5-7版本&#xff0c;也可以去github选标签下载 2.配置好conda环境&#xff0c;网上教程比较多&#xff0c;不做讲解&#xff0c;python3.8即可。 3.在环境里安装pyrtorch 按自己的需求选取&am…

每日一练,java05

目录 题目知识点&#xff1a;1.12.13.1 题目 选自牛客网 1.下列表述错误的是&#xff1f;&#xff08;&#xff09; A.int是基本类型&#xff0c;直接存数值&#xff0c;Integer是对象&#xff0c;用一个引用指向这个对象。 B.在子类构造方法中使用super()显示调用父类的构造…

第T6周:使用TensorFlow实现好莱坞明星识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 文章目录 一、前期工作1.设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据3. 查看数据 二、数据预处理1、加载数据2、数据可视化3、再…

【论文速读】| LLMCloudHunter:利用大语言模型(LLMs)从基于云的网络威胁情报(CTI)中自动提取检测规则

本次分享论文&#xff1a;LLMCloudHunter: Harnessing LLMs for Automated Extraction of Detection Rules from Cloud-Based CTI 基本信息 原文作者&#xff1a;Yuval Schwartz, Lavi Benshimol, Dudu Mimran, Yuval Elovici, Asaf Shabtai 作者单位&#xff1a;Ben-Gurion…

mfc100u.dll 文件缺失?两种方法快速修复丢失mfc100u.dll 文件难题

您的电脑是否遭遇了 mfc100u.dll 文件缺失的问题&#xff1f;这种情况通常由多种原因引起。在本文中&#xff0c;我们将介绍两种修复 mfc100u.dll 文件丢失问题的策略——一种是手动方法&#xff0c;另一种是自动修复的使用。我们将探讨如何有效地解决 mfc100u.dll 文件缺失的几…

Linux下git入门操作

0.创建仓库 可以按这个配置来&#xff0c;.gitignore中存放了上传时忽略的文件类型后缀。 1.clone仓库 在gitee上创建好仓库&#xff0c;点击克隆/下载&#xff0c; 复制地址fyehong/Linux_notes 。 在所需的文件夹中放置仓库。比如我在文件夹lesson9下存储仓库。就在less…

Python爬虫技术 第18节 数据存储

Python 爬虫技术常用于从网页上抓取数据&#xff0c;并将这些数据存储起来以供进一步分析或使用。数据的存储方式多种多样&#xff0c;常见的包括文件存储和数据库存储。下面我将通过一个简单的示例来介绍如何使用 Python 爬取数据&#xff0c;并将其存储为 CSV 和 JSON 文件格…