一.动态内存分配的定义
1.动态内存分配
就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。 动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。
2.与静态内存的区别
静态内存:都在栈区分配的空间,分配的空间都是固定的大小
例如对数组定义 : int a[101]; (定义一个长度为101的整型数组)
动态内存:分配空间从堆中申请,不是栈区
3.内存使用方式
c语言编译程序占用内存分为以下部分
①代码区:存放程序的二进制代码
②常量区:所有常量(常量字符串)存放在常量区,程序结束后由操作系统释放
③全局区:存放全局变量,静态数据,常量,程序结束后由操作系统释放
④栈区:有编译器自动分配存放为运行函数而分配的局部变量,函数参数,返回数据,返回地址(类似数据结构的栈)
⑤堆区:由程序员分配释放,若程序员不释放,程序技术后可能由操作系统回收,与数据结构中的堆不一样
二.有关动态内存分配的函数
1.malloc函数
格式:void*malloc(size);
功能:为大小为size字节的对象分配存储空间,存储空间的初始值不确定
返回值:若分配成功,返回一个指向已分配开头的指针,否则返回空指针
注:因为 malloc 函数默认为 void 型 定义时必须强制转换成需要的类型
具体操作:
①动态内存分配单个指针(不为数组指针)
从堆中申请8个字节的内存 使用 malloc(8);
#include<stdlib.h> // malloc函数头文件
#include<stdio.h>
#include<string.h>
int main()
{
int *a;
a=(int *)malloc(8); //申请8个字节的内存,并且是连续的
// 或者前两行改为 int *a=(int *)malloc(sizeof(int));
if(a==NULL) printf("OUT");
else
{
*a=1001;
printf("%d",*a);
free(a);
}
system("pause");
return 0;
}
②.动态内存分配数组指针
分配 n 个连续的 int 型空间 格式: int *a=(int*)malloc(n*sizeof(int));
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
int n,*a;
scanf("%d",&n);
a=(int *)malloc(n*sizeof(int)); //申请 n 个
for(int i=1;i<=n;i++) *(a+i)=i*i;
for(int i=1;i<=n;i++) printf("%d ",*(a+i));
system("pause");
return 0;
}
2.calloc函数
功能和上述 malloc 功能相同 ,存在一点区别,calloc 定义后空间内容的初始值为0
①动态内存分配数组型指针
格式写法: int *a=calloc(n,sizeof(int));
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
int n,*a;
scanf("%d",&n);
a=(int *)calloc(n,sizeof(int)); // 注意下标从0开始 0~n-1
for(int i=0;i<n;i++) printf("%d ",*(a+i));
printf("\n");
for(int i=0;i<n;i++) *(a+i)=i*i;
for(int i=0;i<n;i++) printf("%d ",*(a+i));
system("pause");
return 0;
}
3. free 函数
格式:free(p);
功能:将 malloc calloc 或者 realloc函数分配的内存地址返回给堆,释放指针的空间,尽管指针仍然指向这块区域,此时为垃圾数据。
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
int n,*a;
scanf("%d",&n);
a=(int *)malloc(sizeof(int));
*a=n;
printf("%p %p\n",&a,a);
free(a); // free释放指针空间 其指向变量改变
printf("%p %p %d",&a,a,*a); // 但 p 的变量地址仍然没变 称为迷途指针
system("pause");
return 0;
}
所以,在释放指针后,需将其命名为空指针 NULL
int *a=(int *)malloc(sizeof(int));
free(a);
a=NULL;
4. realloc 函数
功能:判断当前指针是否有足够的连续空间
① 如果有,扩大内存空间后返回
② 否则,按照指定的大小分配空间,将原有数据拷贝到新分配的内存区域
格式:
// 扩容 p
int *ret = realloc(p,n);
if ( ret != NULL ) p = ret ;
关于为什么扩容a不可以直接 a = realloc ( a , n ) ;
扩容可分为以下三种情况:
① a 的地址处 , 有空余空间来扩容 // 地址保持不变
② a 的地址处,没有空余的空间扩容,但有其他的空间可储存扩容后的空间
// 在一个新的地方申请足够大的地方,此时地址不是原来 a 的地址
③ 调整空间失败 // 扩容失败
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
int n;
scanf("%d",&n);
int *a=(int *)malloc(2*sizeof(int));
for(int i=0;i<=5;i++) *(a+i)=i*i;
for(int i=0;i<=2;i++) printf("%d ",*(a+i));
int *ret=(int *)realloc(a,100); // 扩容操作
if(ret!=NULL)
a=ret;
printf("\n");
for(int i=1;i<=5;i++) printf("%d ",*(a+i));
system("pause");
return 0;
}
总结: 关于为什么要使用动态内存分配
①可以控制内存的大小
②多次利用这部分空间
③不占用栈区的内存 (在堆中申请)