动态内存管理

目录

一.为什么存在动态内存分配

二.动态内存函数的介绍

1.malloc和free

2.calloc

3.realloc

三.常见的动态内存错误

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

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

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

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

 5.对同一块开辟的空间多次释放

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

四.几个经典的笔试题

一.为什么存在动态内存分配

        我们已经掌握的内存开辟方式有:

int a = 10;//在栈空间开辟4个字节的连续空间

int b[20] = { 0 };//在栈空间开辟20个字节的连续空间

这种开辟空间的方式有以下特点:

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

        2.开辟数组时必须指定大小

初学数组时,我写过下面的错误代码。

int N;
scanf("%d",&N);
int a[N]={ 0 };

可N是变量,不能用于数组元素个数的初始化。

如果我们需要的空间大小在程序运行时才能知道,那就只能试试动态内存开辟了。

二.动态内存函数的介绍

1.malloc和free

void* malloc (size_t size);

void free (void* ptr);

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

若开辟成功,返回指向这块空间的指针

若开辟失败,返回NULL指针,因此malloc的返回值一定要做检查

使用完malloc函数要用free释放申请的内存空间

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int* p = (int*)malloc(40);//开辟40个字节的栈空间
	if (p == NULL)            //检查是否为空指针
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i)=i;
	}
	free(p);                 //用完后释放空间,注意参数为首地址
	p = NULL;                //置为空指针
}    

2.calloc

void* calloc (size_t num, size_t size)

calloc的两个参数分别为申请元素的个数每个元素的大小

使用和malloc差不多,但是申请的空间会被初始化为0,

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d  ", *(p + i)); //输出为 10个0
	}
	free(p);
	p = NULL;
}

3.realloc

void* realloc (void* ptr, size_t size)

realloc用于重新设置要开辟内存空间的大小,可以是增大或减小

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

size 是新开辟内存空间的大小

若原空间后面未开辟的空间足够使用,则返回原先的起始地址

 若原空间后面未开辟的空间不足以填满新开辟内存空间,

则会在某个地址开辟所需要的空间,free掉原空间的地址,

并且返回新的地址的起始地址

真 ·  一条龙服务

 若扩容失败,会返回空指针,因此也要检查是否是空指针

三.常见的动态内存错误

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

void test()
{
    int *p = (int*)malloc(INT_MAX/4);
    *p = 20;
    free(p);
}

若p为空指针,则程序错误。

解决方案:检查是否为空指针

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

int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	for (int i = 0; i <= 10; i++)  //当i为10时,形成越界访问,程序出错
	{
		printf("%d  ", *(p + i));
	}
	free(p);
	p = NULL;
}

使用这块空间时要注意是否已经越界访问

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

    int a = 10;
	int* p = &a;
	free(p);

一执行,程序崩溃了

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

void test()
{
	int* p = (int*)malloc(100);
	p++;
	free(p);
}

同样会崩溃

 5.对同一块开辟的空间多次释放

void test()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);
}

没错,又又又崩溃了,就不上图了

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

如果使用空间后不释放,会导致内存泄漏。

内存泄漏的堆积,这会最终消耗尽系统所有的内存

四.几个经典的笔试题

1.

void GetMemory(char* p)            //对空指针解引用
{
	p = (char*)malloc(100);        //内存泄露
}
void test()
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");    
	printf(str);
}

int main()
{
	test();

}

p是str的一份临时拷贝,指向malloc申请的起始地址,

出了函数之后,内存还给系统,str仍为空指针,strcpy把“hello world”放进空指针

2.

char *GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void test()
{
	char* str = NULL;
	str=GetMemory();        //野指针str
	printf(str);
}

int main()
{
	test();

}

定义字符串p,并返回p的地址

但是当出了这个函数,内存还给系统,没有使用权限

指针变为


3.

void GetMemory(char** p,int num)            //传址调用
{
	*p = (char*)malloc(num);        
}
void test()
{
	char* str = NULL;
	GetMemory(&str,100);
	strcpy(str, "hello world");
	printf(str);                                
                                            //没有free
}

int main()
{
	test();

}

打印hello world

没有释放空间

4.

void GetMemory(char** p,int num)
{
	*p = (char*)malloc(num);
}
void test()
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello world");
	free(str);                            //还给你,我还要用,哼~
	if (str != NULL)
	{
		strcpy(str, "!!!");
		printf(str);
	}
}

int main()
{
	test();

}

开辟100个字节的空间后,又把这块空间还给操作系统

再次把“!!!”放进这块空间,非法修改

tips:动态内存管理是在堆区上进行的。

  • 36
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 32
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二球悬铃木丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值