C语言中的动态内存管理


1.内存的使用方式。

  • 当我们创建一个变量时
    局部变量和函数的形参会储存在栈区。
  • 动态内存会储存在堆区。
  • 全局变量,静态变量储存在静态区

2.内存动态分配存在的意义。

我们常用的内存开辟方法

int input = 0;//在栈空间上开辟四个字节。
char arr[10] = {0};//在栈空间上开辟10个字节

上述开辟空间的缺点

  • 1.空间大小是确当的。
  • 2.数组在申请的时候,必须指定数组的长度,它所需要的内存在编译时分配。

但是有时候需要开辟多少空间是程序运行后才能知道的,那么数组开辟空间这种方式显然不能满足,这时候就只能用试试动态开辟内存了。


3.动态内存的函数

1.malloc

  • 分配内存块
    C语言提供了一个动态开辟空间的函数
void* malloc(sizeof(size_t size));

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

  • 1.如果开辟空间成功,则返回一个指向开辟好的空间的指针。
  • 2.如果开辟空间失败,则返回一个NULL指针。
  • 3.malloc的返回值为void*类型,所以malloc函数并不知道开辟空间的类型,具体在使用者自己决定。(对返回值强制类型转换)
  • 4.如果开辟的空间为0,MSDN中是这么解释:的如果size为0,malloc将在堆中分配一个长度为零的项,并返回指向该项的有效指针。

malloc函数的使用

int main()
{
	//向内存申请10个整形的空间
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		//打印错误原因的一个方式
		printf("%s\n", strerror(errno));
	}
	else
	{
		//正常使用空间
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d".*(p + i));
		}
	}
	return 0;
}

MSDN中对malloc函数返回值的解释

  • malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available. To return a pointer to a type other than void, use a type cast on the return value. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Always check the return from malloc, even if the amount of memory requested is small.

2.free

  • C语言中提供了函数free,专门用来释放回收动态内存的
void free(void* ptr);
  • 释放指针ptr指向的内存块的动态内存。
  • 如果指针ptr指向的空间不是动态开辟的,那么free函数的行为是未定义的。
  • 如果指针ptr指向的是NULL,那么free函数什么也不做。

free函数的使用

int main()
{
	//向内存申请10个整形的空间
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		//打印错误原因的一个方式
		printf("%s\n", strerror(errno));
	}
	else
	{
		//正常使用空间
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d".*(p + i));
		}
	}
	//当动态申请的空间不再使用的时候
	//就应该还给操作系统
	free(p);
	p = NULL;//为了防止p再次被使用 导致内存出错 在释放p后 通常吧指针p置空
	return 0;
}

MSDN中的解释

  • The free function deallocates a memory block (memblock) that was previously allocated by a call to calloc, malloc, or realloc. The number of freed bytes is equivalent to the number of bytes requested when the block was allocated (or reallocated, in the case of realloc). If memblock is NULL, the pointer is ignored and free immediately returns. Attempting to free an invalid pointer (a pointer to a memory block that was not allocated by calloc, malloc, or realloc) may affect subsequent allocation requests and cause errors.
    After a memory block has been freed, _heapmin minimizes the amount of free memory on the heap by coalescing the unused regions and releasing them back to the operating system. Freed memory that is not released to the operating system is restored to the free pool and is available for allocation again.
    When the application is linked with a debug version of the C run-time libraries, free resolves to _free_dbg. For more information about how the heap is managed during the debugging process, see Using C Run-Time Library Debugging Support.

3.calloc

  • C语言提供了一个函数叫calloc,calloc函数也用来动态内存分配。
void* calloc(size_t num,size_t size);
  • 函数的功能是为num个大小为size的元素开辟一块空间,并且把每个空间初始化为0。
  • 函数calloc和函数malloc的区别只在于calloc函数在返回指针前会把申请的空间的每字节初始化为0。

calloc函数的使用

int main()
{
       int *p = NULL;
       p = calloc(10,sizeof(int))
       if(p != NULL)
       {
       //使用空间
       }
       free(p);
       p = NULL;
       return0;
}
  • 所以当我们使用的空间需要初始化的时候就可以调用calloc

MSDN中的解释

  • The calloc function allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0.
    calloc calls malloc in order to use the C++ _set_new_mode function to set the new handler mode. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when calloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. To override the default, call

4.realloc

  • realloc函数的出现让动态内存管理更加灵活
  • 有时候我们会发现过去申请的空间太小或者太大了,那么为了合理的使用内存,我们要对内存做灵活的调整,realoc函数就能实现灵活使用内存。
void* realloc(void* ptr,size_t size);
  • ptr是需要调整的内存地址
  • size调整之后的新大小
  • 返回值为调整之后的内存起始位置
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
  • realloc在调整内存空间时存在两种情况。

1.原有空间足够大
在这里插入图片描述
2.原有空间不够大
在这里插入图片描述
当是情况1的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。 情况2 当 是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来 使用。这样函数返回的是一个新的内存地址。 由于上述的两种情况,realloc函数的使用就要注意一些。

realloc函数的使用

#include <stdio.h>
int main() {
    int *ptr = malloc(100);
    if(ptr != NULL)
    {
        //使用内存
    }
else
    {
         exit(EXIT_FAILURE);
    }
//扩展容量
//代码1
ptr = realloc(ptr, 1000);//如果申请失败将会丢失原内存。
//代码2
int*p = NULL;
p = realloc(ptr, 1000); 
if(p != NULL)
{
       ptr = p;
       //使用内存
}
    free(ptr);
    ptr = NULL;
    return 0;
}

relloc函数也可以实现malloc的功能

relloc(NULL,size_t);

MSDN中对realloc返回值的解释

  • realloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough available memory to expand the block to the given size. In the first case, the original block is freed. In the second, the original block is unchanged. The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

MSDN中对函数realloc的解释

  • The realloc function changes the size of an allocated memory block. The memblock argument points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc and allocates a new block of size bytes. If memblock is not NULL, it should be a pointer returned by a previous call to calloc, malloc, or realloc.
    The size argument gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a new memory location, the pointer returned by realloc is not guaranteed to be the pointer passed through the memblock argument.
    realloc calls malloc in order to use the C++ _set_new_mode function to set the new handler mode. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when realloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. To override the default, call

4.常见的内存错误

1.对NULL指针的解引用

int main()
{
     int* p = (int *)malloc(INT_MAX/4);
     *P = 20;//P的值为NULL就会出现错误
}

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

int main()
{
	int i = 0;
	int* p = (int*)malloc(10 * sizeof(int));
	if (NULL == p)
	{
		exit(EXIT_FAILURE);
	}
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = i;//i为10时越界访问
	}
	free(p);
	p = NULL;
	return 0;
}

3.对非动态开辟内存使用free

int main()
{
	int a = 10;
	int* p = &a;
	free(p);//此行为在c语言中是为定义的
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(100);
	p++;
	free(p);//p++后p将不在指向动态内存起始位置
	return 0;
}

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

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

6.动态开辟内存忘记释放导致内存泄漏

void wuhu()
{
	int* p = (int*)malloc(100);
	if (NULL != p)
	{
		*p = 20;
	}
}
int main()
{
	while (1)
	{
		wuhu();
	}
	return 0;
	
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值