目录
1.malloc 和 free
1.1 malloc函数
malloc函数的头文件为stdlib.h
函数原型:
void* malloc(size_t size) //开辟内存块,size为要几个字节大小;
示例:
int main()
{
//向内存申请10个整形空间;
int* p=(int*)malloc(10*sizeof(int)); //返回值为申请的空间的地址,需要强制类型转换;
if(p==NULL)
{
printf("%s\n",strerror(errno)); //会报出对应的错误信息,即为什么内存开辟失败;
}
else
{
//正常使用空间;
int i=0;
for(i=0;i<10;i++)
{
*(p+i)=i;
}
for(i=0;i<10;i++)
{
printf("%d\n",*(p+i));
}
}
//当申请的空间不再使用的时候
//应该还给操作系统
return 0;
}
1.2 free函数
free函数是专门用来做动态内存的回收和释放的;
函数原型为:
void free(void* ptr);
free函数用于释放动态内存开辟的内存。
·如果参数ptr指向的空间不是动态开辟的,free的行为就是未定义的;
·如果ptr是NULL指针,则函数什么事都不做;
示例:
int main()
{
//向内存申请10个整形空间;
int* p=(int*)malloc(10*sizeof(int)); //返回值为申请的空间的地址,需要强制类型转换;
if(p==NULL)
{
printf("%s\n",strerror(errno)); //会报出对应的错误信息,即为什么内存开辟失败;
}
else
{
//正常使用空间;
int i=0;
for(i=0;i<10;i++)
{
*(p+i)=i;
}
for(i=0;i<10;i++)
{
printf("%d\n",*(p+i));
}
}
//当申请的空间不再使用的时候
//应该还给操作系统
free(p); //当程序结束时,动态内存开辟的空间也会还回去,free就是主动还回去
p=NULL; //free过后p并没有发生变化,还是指向开辟的那块空间,为了防止那块空间被再次利用,就将p赋值为空指针;
//malloc 和 free 函数要成对使用;
return 0;
}
2. calloc函数
开辟一个数组在内存中,元素初始化为0;
函数原型:
void* calloc(size_t num,size_t size)
示例:
int main()
{
// malloc(10*sizeof(int));
int* p=(int*)calloc(10,sizeof(int));//几个元素,每个元素多少个字节;
//开辟失败时,同样返回空指针
if(p==NULL)
{
printf("%s\n",strerror(errno));
}
else
{
int i=0;
for(i=0;i<10;i++)
{
printf("%d",*(p+i)); //打印结果都是0;
}
}
//释放空间
free(p);
}
malloc和calloc函数的区别在于,malloc效率高,但不初始化;calloc效率低,但初始化;
3. realloc函数
函数原型:
void* realloc(void* ptr,size_t size);
realloc函数的出现,让动态内存管理更加灵活
realloc可以对动态开辟内存的大小进行调整
ptr是要调整的内存地址,size是调整之后的新大小,返回值为调整好之后的内存起始地址,这个函数在调整原内存空间的基础上,还会将原来内存中的数据移动到新的空间。
示例:
int main()
{
int* p=(int*)malloc(20);
if(p==NULL)
{
printf("%s",strerror(errno));
}
else
{
int i=0;
for(i=0;i<5;i++)
{
*(p+i)=i;
}
}
//此时在使用malloc开辟的20个字节的空间;
//假设这里,20个字节不能满足我们的需求
//希望有40个字节空间
//此时可以使用realloc来调整内存;
int* ptr=(int*)realloc(p,40);
if(ptr!=NULL)
{
ps=ptr;
int i=0;
for(i=0;i<10;i++)
{
printf("%d ",*(ps+i));
}
}
free(ps);
ps=NULL;
return 0;
}
3.1realloc函数使用的注意事项:
1.如果p指向空间之后有足够的内存空间可以追加,则直接追加,后返回p;
2.如果p指向空间之后没有足够的内存空间可以追加,则realloc会重新找一个新的内存区域开辟一块满足需求的空间,并把原来内存中的数据拷贝过来,释放原来的内存空间,最后返回新开辟的内存空间地址;
3.得用一个新的变量来接受realloc的返回值
4. 动态内存开辟的常见错误
4.1 对NULL进行解引用操作
示例:
int* p=(int*)malloc(40);
//这里是有可能会开辟失败的,这个时候p就是空指针,下面就是对空指针进行解引用;
int i=0;
for(i=0;i<10;i++)
{
*(p+i)=i;
}
4.2 对动态内存开辟的越界访问
示例:
int *p=(int*)malloc(5*sizeof(int));
if(p==NULL)
{
return 0;
}
else
{
int i=0;
for(i=0;i<10;i++) //造成越界访问了,5个元素放了10个元素;
{
*(p+i)=i;
}
}
free(p);
p=NULL;
4.3 对非动态内存开辟空间使用free函数
示例:
int main()
{
int a=10;
int* p=&a;
*p=20;
free(p);
p=NULL;
}
4.4 使用free释放动态开辟内存的一部分
示例:
int main()
{
int *p=(int*)malloc(40);
if(p=NULL)
{
return 0;
}
int i=0;
for(i=0;i<10;i++)
{
*p++=i;
}
free(p);
p=NULL; //错误原因就是p指向的变成后面的空间了,++使得p指向地址以及发生改变;
}
4.5 对同一块动态开辟内存进行多次释放
int main()
{
int* p=(int*)malloc(40);
if(p=NULL)
{
return 0;
}
free(p); //用完后将p置为空指针,可以防止多次释放;
//·····
free(p);
return 0;
}
4.6 对动态开辟内存的忘记释放
//内存泄漏
int main()
{
while(1)
{
malloc(1);
}
}