BSPday19(动态内存申请、内存泄漏及分糖果作业)

 

 

一、动态内存申请

C语言支持动态存储分配,即在程序执行期间分配内存单元的能力。利用动态存储分配,可以设计出能根据需要扩大(和缩小)的数据结构。

虽然动态存储分配适用于所有类型的数据,但主要用于字符串、数组和结构。动态分配的结构式特别有趣的,因为可以把它们链接成表、树或其他数据结构。

1、内存分配函数

为了动态的分配存储空间,需要调用三种内存分配函数的一种,这些函数都是声明在<stdlib.h>头文件中的。

· malloc函数——分配内存块,但是不对内存块进行初始化。初始化清零要与memset函数连用;

· calloc函数——分配内存块,并且对内存块进行清零。

· realloc函数——调整先前分配的内存大小。

三种函数中,malloc函数是最常用的一种。因为malloc函数不需要对分配的内存块进行清零,所以它比calloc函数更加高效。

当为申请内存块而调用内存分配函数时,由于函数无法知道计划存储在内存块中的数据是什么类型的,所以它不能返回int类型、char类型等普通类型的指针。取而代之的,函数会返回void *类型的值。void *类型的值是通用指针(万能指针),本质上它只是内存地址。

2、空指针

当调用内存分配函数时,总存在这样的可能性:找不到满足我们需要的足够大的内存块。如果真的发生了这类问题,函数会返回空指针。空指针是“不指向任何地方的指针”,这是一个区别于所有有效指针的特殊值。在把函数的返回值存储到指针变量中以后,需要判断该指针变量是否为空指针。

p = malloc(sizeof(int)*2500) //即10000字节
if(p == NULL)
{...}

二、动态分配数组

1、使用malloc函数为数组分配存储空间

可以使用malloc函数为数组分配存储空间,我们需要使用sizeof运算符来计算出每个元素所需要的空间数量。

假设正在编写的程序需要n个整数构成的数组,这里的n可以在程序执行期间计算出来。首先需要申明指针变量:

int *a;

一旦n的值已知了,就让程序调用malloc函数为数组分配存储空间:

a = malloc(n*sizeof(int));

一旦a指向动态分配的内存块,就可以忽略a是指针的事实,可以把它用作数组的名字;

2、calloc函数

可以用malloc函数来为数组分配内存,但是C语言还提供了另外一种选择(calloc函数).

calloc函数会通过把所有位设置为0的方式初始化。

3、realloc函数

一旦为数组分配完内存,稍后可能会发现数组过大或小。realloc函数可以调整数组的大小。

三、释放存储空间

C语言当中 free() 函数与 malloc() 函数应是成对出现的:
malloc() 函数负责空间的申请, malloc() 函数的对头free() 函数则负责将 malloc() 函数申请的空间给释放掉;
 

#include <stdio.h>
#include <stdlib.h>

#define 	MALLOC_SIZE		250

int main(void)
{
	//申请一段长度为250,类型为 char 的空间
	char *pointer = null;
	pointer = (char *)malloc( MALLOC_SIZE * sizeof(char) );
	
	//释放空间
	if(null != pointer)
	{
		free( pointer );
		pointer = null;
	}
	
	return 0;
}

以上是个申请空间又释放掉的显得闲得蛋疼的例子,那问题来了:

free() 函数是如何确定要释放空间大小的?
free() 函数释放掉的是什么内容呢?
指针 pointer 不指向 null 行不行?
不判断 null != pointer 是否必要?
free( pointer + 1),能否释放?
以下为个人的理解:
第一点:申请空间的大小是由用户决定的,系统有基于链表的内存管理,申请得到的空间在物理空间上不一定连续的,但申请到的空间映射出的虚拟空间是连续的,申请空间时,对于系统来说,系统只会关注申请空间的大小,并不关注空间类型,所以申请空间返回的空间也不具有特定的空间类型,只是分配了一段空间供用户使用; malloc函数返回来的是申请到空间的地址,然后用户使用一个指针指向这块空间,便可以使用了;在申请到空间的开始地址前的空间会记录着空间的大小,因此在 free() 释放空间时会先去确认空间的大小,再进行空间释放。
第二点:

空间结构的大致图示,假设此时指针 pointer 指向空间首地址0x0001,空间中存用户想要存储的数据,调用 free( pointer ) 函数,会将空间的内存给释放掉,也算是将空间的使用权给释放掉,释放后用户无法合法访问这段空间,释放掉后的空间存储的数据是随机值,释放后的空间可在下次申请空间时循环使用,若使用完之后空间不释放,则这块空间无法归还给系统,无法再次利用,导致内存泄漏;
第三点:调用调用 free( pointer ) 函数,指针 pointer 是不会被释放掉的,即便释放空间后,指针 pointer 还是指向地址0x0001的地方,释放后再继续调用指针则会越界,为了避免此类错误,最好在释放空间后将指针指向null;
第四点:释放空间前最好先判断一下 null != pointer ,因为有可能出现系统空间不足导致申请空间失败的情况,也就无法进行空间释放了;
第五点:free( pointer + 1) 是无法释放空间的,因为申请空间的地址不匹配了,而且无法找到这段空间大小的记录,导致释放空间失败;只有地址与申请空间的首地址匹配,系统查找到合理的空间长度记录才会进行空间释放操作;

四、一些作业

0个小孩围成一圈分糖果,老师顺次分给每个人的糖数为12 2 8 22 16 4 10 6 14 20.然后按下列规则进行调整,所有小孩同时把自己的糖果分一半给右边的小孩,糖块数变奇数的人,再向老师补要一块,问经过多少次调整后,大家的糖块一样多,且每人多少块?

#include<stdio.h> 

int main()
{
	int count = 0;
	int arr[10] = {12, 2, 8, 22, 16, 4, 10, 6, 14, 20};
	int arr1[10] = {0};
	while(1)
	{
		for(int i = 0 ; i < 10; i++)//判断是否是偶数,偶数除以2,否则加一除以2 
		{
			if(arr[i] % 2 == 0) 
			{
				arr[i] /= 2;
				arr1[i] = arr[i];
				
			}
			else
			{
				arr[i] = (arr[i] + 1) / 2;
				arr1[i] = arr[i];	
				
			}
		}	
		for(int i = 0; i < 9; i++)//左边的给右边的 
		{
			arr[i + 1] += arr1[i];
		}
		arr[0] += arr1[9];
		
		for(int i = 0; i < 10; i++)
		{
			printf("%d	", arr[i]);
		}
		count++;//分一次计数 
		int flag = 0;
		for(int i = 0; i < 10; i++)//看是否分完 
		{
			for(int j = 0; j < 10; j++)
			{
				if(arr[i] != arr[j])
				{
					flag = 1;	
				}	
			} 
			
		}
	printf("\n");	
		if(flag == 1)
		{
			flag = 0;
		}
		else
		{
			break;
		}
	


	}
	printf("%d次后每个孩子的糖一样, 有%d个", count, arr[0]);
	
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值