文章目录
什么是动态内存管理
在C语言中,编写程序的时候不能确定内存变量应该定义为多大,程序员希望在程序运行的时候根据数据量的大小向系统动态获得内存空间。所谓动态内存管理,就是指在程序执行的过程中动态地申请和回收内存空间。动态内存管理不像变量和数组那样在程序编写时预先分配内存空间,而是根据程序的需要即时分配,而且分配的内存大小就是程序要求的大小。
C语言允许程序动态申请内存,用于存放一些数据,需要时随时开辟,不需要时随时释放。C语言中,内存的动态分配是通过系统提供的库函数来实现的,主要有 malloc,calloc,realloc和 free 函数,他们都存放在stdlib.h的头文件中。
malloc
void* malloc (size_t size);
malloc函数是向内存申请一块连续可用的内存空间,并返回指向该空间的指针。
- 如果开辟成功,则返回指向开辟好空间的指针,并不会初始化。
- 如果开辟失败,则返回NULL指针,因此在使用malloc函数开辟空间之后,要判断是否为 NULL指针
- 该函数的返回值是void*,因为该函数只管开辟一块动态空间,但不知道使用者会传什么类型的参数,所以具体的参数还是需要使用者来确定( void*类型的指针的好处是可以接受任意类型的指针,但在使用是需要强制转换成相应类型的指针)
free
c语言本身还自带了free函数,用于对动态内存的释放和回收。
void free (void* ptr);
free函数用来释放动态开辟的内存。
- 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的,所以不知道会发生什么事情,所以使用前要判断这块空间是否是动态内存开辟的空间
- 如果参数 ptr 是NULL指针,则函数什么事都不做,类似于空语句
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 ", *(p + i));
}
}
free(p);
p = NULL;//这里要将p置为空
return 0;
}
注:
如果最后没有将p所指向的空间用free函数释放其内存空间,可能会导致内存泄漏的问题,及每次创建一个新的空间,在新的一轮程序运行下去,又重新开辟空间,最后内存可能会被“吞掉”一部分。
calloc
void* calloc (size_t num, size_t size);
- 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0
- calloc与malloc的区别在于calloc会对申请的这段空间进行初始化为零,而malloc不会初始化
realloc
- realloc函数使动态内存管理更加灵活
- 在使用动态内存管理时,可以使用realloc函数对动态内存的空间大小进行调整,以达到创建符合使用者所需要的动态内存空间
void* realloc (void* ptr, size_t size);
- ptr 是要调整的内存地址,size 调整之后新大小
- 返回值为调整之后的内存起始位置。
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。
- 在对动态内存空间进行调整时会有两种情况:
1.原本的空间足够放得下重新分配好的空间
函数会在原本创建好的空间后面进行追加相应的空间。
2.原本的空间不能放下重新分配好的空间
函数会将原本的数据进行保存,并重新在内存中寻找另外一块足够大的空间,这样函数就会返回一个新的地址。
使用动态内存一般存在的问题
1.未对指向创建动态内存空间的指针进行判断
int main()
{
int *p = (int *)malloc(10*sizeof(int));
*p = 5;//如果p的值是NULL,就会有问题
free(p);
p = NULL;
return 0;
}
2.越界访问
int main()
{
int i = 0;
int *p = (int *)malloc(5*sizeof(int));
if(NULL == p)
{
return 0;
}
for(i=0; i<=10; i++)
{
*(p+i) = i;//当i是6的时候越界访问
}
free(p);
p = NULL;
return 0;
}
3.可能对非动态内存开辟的空间进行free释放
int main()
{
int p = 56;
int* b = &p;
free(b);
b = NULL;
return 0
}
对非动态内存开辟的空间进行free释放的结果未定义,要看内存的实际情况了。
4.对动态内存的部分进行释放
int main()
{
int *p = (int *)malloc(10*sizeof(int));
p++;//此时指向这块动态内存空间的指针发生改变
free(p);
p = NULL;
return 0;
}
这样可能会造成内存泄漏。
5.对动态内存进行多次释放
int main()
{
int *p = (int *)malloc(10*sizeof(int));
if(p == NULL)
{
return 0;
}
free(p);
free(p);
p = NULL;
return 0;
}
如果释放2次,程序就会挂掉,最好释放之后把p赋值为NULL,每次使用的时候再来判断下。
6.未对申请的动态内存空间进行free释放
int main()
{
int *p = (int *)malloc(10*sizeof(int));
if(p == NULL)
{
return 0;
}
return 0;
}
这样会导致内存泄漏。最后内存会被“吞掉”一部分。
希望这篇c语言动态内存能够给与大家一定的帮助,感谢你能够看到这里,希望下次还能再见。