IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 如何杜绝铺张浪费,用多少申请多少(内存)——动态内存分配 -> 正文阅读

[C++知识库]如何杜绝铺张浪费,用多少申请多少(内存)——动态内存分配

前言:

在我们使用计算机空间时,我们往往会不知道到底该如何分配所需的内存空间,从而导致内存空间的浪费,那么学完本篇文章,就可以有效避免这种局面!


为什么会存在动态内存分配?

当前我们知道的内存的使用方式:
1.创建一个变量

int a=10;//局部变量 - 栈区
int g_a=10;//全局变量 - 静态区

在这里插入图片描述
2.创建一个数组
int arr[10];(局部是栈区,全局是静态区)
gcc支持C99标准,但不是所有编译器都支持
但是上述的开辟空间的方式有两个特点:

  1. 空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道, 那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态存开辟了。

一、动态内存分配函数

1.malloc函数

只负责在堆区开辟申请空间,并且返回起始地址,不初始化内存空间
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自 己来决定。
  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
void* malloc (size_t size);

p=NULL;防止变成野指针

int main()
{
	//向内存申请10个整型空间,也要还(释放)
	//int* p = (int*)malloc(10 * sizeof(int));//强制类型转换
	int* p = (int*)malloc(INT_MAX);
	if (p == NULL)
	{
		//打印错误原因的一个方式
		printf("%s\n", strerror(errno));
	}
	else
	{
		//正常使用空间
		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的地址并没有改变
	p = NULL;//直接将其强制变为空指针,防止变成野指针
	return 0;
}

2.free函数

void free (void* ptr);

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

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。
int main()
{
	//向内存申请10个整型空间,也要还(释放)
	//int* p = (int*)malloc(10 * sizeof(int));//强制类型转换
	//int* p = (int*)malloc(INT_MAX);
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		//打印错误原因的一个方式
		printf("%s\n", strerror(errno));
	}
	else
	{
		//正常使用空间
		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的地址并没有改变
	p = NULL;//直接将其强制变为空指针
	return 0;
}

一定要和动态内存函数成对使用!

3.calloc函数

void* calloc (size_t num, size_t size);

calloc函数在堆上申请空间并且初始化为0,然后返回起始地址

int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return -1;
	}
	//申请成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p);
	return 0;
}

3.realloc函数(增容)

realloc函数的出现让动态内存管理更加灵活。 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时
候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整 后面追加的空间足不足够进行追加?

如果不够那么就会找其他空间,连续开辟一块两倍原大小的空间,并把原来的数据拷贝到新开辟的空间!
也可能增容失败!
在这里插入图片描述

void* realloc (void* ptr, size_t size);
  • ptr 是要调整的内存地址 size 调整之后新大小 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
    1.如果够了还是返回的p的地址
    2.如果不够返回新开辟的地址
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return -1;
	}
	//申请成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//空间不够了,增加空间至20个int,增容也可能失败!
	//p = realloc(p, 20 * sizeof(int));
	//这种写法是错误的,如果增容失败,那么返回空指针,如果将p这么写,那么原来的开辟的空间也会消失,所以应该创建新的指针
	int *ptr = (int*)realloc(p, 20 * sizeof(int));//这种方法才是正确的
	if (ptr != NULL)
	{
		p = ptr;//增容成功,如果增容失败,p还是原来的地址,继续维护老的空间
	}
	else
	{
		return -1;//表示函数失败
	}
	for (i = 10; i < 20; i++)
	{
		*(p + i) = i;
;	}
	//打印
	for (i = 0; i < 20; i++)
	{
		printf("%d ", *(p + i));
	}
	//释放空间
	free(p);
	p = NULL;
	return 0;
}

二、动态内存函数易错点

1.对空指针解引用是错误的!

直接这样写是有风险的!!开辟空间失败了就会对NULL解引用!

int main()
{
	int* p = (int*)malloc(20);
	*p = 0;
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(200);//总共200字节
	if (p == NULL)
	{
		return -1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 80; i++)//访问了400字节
	{
		*(p + i) = i;
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

3.对非动态开辟空间使用free释放

一个是在栈上,一个释放的是堆上的空间!不能这样释放!

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

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

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

在这里插入图片描述

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

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

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

在堆区上申请的空间,有2种回收的方式
1.free
2.当程序退出时,申请的空间也会回收

int main()
{
	int* p = (int*)malloc(10 * sizeof(int));//会一直占用这块空间
	if (p == NULL)
	{
		return -1;
	}
	//使用
	//忘记释放
	getchar();//等待接收一个字符
	return 0;
}

请观察如下代码的问题:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.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;
}

在这里插入图片描述
1.str传给p的时候,是值传递,p是str的临时拷贝,所以当malloc开辟的空间起始地址放在p中的时候,不会影响str,str依然为NULL
2.str是NULL,strcpy想把hello world拷贝到str指向的空间时,程序就会崩溃。因为NULL指向的空间是不能直接访问的。
正确代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void GetMemory(char** p)
{
	*p = (char*)malloc(100);//*p==str
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);
	strcpy(str, "hello world");//str仍然是空指针
	printf(str);//崩溃
	free(str);
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

7.非法访问内存!

void Test(void)
{
	char* str = (char*)malloc(100);//在堆上申请的100字节的空间
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");//非法访问内存,str此时是野指针
		printf(str);
	}
}
int main()
{
	Test();
	return 0;
}

free之后一定要将指针置空!
str=NULL;
否则str是野指针

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-06 12:00:37  更:2021-10-06 12:01:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 20:51:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码