本篇文章为动态内存函数的使用详解,希望对你的动态内存函数学习有所帮助。
对于初学者来说,最先接触到的内存使用便是以下场景:
//
int val = 3;//为变量val在栈区上申请一块空间存储数据
char str[] = "abc";//为数组str在栈区上申请一块空间存储数据
这样的空间开辟方式,在后续操作中,是无法改变以上数据所占空间大小的,并且对于数组来说,开辟空间是必须指明数组长度的。而在我们实际生活中又确实会出现一组数据量会随时变化的数据组。这时我们就需要使用动态内存函数来为数组,变量来开辟空间。
(函数声明在头文件stdlib.h
中)
malloc
是C语言提供的一个开辟动态内存的函数。
void* malloc (size_t size);
这个函数向内存申请一块在堆区上连续可用的空间,并返回指向该空间的指针。
void*
指针,具体使用时只需要对返回的指针进行强制类型转换即可。malloc
并未对size
是0的情况进行规定,具体情况看编译器。同时,C语言提供另外一个函数free
,专门用于释放和回收动态内存。
void free (void* ptr);
free
函数接收一个指向一块开辟好的动态内存空间,释放并回收这块J空间。
ptr
指向的空间不是动态开辟的这个行为并没有做出规定。ptr
是NULL指针,函数不会进行任何操作。int main()
{
int n = 10;
int* array = (int*)malloc(sizeof(int) * n);//开辟n个整型数据大小的连续空间
if (array == NULL)//检测是否申请失败
{
perror("malloc failed");//发出失败提示
exit(-1);//运行失败,结束程序
}
for (int i = 0; i < n; i++)
{
array[i] = i;//此时当作数组使用
}
free(array);//释放动态内存
array = NULL;//对该指针置空,防止非法访问内存空间(野指针)
return 0;
}
除malloc
外,C语言还提供了一个函数calloc
用于动态内存分配。
void* calloc (size_t num, size_t size);
num
个大小为size
的空间malloc
不同的是,calloc
会将申请到的空间的每个字节初始化为0int main()
{
int n = 10;
int* array = (int*)calloc(n, sizeof(int));//申请n个整型大小的内存空间
if (array == NULL)//检测是否申请失败
{
perror("calloc failed");//发出失败提示
exit(-1);//运行失败,结束程序
}
for (int i = 0; i < n; i++)
{
printf("%d ", array[i]);//此时打印,是已初始化的数据,全零
}
printf("\n");
free(array);
array = NULL;
return 0;
}
(代码运行截图)
仅有以上的函数要实现真正的动态地使用一块内存空间还是不够的。以上函数功能仅仅是申请和释放一块动态内存,而我们还需要一块改变动态内存大小的函数,这个函数就是realloc
。
void* realloc (void* ptr, size_t size);
ptr
指向需要调整的内存空间的地址。
size
是调整之后的大小。
void*
的指针。
realloc
在调整内存空间大小时存在两种情况:
realloc
函数会在堆的其他位置上找一块总够大的空间,将原有数据拷贝进去,并且会自行释放原来占用的空间,最后返回的地址是一个新的地址。
int main()
{
int n = 10;
int* array = (int*)calloc(n, sizeof(int));//申请n个整型大小的内存空间
if (array == NULL)//检测是否申请失败
{
perror("calloc failed");//发出失败提示
exit(-1);//运行失败,结束程序
}
//危险的操作
//array = (int*)realloc(array, 12);//由于申请失败时不会自行释放原空间,而此代码将原先指向原空间的指针置空,无法再找回原空间并释放(内存泄露)
//安全的操作
int* ptr = NULL;
ptr = (int*)realloc(array, 12);
if (ptr != NULL)//检测是否扩容失败
{
array = ptr;//扩容成功再赋值回来
}
//...
free(array);
array = NULL;
return 0;
}
由于动态内存函数地使用涉及指针,内存空间的知识,对于C语言这块内容还不是很熟悉的人来说使用难度较大。这里总结几个比较常出现的错误,希望对你的使用有所帮助。
void test1()
{
int* ptr = (int*)malloc(sizeof(int));
//如果malloc申请空间失败那么此时ptr就是NULL
*ptr = 9;//此时就会发生
}
void test2()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
exit(-1);
for (int i = 0; i <= 10; i++)
ptr[i] = i;//当i==10的3时候发生越界
free(ptr);//值得注意的是,动态内存空间的越界并不会直接检测出来,而是会在free的时候检测出来并报错
//此时会报出类似堆区异常访问,或者在访问正常数据后的空间之类的错误
}
(代码运行截图)
free
释放非动态开辟的内存空间void test3()
{
int a[10] = { 0 };
int* p = &a;
//...
free(p);//报错
}
void test4()
{
int* ptr = (int*)malloc(sizeof(int));
if (ptr == NULL)
exit(-1);
//...
free(p);
free(p);//重复释放
}
void test5()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
exit(-1);
//...
p++;
//...
free(p);//只释放了一部分内存
}
void test6()
{
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL)
exit(-1);
//...
//内存泄露
}
非常感谢各位读者能读完这篇文章,如果你觉得做的还不错的话,可以点赞收藏分享,让更多的朋友知道,当然,如果你觉得有什么问题的话也欢迎在评论区留言或私信告诉我哦!下期再会!