动态内存管理

感谢各位大佬的光临,希望和大家一起进步,望得到你的三连,互三支持,一起进步

个人主页:LaNzikinh-CSDN博客

收入专栏:http://t.csdnimg.cn/LJ2J2

文章目录

  • 前言
  • 一.malloc函数和free
  • 二.calloc函数
  • 三.relloc函数(调整)
  • 四.常见的动态内存的错误分析
  • 五.经典笔试题
  • 总结

前言

我们之前讲解了,内存函数和字符串函数的一些知识,我们现在来说一下,关于动态开辟内存的一些函数和一些事例,为什么要开辟动太内存的分布呢?因为我们之前学的都是静态的,有一些题目,你并不知道我需要的内存大小是多少,所以我们就需要了解一个动态开辟的方法。


先从几个动态函数说起

一.malloc函数和free

void* malloc (size_t size);

这个函数就是像内存申请一块连续可用的空间,并且返回指向这块空间的指针,所以我们运用这个函数的时候必须要用一个指针去接收他,如果开辟成功,他就会返回开辟好的指针,如果开辟失败,就会返回一个空指针,因此它的返回值一定要做检查。来看一段代码

#include<stdio.h>
#include<stdlib.h>//注意头文件
#include<assert.h>
int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	assert(p);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;

	}
//必须释放动态开辟空间的起始位置
	free(p);
	p = NULL;
}

free函数就是用来释放空间的,如果动态开辟的内存没有释放的话,那么就会造成很严重的内存泄露问题。

二.calloc函数

void* calloc (size_t num//开辟的元素个数, size_t size//元素的大小);

这两个函数实际上是一样的,不管是他的初始化方式,还是他的功能都是与malloc函数是一样的,但是唯一不同的是malloc函数开辟的是随机值calloc函数开辟的空间会全部初始化把它们存放为0

int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	assert(p);
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	free(p);
	p = NULL;
	return 0;
}

三.relloc函数(调整)

void* realloc (void* ptr//调整空间的起始位置, size_t size//空间的大小);

调整到底是什么意思呢?就是说如果我之前用malloc函数开辟的空间大小,如果我不满意的话。我就可以用这个relloc函数来调整之前的空间大小。

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

情况一:原有空间之后,有足够大的空间

有空间的话,就会直接开辟

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

若后面没有,则会重新开辟,先把原来拷贝进新的,在释放空间

特殊情况:开辟空间失败会自动返回空指针

四.常见的动态内存的错误分析

4.1对NULL指针的解引用操作

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

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

void test()
{
	int i = 0;
	int* p = (int*)malloc(10 * sizeof(int));
	assert(p);
	//注意这里是<=
	for (i = 0; i <= 10; i++)
	{
		//当i是10的时候越界访问
		*(p + i) = i;
	}
	free(p);
}

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

这个就不用代码举例了,记住free函数,只对动态开辟内存的函数使用

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

这个问题的表述可能不清晰,他实际上的意思是说因为free函数他是释放的malloc函数,开辟的初始位置的那个指针,如果释放的不是动态内存的起始位置就会有这个错误

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

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

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

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

这个也是之前最开始说的最经典的错误就是你开辟了空间,忘记是否就会造成内存泄漏,这个地方也不多说了

五.经典笔试题

5.1能否打印出hello,world

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

等GetMemory函数返回后使用的指针去访问数组就是非法访问,因为数组的内存已经还给了操作系统,所以不可以。

5.2能否打印

void GetMemory(char *p)
 {
 p = (char *)malloc(100);
 }
void Test(void)
 {
 char *str = NULL;
 GetMemory(str);
 strcpy(str, "hello world");
 printf(str);
 }

他犯了很多错误,第一个错误就是开辟的空间没有释放,第二个错误就是他其实并没有开辟到空间就是空间开辟了,但我无法获取他开辟的空间,我并没有拿到地址,因为局部变量出去了就会被销毁

改1:利用二级指针二级指针是存放指针变量的地址的,这个题的思路,其实就是我们要把P的地址放进str就可以了

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

改2:这个就是利用函数返回值的性质去改的,其实改这个笔试题的思路,就是我必须要把开辟出来的空间的地址找到,所以我直接接触他的返回值也是可以的

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

总结

C语言引用了动态开辟让程序员可以自己申请空间,使代码运行变得比较灵活了。在以后学习数据结构的时候,需要大量运用动态开辟的知识。所以说还是比较重要的。

  • 52
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 43
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 43
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LaNzikinh篮子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值