栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

动态内存开辟

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

动态内存开辟

动态内存开辟
  • (一)三种方式
  • (二)动态内存函数
    • 1.malloc和free
    • 2.calloc
    • 3.realloc
  • (三)常见错误
    • 1.对空指针进行解引用
    • 2.对动态内存开辟的越界访问
    • 3.与free有关的错误
      • free释放非动态开辟内存
      • free释放动态内存空间的一部分
      • free对同一块空间多次释放
      • 动态开辟内存忘记释放/内存泄漏

(一)三种方式

  内存中存在三种空间,分别是栈区(用来存放局部变量和函数形式的参数),堆区(动态内存分配),静态区(存放全局变量和静态变量)

(二)动态内存函数 1.malloc和free

  malloc是申请开辟动态内存分配空间函数,头文件为,在MSDN上解释为void *malloc( size_t size );  如果开辟成功,那么返回值为指向这块空间的指针,如果开辟失败,那么返回NULL。
  free是释放内存空间函数,和malloc一起使用。

#include 
#include 
int main()
{
	int* p = (int*)malloc(40);
	//开辟内存空间
	if (p == NULL)//开辟失败
	{
		return -1;
	}
	for (int i = 0;i < 10;i++)
	{
		*(p + i) = i;
	}
	free(p);
	//释放内存空间
	return 0;
}

  在内存中显示如下,

2.calloc

  calloc也是开辟内存空间函数,MSDN上解释为void *calloc( size_t num, size_t size );,与malloc函数不同,calloc函数在堆区开辟空间后初始化为0,其中,num为元素的个数,size为每个元素的字节长度。

#include 
#include 
int main()
{
	int* p = (int *)calloc(10,sizeof(int));
	//开辟内存空间
	if (p == NULL)//开辟失败
	{
		printf("%d", strerror(errno));
		return -1;
	}
	for (int i = 0;i < 10;i++)
	{
		printf("%d ", *(p + i));
		//输出为0 0 0 0 0 0 0 0 0 0
	}
	free(p);
	//释放内存空间
	return 0;
}
3.realloc

  realloc也是内存开辟函数,要在原有开辟的基础上再次开辟,相当于增加空间,在MSDN上解释为void *realloc( void *memblock, size_t size );,头文件为或者,其中memblock是原来开辟内存空间的起始地址,size是再次开辟的内存空间之后的总大小,单位是字节。

#include 
#include 
#include 
int main()
{
	int* p = (int *)calloc(10,sizeof(int));
	//开辟内存空间
	if (p == NULL)//开辟失败
	{
		printf("%d", strerror(errno));
		return -1;
	}
	int* ch = (int*)realloc(p, 20 * sizeof(int));
	if (ch != NULL)
	{
		p = ch;//开辟成功
	}
	else
	{
		return -1;//开辟失败
	}
	for (int i = 10;i < 20;i++)
	{
		*(p + i) = i;
	}
	for (int j = 0;j < 20;j++)
	{
		printf("%d ", *(p + j) );
	}
	free(p);
	//释放内存空间
	return 0;
}

  realloc函数在内存中开辟空间的形式如下,如果后续空间足够大,那么就直接开辟;如果后续空间不足,那么将向后寻找直至找到足够开辟空间的位置,如果找不到,那么开辟失败,返回NULL。如图所示,

(三)常见错误 1.对空指针进行解引用
#include 
int main()
{
	int* p = (int*)malloc(20);
	*p = 20;//error
	return 0;
}

  如果开辟内存空间失败,那么p为空指针,无法进行操作。应该加判断,

	if (p == NULL)
	{
		return -1;
	}
	else
	{
		*p = 20;
	}
2.对动态内存开辟的越界访问
#include 
int main()
{
	int* p = (int*)malloc(5*sizeof(int));
	if (p == NULL)
	{
		return -1;
	}
	for (int i = 0;i < 10;i++)//error
	{
		*(p + i) = i;//赋值
	}
	for (int j = 0;j < 10;j++)
	{
		printf("%d ", *(p + j));//打印
	}
	free(p);
	return 0;
}

  在这里malloc函数开辟的空间为五个整型的大小,在赋值时,却对十个整型进行赋值,导致动态内存开辟的越界访问,运行显示错误。

3.与free有关的错误 free释放非动态开辟内存
#include 
int main()
{
	int a = 10;
	int* p = &a;
	free(p);//error
	p = NULL;
	return 0;
}

  这里的p开辟的地址被放在栈区,而free是对堆区的内存进行操作,运行报错。

free释放动态内存空间的一部分
#include 
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return -1;
	}
	for (int i = 0;i < 10;i++)
	{
		*p++ = i;
	}
	free(p);
	return 0;
}    

  free指向的应该是释放空间的头地址,p++过后,p已经不再指向起始地址了,运行产生错误。

free对同一块空间多次释放
#include 
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	free(p);
	free(p);
	return 0;
}  

  两次释放p的空间,error,可以在每次释放之后给p赋值为NULL以避免这种错误。

动态开辟内存忘记释放/内存泄漏

  动态开辟内存或通过free手动释放或者在程序结束时进行自我回收。如果不进行free释放空间,程序一直运行且不结束的话,则会存在内存泄漏,除非程序重启。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/317852.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号