动态内存-C语言

        当我们需要根据变量定义数组,变量作为数组的长度(在[]内的)时,就用到了动态内存。

动态内存总共有四个函数:malloc;calloc;realloc;free.其引用的头文件为<stdlib.h>。

        malloc:用来动态创建内存,里面只有一个参数,即要分配的字节长度数。        其中数据类型的长度都用sizeof()计算,这样代码跨平台也可移植,不用担心不同平台的数据类型的大小是否发生改变。        其返回值是void*malloc,即系统会将malloc(从堆里面)申请出来的内存首地址返回给你去用。(void*:是没有特定具体类型的指针的意思,是通用指针或者泛型指针)。        这里malloc是以字节数申请的内存大小,它并不知道你是什么类型,所以它也不能返回给你具体数据类型。它不管你用这个内存去干嘛。        如果内存不够申请的大小,则会返回无效的指针给分配的空间或返回空指针(NULL).        其接收返回值的类型可根据变量的类型定义,但同时malloc前面也要强制转换成同种类型。

        下面是定义一个n长度的整型数组代码:

int main()
{
	int n;
	scanf("%d", &n);
	//int arr[n];//这样写长度为变量n的数组是错的
	int *p = (int *)malloc(n * sizeof(int));//n长度的int数组......其等同于int p[n];
		//因为会有返回NULL的可能性,所以要加一个断言(assert)
		assert(p != NULL);//不用等分配完后程序再崩溃掉,直接在这就结束退出函数。
	if (p == NULL)
	{
		printf("分配内存失败\n");
		return 0;
	}//一般不会被执行到这一句,但在release的模式下assert会失败,就要用的这句,通常跟assert合在一起用
	for (int i = 0; i < n; i++)//访问p,指针当数组用
	{
		p[i] = i;
	}
	for (int i = 0; i < n; i++)
	{
		printf("%4d", p[i]);
	}
	printf("%\n");
	return 0;
}

        但上面的代码还有一个问题,就是malloc函数使用完会有内存泄漏,这里就要用到free函数。

free:用来释放动态申请的内存,如果没有用free释放,则会出现内存泄漏,内存泄漏非常麻烦且容易被忽视,难以察觉,所以内存释放十分重要。        free也只需要一个参数,就是将刚刚动态申请的内存的指针丢进去就可以了,即free(p)。

下面定义一个n长度的double型数组并用完后释放的代码:

int main() {
	double n;
	scanf("%lf", &n);
	double* p = (double*)malloc(n * sizeof(double));
	assert(p != NULL);
	if (p == NULL)
	{
		printf("分配内存失败\n");
		return 0;
	}
	for (int i = 0; i < n; i++)
	{
		p[i] = i;
	}

	for (int i = 0; i < n; i++)
	{
		printf("%.1lf\n", p[i]);//%.1lf是只保留一位小数的意思
	}
	free(p);//释放p
	return 0;
}

        而正因为内存泄漏难以察觉,所以我们需要一些可以检测内存泄漏的工具,在C语言里面,我们可以引用一个叫做 <vld.h>的头文件,vld(Visual Leak Detector)是一个开源工具,用来检测内存泄漏,用于malloc,new等。

        这里我们可以看到理论应该上泄漏了160个字节,因为一共有20个格子,一个格子8个字节,

20*8=160.但实际上泄漏了212个字节,这个多出来的是用来做标记的,在后面数据结构里会说。

        而将free打开后,vld就会告诉你没有内存泄漏了。

        下面我们来看看如果内存泄漏了会有什么麻烦事。

首先我们的软件运行在工作环境中时是不允许关机的,如果有内存泄漏每天100M(兆),那它在运行的前一小段时间内是没有问题出现的,但一个月后这个程序软件可能点都点不动,点一下反应半个小时才能好,就因为内存泄漏每天100M(兆),那么30天就会泄漏掉3G内存,而这个泄漏掉的内存既没有人用它,系统也不能把它再分配出去给别的,因为在操作系统眼里这个泄漏掉的内存还是有人在用的,只是还没有用完后还给我,而实际上这部分内存是没人用的。就相当于系统借出去的内存没人用也没人还,那系统最后自己也没有可以用的内存了。那么假设一个系统有8个G的内存,而上面的一个程序就泄漏掉了3个G的内存,也就是3个G的内存被白白浪费了,系统可用的内存只剩5个G的了。一旦没有了内存,所有的程序都是运行不了的。

  其次就是内存泄漏很难调试,比如当一个程序崩溃时,我们首先要找到崩溃的点在哪里,然后再去通过调试看一下为什么在这个地方崩溃了,但要是内存泄漏了就没办法调试,因为要调试就要把程序暂停下来,通过调试在一步一步的单步执行,但只要程序一停下来后所有释放和泄漏的内存都会全部还回来。

这里就涉及到另一个问题,就是泄漏的内存什么时候会回收:1.程序(进程)退出,例如我们平时在运行框里看到的最后一句  按任意键关闭此窗口  就是程序退出。        2.关机,当Windows开机时,很多程序就自动运行起来了,比如一些背后默认运行的进程,所以有些程序是不允许退出进程的,比如监控系统,公安系统,游戏的服务器等就是基本不能退出的。所以很多应用是不允许关机或重启的。但当你关机时,不光进程会退出,整个操作系统消耗的所有的内存会全部回收,因为所有的程序都会停标。而重启就是先关机再开机,也类似于关机。

那么在C语言里几乎是没有解决内存泄漏的办法,所以要每次使用检测工具测一下。但vld有些平台不支持这个,而且有些时候你自己会忘记用检测工具。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值