动态内存

      在我们编写程序的过程中,经常会使用到动态内存,比如我们在不向子函数传指针的,但又得让子函数向父函数传递一个指针,这个时候我们就得用到动态内存这个知识。

      但是关于动态内存,它到底是如何创建和使用的呢?让我们一起来看一下。

      一、动态内存的申请。

      我们要申请动态内存,就要用到malloc(),calloc(),realloc()函数,首先就得引用#include<stdlib.h>这个头文件。

      1、malloc函数

       malloc()函数的作用就是申请动态内存空间,malloc()函数如何使用呢?

       malloc()函数的形参就是所要申请内存的字节数(动态数组所占用的总字节数),如果动态申请成功,则它的返回值就是所申请连续动态内存的首地址,如果申请失败,则它的返回值就是一个空指针 。我们以整型为例,形式如下:

       int *p=(int *)malloc(10*sizeof(int));     //10*sizeof(int)就是10个int长度,等于40字节,所以申请的这个动态内存可存放10个整型变量 ;

        free(p);       //释放所申请的动态内存p;

        动态内存存放在堆里,它突破了局部变量的作用域和生存周期,如果申请动态内存成功,只有经过free()函数释放或程序运行结束后才会销毁 ,否则此段内存始终存在并可以使用。

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

int *Fun()
{
	int arr[]={1,2,3,4,5,6,7};
	return arr;
}
int main()
{
	int *p=Fun();
	for(int i=0;i<7;i++)
	{
		printf("%d",p[i]);
	}
	printf("\n");
	return 0;
}

        我们想通过上段代码,将arr[]传给main函数。

运行结果如下图。

         

       显然这不是我们想要的结果,那我们怎样才能将子函数中的arr[]传递到main()函数中呢,上面我们说了动态内存,我们用动态内存试试。

int *Fun()
{
	int *arr=(int *)malloc(10*sizeof(int));     //申请动态内存
	for(int i=0;i<10;i++)
	{
		arr[i]=i+1;
	}
	return arr;
}
int main()
{
	int *p=Fun();
	for(int i=0;i<10;i++)
	{
		printf("%d ",p[i]);
	}
	printf("\n");
	free(p);           //释放动态内存p

	return 0;
}

       我们使用malloc()函数申请10个整型单元格子的内存大小,将arr的首地址传给p,在主函数中输出,运行结果如下图,显然达到了我们想要对的结果。



        2、calloc()函数 

        calloc()函数的形参就是所申请的单元格数和每个单元格所占的字节数,如果动态申请成功,则它的返回值就是所申请连续动态内存的首地址,如果申请失败,则它的返回值就是一个空指针 。

        用malloc()函数申请动态内存时,动态内存内个格子的初始值为随机值,如下代码所示:

int *Fun()
{
	int *arr=(int *)malloc(10*sizeof(int));
	return arr;
}
int main()
{
	int *p=Fun();
	for(int i=0;i<10;i++)
	{
		printf("%d ",p[i]);
	}
	printf("\n");
	free(p);

	return 0;
}

        calloc()函数也可用来申请动态内存,但是它与malloc()函数的区别在哪里呢?

        与malloc()函数相比,calloc()函数所申请的动态内存初始化为0

int *Fun()
{
	int *arr=(int *)calloc(10,sizeof(int));
	return arr;
}
int main()
{
	int *p=Fun();
	for(int i=0;i<10;i++)
	{
		printf("%d ",p[i]);
	}
	printf("\n");
	free(p);

	return 0;
}

        如果我们用malloc()函数申请的动态内存,想要将其初始化成0,就需要通过以下步骤,相比于calloc()函数就比较麻烦。

int *Fun()
{
	int *arr=(int *)malloc(10*sizeof(int));
	for(int i=0;i<10;i++)
	{
		arr[i]=0;
	}
	return arr;
}
int main()
{
	int *p=Fun();
	for(int i=0;i<10;i++)
	{
		printf("%d ",p[i]);
	}
	printf("\n");
	free(p);
	return 0;
}

       3、realloc()函数

       realloc()函数的作用就是修改所申请动态内存的大小。

       realloc()函数的形参就是所要改变的动态数组的首地址和修改后的动态内存大小的总字节数,如果动态申请成功,则它的返回值就是所申请连续动态内存的首地址,如果申请失败,则它的返回值就是一个空指针 。

       我们经常会遇到这么一个问题,所申请的动态内存大小,不够我们使用或者是使用不完。

       (1)、动态内存的扩大

      在不使用realloc()函数的情况下,我们就得先申请一个新的足够大的动态内存空间,将就空间的数据复制到新的空间中,释放旧的空间。

int main()
{
	int *arr=(int *)malloc(10*sizeof(int));  //我们申请了10个整型单元格但是我们想将20个数依次存放在动态数组中
	for(int i=0;i<10;i++)
	{
		arr[i]=i+1;
	}
	int *brr=(int *)malloc(20*sizeof(int));     //我们就得重新申请动态内存
	for(int i=0;i<10;i++)   //将arr[]中的数据复制到brr[]中
	{
		brr[i]=arr[i];
	}
	for(int i=10;i<20;i++)
	{
		brr[i]=i+1;
	}
	free(arr);
	for(int i=0;i<20;i++)
	{
		printf("%d ",brr[i]);
	}
	printf("\n");
	free(brr);
}

        但是如果我们使用了realloc()函数的话就不用这么麻烦。

int main()
{
	int *arr=(int *)malloc(10*sizeof(int)); 
	for(int i=0;i<10;i++)
	{
		arr[i]=i+1;
	}
	int *brr=(int *)realloc(arr,20*sizeof(int));
	for(int i=10;i<20;i++)
	{
		brr[i]=i+1;
	}

	for(int i=0;i<20;i++)
	{
		printf("%d ",brr[i]);
	}
	printf("\n");
	free(brr);
	return 0;
}

realloc()函数会自动释放旧的动态内存空间,不需要再次释放。

(2)、缩小动态内存

realloc()函数不能进行动态内存的缩小,申请成功的动态内存不经过free()函数的释放一直存在,直到程序运行结束 。

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int *arr=(int *)malloc(10*sizeof(int)); 
	for(int i=0;i<10;i++)
	{
		arr[i]=i+1;
	}
	printf("未改变前arr的首地址 %d\n",arr);
	for(int i=0;i<10;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
	arr=(int *)realloc(arr,5*sizeof(int));
	for(int i=0;i<10;i++)
	{
		arr[i]=i+1;
	}

	printf("改变大小后arr的首地址 %d\n",arr);
	for(int i=0;i<10;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
	free(arr);
}

我们可以看出,无论是首地址还是内存大小都没有发生改变。

二、动态内存的释放

       使用完动态内存后要用free()函数释放掉申请的动态内存,否则会造成 内存泄漏( 可使用的内存越来越少), 释放掉动态内存后要将保存原动态内存首地址的指针置空,此时这段内存已被操作系统回收,这个指针为野指针。

free()函数的参数就是所要释放动态内存的首地址。

在我们用到free()函数时经常会遇到崩溃问题,使用free()函数时程序会崩溃,有下列四种原因:

1、越界

越界使用动态内存。

int main()
{
	int *arr=(int *)malloc(10*sizeof(int)); 
	for(int i=0;i<=10;i++)     //这里的判断条件应该是i<10
	{
		arr[i]=i+1;
	}
	free(arr);
	return 0;
}

2、修改了指针指向

int main()
{
	int *arr=(int *)malloc(10*sizeof(int)); 
	for(int i=0;i<=10;i++)
	{
		*arr=0;
		arr++;
	}
	free(arr);
}

3、重复释放同一段内存

int main()  
{  
    int *arr = (int *)malloc(10*sizeof(int));  
    for(int i=0;i<10;i++)  
    {  
        arr[i] = i;  
    }  
    int *brr = (int *)malloc(20*sizeof(int));  
    for(int i=0;i<10;i++)  
    {  
        brr[i] = arr[i];  
    }  
    free(arr);  
    brr = arr;  
          
    free(arr);  
    free(brr);// 应将arr=NULL;  
    return 0;  
} 

4、释放非动态内存    

int main()  
{  
    int arr[10];  
    free(arr);  
  
    return 0;  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值