由于在函数栈内定义数组,寿命在函数结束时销毁,静态变量定义如果太多会导致文件太大,所以在这里我们引入堆。
堆:头文件名#include<stdlib.h>
malloc:堆上动态数组的申请和释放
//这里给大家介绍一个man手册,在终端中 man +你要查的函数名 可以查看该函数的用法
void* 万能指针:它能转化为任何数据类型的指针,也可以承接任何类型的指针。
malloc申请空间返回的指针都是void*型的指针,所以我们一般都会进行一次强制类型转换。
比如(int*)将它强转为int*型。
使用方式:int *p=(int *)malloc(sizeof(int));
但是注意,malloc函数申请空间并不一定会成功(堆肯占满了)
所以要对返回值进行判空
if(p==NULL)
{
return NULL;(函数中)/return 0;(main函数中)
}
堆申请空间会导致空间碎片化,因为空间是链式结构,当空间碎片化后,再想申请完整的大内存可能会失败。所以每次在堆上申请空间之后我们都要进行释放,不释放的话会造成内存泄漏
(因为申请空间后不释放,所以默认这块内存被占用,但由于函数结束后,申请的地址也会被销毁,所以最后这块内存就好永远被占用,称为内存泄漏。)
free(p);释放这块内存。
所以malloc和free要一起使用,同时,在释放内存之后一定要将p=NULL;进行置空,防止别人二次释放这个内存导致软件崩溃。
所以malloc但大致使用格式:
int*p=(int *)malloc(sizeof(int));
if(p=NULL)
{
return NULL;(函数中)/return 0;(main函数中)
}
free(p);
p=NULL;
calloc:向堆申请n个size大小的内存。
使用格式:calloc(n,size)
int*p=(int *)calloc(2,sizeof(int));
申请两个内存为4字节的数组p。
*p=10/p[0]=10;
*(p+1)=20/p[1]=20;
分别给两个赋值。
特点:这个函数会对内存进行初始化,初始化值为0。
//malloc(sizeof(int)*2)等价于calloc(2,sizeof(int)),区别在于malloc没有初始化。
realloc:1、在后面内存不够的情况下,重新申请一块内存,并把之前那块地址的值拷贝过来。
2、在后面内存足够的情况下,在原基础上扩容,初始地址不变。
使用格式:realloc(p,4*sizeof(int));表示在p重新开辟空间或扩展空间到16个字节,但同时注意,如果是重新开辟内存的话,要将p中存储的原先的内存地址存储起来,否则后续释放内存时找不到地址。
如果在扩容时,p=malloc(4);p1=realloc(p,8)
无论释放p还是释放p1,都会被全部释放。
用堆定义二维数组的两种方式:
1、指针数组
int **p=(int **)malloc(2*sizeof(int*));
for(int i=0;i<2;i++)
{
p[i]=(int *)malloc(sizeof(int)*3);
}
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
p[i][j]=i*3+j+1;
printf("%d",p[i][j]);
}
}
printf("\n");
for(int i=0;i<2;i++)
{
free(p[i]);
}
free(p);
p=NULL;
- 数组指针
int (*p)[3]=(int(*)[3])malloc(sizeof(int)*6);
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
p[i][j]=i*3+j+1;
scanf("%c",p[i][j]);
printf("%d",p[i][j]);
}
printf("\n");
}
free(p);
p=NULL;
用指针数组时,释放内存需要怎么存入,怎么释放。当使用数组指针时,因为本质上是一个指针,所以只需要释放一次就可以了。
main函数的参数
int main (int argc,char*argv[ ])
{}
作用:在刚启动函数的时候输入参数,可以传入参数,函数第一个输出一定是当前文件的文件名,之后的输出按文件内代码定义输出,作用:登录界面