一、本课重点

  • 为什么存在动态内存管理
  • 动态内存函数介绍
  • malloc
  • free
  • calloc
  • realloc
  • 常见动态内存错误
  • 几个经典的面试题
  • 柔性数组

二、为什么存在动态内存管理

在堆区(heap)进行分配,可以节省空间

三、动态内存函数介绍

1.malloc

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

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

C语言第十八课--动态内存管理_内存空间

2.free

C语言第十八课--动态内存管理_内存空间_02

将申请的空间释放,p指向的空间虽然被释放,但是依然可通过p找到这块空间,需要将p手动赋值,断开与p之间的联系,以免造成问题。

3.calloc

与malloc区别在于在返回地址之前会把申请的空间的每个字节初始化为全0

C语言第十八课--动态内存管理_动态内存_03

4.realloc

调整动态开辟内存空间的大小

realloc使用的注意事项

    1.如果p指向的空间之后有足够的空间可以追加,后返回p

    2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存空间区域

    开辟一块满足需求的空间,并且把原来的内存中的数据拷贝回来,释放旧的内存空间

    最后返回新开辟的内存空间地址

得用一个新的变量来接收realloc函数的返回值

int main()
{
	int* p = (int*)malloc(20);
	if(p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for(i = 0; i< 5; i++)
		{
			*(p+i) = i;
			
		}
	}
	//使用malloc开辟的20个字节的空间
	//希望能够有40个字节的空间
	//在使用ralloc函数开辟更大的空间
	//realloc使用的注意事项
	//1.如果p指向的空间之后有足够的空间可以追加,,后返回p
	//2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存空间区域
	//开辟一块满足需求的空间,并且把原来的内存中的数据拷贝回来,释放旧的内存空间
	//最后返回新开辟的内存空间地址
	//3.得用一个新的变量来接收realloc函数的返回值
//	int* p2 = (int*)realloc(p, 40);

	int* ptr = realloc(p, INT_MAX);
	if(ptr != NULL)
	{
		p = ptr;
		int i = 0;
		for(i = 5; i< 10; i++)
		{
			*(p+i) = i;			
		}
		for(i = 0; i< 10;i++)
		{
			printf("%d ", *(p+i));
		}
	}
	
	//释放内存
	free(p);
	p = NULL;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.

四、常见动态内存错误

  • 对NULL进行解引用操作
  • 对动态开辟的内存越界访问
  • 对非动态开辟空间的free释放
  • 使用free释放动态开辟内存的一部分(注意指针的位置)
  • 对同一块动态内存多次释放
  • 对动态开辟空间忘记释放,会造成内存泄漏
int main()
{
	//6.动态开辟内存忘记释放,引起内存泄漏
	while(1)
	{
		malloc(1);
		Sleep(1000);//单位:ms
	}
	return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

五、几个经典的面试题

1.动态内存泄露

C语言第十八课--动态内存管理_内存空间_04

2.返回栈空间地址问题

栈区会自动销毁,引起非法访问

C语言第十八课--动态内存管理_动态内存_05

堆空间需要释放才会销毁

C语言第十八课--动态内存管理_动态内存_06

六、(flexible arry)柔性数组

C99中,结构体中的最后一个成员可以是未知大小(前面至少存在一个结构体成员),它的空间开辟需要使用malloc

C语言第十八课--动态内存管理_c函数_07

结构体中柔性数组成员不占大小(sizeof返回的这种结构大小不包括柔性数组的内存)

定义arr数组大小为5个整型

C语言第十八课--动态内存管理_内存空间_08

使用指针创建可调整大小的空间(malloc函数)- 代替柔性数组

C语言第十八课--动态内存管理_c函数_09

两种方法对比:(malloc函数开辟空间时,会找足够的空间去开辟,会造成内存碎片)

  • 柔性数组优势:
  • 1.使用malloc函数少,不用多次释放空间,减少失误可能性(方便内存释放)
  •  2.减少内存碎片,内存利用率高
  • 3.开辟的空间连续,访问空间时速度更快、效率更高