动态内存管理

文章目录

1、动态内存分配的意义

在我们平时定义一个变量或一个数组时其大小为固定值。无法做到灵活多变,我们使用动态内存分配可以很好的解决问题。

2、动态内存函数

2.1malloc

void* malloc (size_t size);

其中size为需要申请的字节大小数,类型为size_t;
返回值为void* 成功时,指向函数分配的内存块的指针。此指针的类型始终为void*,可以将其转换为所需的数据指针类型,如果函数未能分配请求的内存块,则返回空指针。
在我们使用动态内存分配函数后,申请得到的内存要释放这里我们使用 :

void free (void* ptr);

来释放获得的内存。
举一个使用的例子。

#include<stdlib.h>
#include<stdio.h>
int main()
{
	int *p = (int *)malloc(10 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p[i] = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	} 
	printf("\n");
	free(p);
	return 0;
}

2.2calloc

void* calloc(size_t num,size_t size);
为num元素数组分配一个内存块,每个元素的大小为字节长,并将其所有位初始化为零。有效的结果是分配(num*size)字节的零初始化内存块。如果大小为零,则返回值取决于特定的库实现(它可能是空指针,也可能不是空指针),但不应取消对返回指针的引用。

#include<stdlib.h>
#include<stdio.h>
int main()
{
	int *p = (int *)calloc(10, sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
	return 0;
}

动态内存管理

我们通过查看内存可以看到申请得到的空间确实被初始化为0。

2.3realloc

在我们通过动态内存申请获得内存不够用时,可以使用realloc为其增加空间,其原型为

void* realloc (void* ptr, size_t size);
ptr为指向以前使用malloc、calloc或realloc分配的内存块的指针。或者,这可以是一个空指针,在这种情况下,将分配一个新块(就像调用了malloc一样)。
size为内存块的新大小,以字节为单位。size_t是无符号整数类型。

#include<stdlib.h>
#include<stdio.h>
int main()
{
	int *p = (int *)malloc(10 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p[i] = i;
	}
	int *c = (int *)realloc(p, 20 * sizeof(int));//扩大容量
	/*if (c != NULL)
	{
		p = c;
	}
	*/
	for (i = 10; i < 20; i++)
	{
		c[i] = i;
	}
	for (i = 0; i < 20; i++)
	{
		printf("%d ", c[i]);
	} 
	printf("\n");
	free(c);
	return 0;
}

这里需要说明当内存中有足够的连续空间时则,分配向后的连续空间返回原指针。当连续空间不足时则会重新找一块新内存,将原来的数据复制下来,新的空间也可以使用。

3、 常见的动态内存错误

3.1 对NULL指针的解引用操作

若动态内存申请1失败则会返回空指针,此时对其解引用就会发生错误。

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

int main()
{
	int *p=(int*)malloc(10* sizeof( int));
	int i = 0;
	for (i = 0; i < 13; i++)//对动态内存分配的空间越界访问。
	{
		p[i] = i;

	}
	free(p);
	return 0;
}

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

int main()
{
	int p = 0;
	free(p);//对非动态开辟内存使用free释放
	return 0;
}

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

void text()
{
	int *p = (int *)malloc(10 * sizeof(int));//对一部分动态内存申请的释放。
	p++;
	free(p);

}

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

void text()
{
	int *p = (int *)malloc(10 * sizeof(int));//对动态内存的多次释放。
	free(p);
	free(p);

}

3.6 动态开辟内存忘记释放

虽然程序结束会自动释放,但在大项目中可能会造成严重的内存浪费。

4、 柔性数组

下边是一个柔性数组。

struct student
{
	int i;
	int a[];//也可写为a[0]
};

4.1柔性数组的特点与使用

结构中的柔性数组成员前面必须至少一个其他成员。
sizeof 返回的这种结构大小不包括柔性数组的内存。
包含柔性数组成员的结构用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

struct student
{
	int j;
	int a[];//柔性数组
}a;
int main()
{
int i = 0;
struct student *p = (struct student*)malloc(sizeof(a)+100 * sizeof(int));//这样相当于a[100]
p->j = 100;
for (i = 0; i<100; i++)
{ 
	p->a[i] = i;
}
free(p);
return 0;


}

4.2 柔性数组的优势

柔性数组对于动态内存申请来说有以下两个优势
1.方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
2.这样有利于访问速度.
连续的内存有益于提高访问速度,也有益于减少内存碎片。

上一篇:c++ 的学习 堆空间申请与释放-malloc,free


下一篇:C++收藏夹