目录
前言
C语言的特点之一是功能强大且灵活,但是我在学习C语言的过程中发现在写代码时,如果我像要在储存数据就要在开辟特定大小的内存存放数据,那么以功能强大且灵活的C语言有没有提供一种更加灵活的选择来分配内存呢?C语言提供了库函数供我们动态分配和释放内存。
一、动态内存分配是什么?
在C语言中大多数我们要使用内存是都是通过创建变量,数组等,但这种方式开辟内存的虽然方便但是开辟的空间是固定的即确定开辟多大的空间通常被称为(静态内存分配),要是在像在程序运行是在开辟更多的空间是无法做到的,但是C语言提供提供了库函数malloc,free,calloc,realloc来帮助我们动态分配和管理内存。的。
二、动态内存库函数介绍
1.malloc
函数名称 | malloc |
头文件 | #include <stdlib.h> |
函数格式 | void *malloc(size_t size); |
函数功能 | malloc会寻找没有被开辟的内存,大小是size大小个字节的内存空间,如果开辟成功内存,不初始化开辟的内存空间。 |
返回类型 | 如果函数开辟内存成功,返回类型为void的指针(一般将返回类型强制转换),这个指针指向开辟空间的首字节地址,如果malloc开辟空间失败返回空指针(NULL)。 |
使用如下(示例):
#include <stdio.h>
int main()
{
//代码1
int num = 0;
scanf("%d", &num);
int arr[num] = { 0 };
//代码2
int* ptr = NULL;
ptr = (int*)malloc(num * sizeof(int));
if (NULL != ptr)//判断ptr指针是否为空
{
int i = 0;
for (i = 0; i < num; i++)
{
*(ptr + i) = 0;
}
}
free(ptr);//释放ptr所指向的动态内存
ptr = NULL;//ptr所指向的空间以及被释放所以置为空指针
return 0;
}
2.calloc
函数名称 | calloc |
头文件 | #include <stdlib.h> |
函数格式 | void *calloc(size_t num, size_t size); |
函数功能 | malloc会寻找没有被开辟的内存,为num个大小为size字节的内存空间,该空间内的所有位都会初始化为0; |
返回类型 | 如果函数开辟内存成功,返回类型为void的指针(一般将返回类型强制转换),这个指针指向开辟空间的首字节地址,如果malloc开辟空间失败返回空指针(NULL) |
使用如下(示例):
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (NULL != p)
{
//使用空间
free(p);
p = NULL;
return 0;
}
}
3.realloc
函数名称 | realloc |
头文件 | #include <stdlib.h> |
函数格式 | void *realloc(void *mem_address, unsigned int newsize); |
函数功能 | 更改mem_address指向的内存大小,情况1:原有空间之后有足够的空间,再原有空间上的追加newsize个字节的大小的空间; 情况2:如果原有空间之后没有足够多的空间时,再内存上另找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址,会将原有空间的数据拷贝到新的内存空间,并且将free(mem_address)释放原有空间。 |
返回类型 | 情况1返回:mem_address; 情况2返回:类型为void的指针,指针指向新的内存空间的首地址; 开辟空间失败返回NULL; |
使用如下(示例):
#include <stdio.h>
int main()
{
int *ptr = (int*)malloc(100);
if(ptr != NULL)
{
//业务处理
}
else
{
exit(EXIT_FAILURE);
}
int*p = NULL;
p = realloc(ptr, 1000);
if(p != NULL)
{
ptr = p;
}
free(ptr);
ptr=NULL;
p=NULL;
return 0;
}
4.free
函数名称 | free |
头文件 | #include <stdlib.h> |
函数格式 | void free(void *ptr); |
函数功能 | 释放ptr所指向的空间,free会自动计算prt指向空间的大小,当实际参数与之前通过calloc函数、mal1oc函数或realloc函数返回的指针不 一致时,或者ptr指向的空间已经通过被free或realloc被释放时,则作未定义处理。 |
返回类型 | 无 |
三、动态内存分配常见问题内存泄漏
int main() {
int i;
scanf("%d", &i);
for (int j=1;j<=i;j++){
int* ret=(int*)malloc(i * sizeof(int));
if (ret == NULL){
return;
}
printf("%d开辟空间\n",j);
//free(ret);假设忘记释放空间
//ret = NULL;
}
return 0;
}
由于malloc,realloc,calloc都是在堆区开辟空间,堆区一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收(有的操作系统不会回收),一旦忘记释放不再使用的动态开辟的空间就会造成内存泄漏。
上述代码理论上可以循环多次,但是由于程序员在循环体内没有释放malloc开辟的空间造成了内存泄漏,就会卡死。
四、C/C++的内存开辟
C/C++程序内存分配的几个区域:
1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结 束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是 分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返 回地址等。 2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分 配方式类似于链表。
3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。