动态内存管理及其函数讲解
什么是动态内存管理?
C语言提供了动态内存管理的功能,使得程序可以在运行时动态地分配和释放内存。动态内存管理是指在程序运行时动态地分配和释放内存,以满足程序的内存需求。与静态内存分配不同的是,动态内存分配可以在程序运行时动态地分配内存,从而提高程序的灵活性和效率。
为什么要有动态内存管理?
我们已经掌握的内存开辟空间的方式有:
1 int val = 20;//在栈空间上开辟四个字节
2 char arr[10] = {0};//在栈空间上开辟10个字节的连续空间
但是上述的开辟空间的方式有两个特点:
• 空间开辟的大小是固定的。
• 数组在申明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整
所以C语言提供了动态内存管理的功能,使得程序可以在运行时动态地分配和释放内存。动态内存管理是指在程序运行时动态地分配和释放内存,以满足程序的内存需求。
与静态内存分配不同的是,动态内存分配可以在程序运行时动态地分配内存,从而提高程序的灵活性和效率。
静态内存分配是在程序编译时分配内存,程序运行时不能改变内存大小,而动态内存分配可以在程序运行时动态地分配和释放内存,从而提高程序的灵活性和效率。动态内存管理的主要应用场景包括:
- 程序需要在运行时动态地创建数据结构或对象,而这些数据结构或对象的大小不能在编译时确定。
- 程序需要在运行时动态地分配和释放内存,以满足程序的内存需求。
- 程序需要在运行时动态地调整内存大小,以适应程序的变化。
动态内存管理可以帮助程序更好地利用内存,并提高程序的效率和灵活性。但是,需要注意的是,动态内存管理需要程序员自己负责管理内存,如果处理不当可能会导致内存泄漏或内存溢出等问题。因此,在使用动态内存管理时,程序员需要仔细地分配和释放内存,以确保程序的正确性和稳定性。
四个动态内存管理函数及使用示例
C语言提供了四个函数来实现动态内存管理,它们是malloc、calloc、realloc和free函数。
malloc函数
malloc函数用于动态分配内存,函数原型为:
void *malloc(size_t size);
其中,size_t是一个无符号整数类型,表示要分配的内存大小,单位是字节。函数返回一个指向新分配的内存的指针,如果分配失败则返回NULL。
以下是malloc函数的使用示例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
p = (int *)malloc(sizeof(int));
if (p == NULL) {//判断是否空间开辟失败
printf("malloc failed\n");
return 1;
}
*p = 10;
printf("*p = %d\n", *p);
//释放空间
free(p);
p=NULL;
return 0;
}
输出:
*p=10
在这个示例中,程序首先调用malloc函数分配了一个int类型的内存空间,大小为sizeof(int)即4个字节。然后程序将指针p指向这个内存空间,并将*p的值设置为10。最后程序调用free函数释放了这个内存空间。
calloc函数
与
malloc的不同就是:calloc可以指定需要分配的元素个数,且将分配的内存全部初始化为0
函数原型为:
void *calloc(size_t nmemb, size_t size);
其中,nmemb表示要分配的元素个数,size表示每个元素的大小,单位是字节。如果分配成功函数返回一个指向新分配的内存的指针,如果分配失败则返回NULL。
以下是calloc函数的使用示例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
p = (int *)calloc(1, sizeof(int));
if (p == NULL) {//判断是否空间开辟失败
printf("calloc failed\n");
return 1;
}
//使用空间
printf("*p = %d\n", *p);
//释放空间
free(p);
return 0;
}
输出:
*p=0
在这个示例中,程序首先调用calloc函数分配了一个int类型的内存空间,并将这个空间初始化为0。然后程序将指针p指向这个内存空间,并输出*p的值。最后程序调用free函数释放了这个内存空间。
realloc函数
有时当我们发现过去申请的空间过小或者过大,那为了合理的使用内存,我们就会需要对内存进行调整.
realloc函数就用于重新分配已经分配的内存空间的大小,函数原型为:
void *realloc(void *ptr, size_t size);
其中,ptr是一个指向已经分配的内存空间的指针,size表示要重新分配的内存大小,单位是字节。函数返回一个指向新分配的内存的指针,如果分配失败则返回NULL。
以下是realloc函数的使用示例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
p = (int *)malloc(sizeof(int));
if (p == NULL) {//判断是否空间分配失败
printf("malloc failed\n");
return 1;
}
//使用空间
*p = 10;
printf("*p = %d\n", *p);
//重新分配空间
p = (int *)realloc(p, 2 * sizeof(int));
if (p == NULL) {
printf("realloc failed\n");
return 1;
}
*(p + 1) = 20;
printf("*(p + 1) = %d\n", *(p + 1));
free(p);
return 0;
}
在这个示例中,程序首先调用malloc函数分配了一个int类型的内存空间,大小为sizeof(int)个字节。然后程序将指针p指向这个内存空间,并通过*p解引用将这个内存空间的值设置为10。接着程序调用realloc函数将p指向的内存空间重新分配为2个int类型的内存空间,大小为2 * sizeof(int)个字节。最后程序将*(p + 1)的值设置为20,并输出*(p + 1)的值。程序最后调用free函数释放了这个内存空间。
输出:
free函数
C语音提供了另外一个函数
free,专门是用来做动态内存的释放和回收的,函数原型为:
void free(void *ptr);
其中,ptr是一个指向已经分配的内存空间的指针。函数不返回任何值。
以下是free函数的使用示例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
int size=10
p = (int *)malloc(size*sizeof(int));
if (p == NULL) {//判断是否空间开辟失败
printf("malloc failed\n");
return 1;
}
//使用空间
int i=0;
for(i=0;i<size;i++)
{
*p[i]=i+1;
}
for(i=0;i++;i<size)
printf("%d \n", *p[i]);
//释放空间
free(p);
p=NULL;
return 0;
}
输出:
1 2 3 4 5 6 7 8 9 10
这个示例中,上面用我们学过的的函数malloc分配并且使用了一块空间,最后我们调用free释放空间,注意的是,当我们释放空间完毕之后,要让p指向空指针(NULL),以防它变成野指针。
注意事项
使用动态内存管理时需要注意以下几点:
1. 内存泄漏
动态内存管理的一个常见问题是内存泄漏。如果程序分配了内存空间但没有正确释放,就会导致内存泄漏。内存泄漏会导致程序的内存使用量不断增加,最终可能导致程序崩溃或者系统资源耗尽。
为了避免内存泄漏,程序应该在不需要使用动态分配的内存空间时及时释放它们。在释放内存空间时,应该确保释放的是已经分配的内存空间,并且每个分配的内存空间只被释放一次。
2. 内存越界
另一个常见问题是内存越界。内存越界指的是访问已经分配的内存空间之外的内存地址。内存越界可能会导致程序出现未定义的行为,例如程序崩溃或者产生不正确的结果。
为了避免内存越界,程序应该确保访问的内存地址在已经分配的内存空间之内。可以通过检查指针是否为NULL以及使用内存边界检查工具等方式来避免内存越界。
3. 多次释放同一个内存空间
如果程序多次释放同一个内存空间,就会导致程序出现未定义的行为。为了避免这种情况,程序应该确保每个分配的内存空间只被释放一次。
4. 分配的内存空间大小
程序应该确保分配的内存空间大小足够存储要存储的数据。如果分配的内存空间大小不足,就会导致程序出现未定义的行为。可以使用sizeof运算符来计算要分配的内存空间的大小。
5. 避免悬空指针
悬空指针是指指向已经释放的内存空间的指针。如果程序使用悬空指针,就会导致程序出现未定义的行为。为了避免悬空指针,程序应该在释放内存空间后将指针设置为NULL。
总之,在使用动态内存管理时,程序应该确保对已经分配的内存空间进行正确的释放,避免内存泄漏和内存越界等问题。同时,程序还应该注意避免多次释放同一个内存空间、分配的内存空间大小足够存储要存储的数据以及避免悬空指针等问题。
本文介绍了动态内存管理的概念、其在C语言中的重要性,以及malloc、calloc、realloc和free等四个主要函数的使用示例和注意事项,如内存泄漏、内存越界和正确释放内存等。
1788





