【C语言提升】深入了解动态内存管理

目录

一、静态分配和动态分配 

二、内存管理函数

1、malloc 申请堆区空间

2、calloc 申请堆区空间

3、free回收堆区空间权限

4、memset内存设置函数

5、realloc内存增减函数

三、内存泄漏(了解)


一、静态分配和动态分配 

1、静态分配

在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式。如int a [10]

必须事先知道所需空间的大小。

分配在栈区或全局变量区,一般以数组的形式。

2、动态分配

在程序运行过程中,根据需要大小自由分配所需空间。

按需分配。
分配在堆区,一般使用特定的函数进行分配。

二、内存管理函数

        C语言提供了一些内存管理函数,用以按需动态分配与回收内存空间。

1、malloc 申请堆区空间

        在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。函数原型返回void*指针,使用时必须做相应的强制类型转换,分配的内存空间内容不确定,一般使用memset初始化

头文件:#include

用法:void *malloc(size_t size);//size表示申请的空间字节数,void *(万能指针)

函数的返回值成功返回空间起始地址

                      失败:NULL

特点:malloc申请的堆区空间 需要使用memset对原有内容清0,即不自动清0

2、calloc 申请堆区空间

头文件:#include

用法:void *calloc(size_t nmemb, size_t size);

nmemb:内存的块数

size:每一块的字节数

函数返回值成功返回堆区空间起始地址

           失败:为NULL

calloc会对申请的空间 自动清0

3、free回收堆区空间权限

头文件:#include

用法:void free(void *ptr);

ptr为需要释放的堆区空间的起始地址

若未用free回收空间,进程结束会全部申请的空间会被回收。

实际应用举例:申请n个元素的动态数组

malloc(n*sizeof(int));

calloc(n, sizeof(int));

综合案例分析: 

【C语言提升】深入了解动态内存管理_第1张图片

4、memset内存设置函数

头文件:#include

用法:void *memset(void *s, int c, size_t n);

s是空间的起始地址

c是空间中每个字节填充的值

n是空间的字节宽度

案例:动态数组

#include 
#include
#include
void test()
{	
	int n = 0;
	printf("请输入元素个数:");
	scanf("%d", &n);
	int *p = NULL;
	p=(int *)malloc(n*sizeof(int));
	if (p = NULL)
	{
		return;
	}
	//将申请的堆区空间清0
	memset(p, 0, n * sizeof(int));
	int i=0;
	for ( i = 0; i < n; i++)
	{
		scanf("%d", p + i);
	}
	for ( i = 0; i < n; i++)
	{
		printf("%d ", p[i]);//*(p+i);
	}
	free(p);
	return;
}
int main(int argc, char const* argv[])
{
		test();
		return 0;
}

5、realloc内存增减函数

        在原先s指向的内存基础上重新申请内存,新的内存的大小为size个字节
如果原先内存后面有足够大的空间,就追加,如果后边的内存不够用,则relloc函数会在堆区
找一个size个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址

头文件:#include

用法:void *realloc(void *ptr, size_t size);

ptr为旧空间起始地址
size为旧空间大小加新空间大小
返回值为增减空间后整个空间的起始地址

注:必须使用指针变量获取realloc返回值,p=realloc(p,20+20);

#include 
#include
void test04()
{
int n = 0;
printf("输入int元素的个数:");
scanf("%d", &n);
//根据元素的个数申请空间
int *p = NULL;
p = (int *)calloc(n, sizeof(int));
if (p == NULL)
{
    return;
}
//获取键盘输入
int i = 0;
for (i = 0; i < n; i++)
{
    scanf("%d", p + i);
}
//遍历数组元素
for (i = 0; i < n; i++)
{
    printf("%d ", p[i]); //*(p+i)
}
printf("\n");
printf("输入新增的元素个数:");
int new_n = 0;
scanf("%d", &new_n);
//追加空间
p = (int *)realloc(p, (n + new_n) * sizeof(int));
printf("输入%d个新增元素:", new_n);
//输入新增的元素
for (i = n; i < n + new_n; i++)
{
    scanf("%d", p + i);
}
//遍历数组元素
for (i = 0; i < n + new_n; i++)
{
    printf("%d ", p[i]); //*(p+i)
}
printf("\n");
free(p);
}

三、内存泄漏(了解)

        申请的内存,首地址丢了,无法再使用,也没法释放,这块内存就被泄露了。

案例1:

char *p;

p=(char *)malloc(100);

p="hello world";//p 指向别的地方了

//此后,找不到申请的 100 个字节,动态申请的 100 个字节就被泄露了。

案例2:

void test()
{
    char *p;
    p=(char *)malloc(100);
    //函数结束该内存未释放
}
int main()
{
    test();
    test();//调用一次,内存就泄漏一次。
}

 案例2解决方案:调用结束时用free函数释放内存或者将指针变量返回

free函数释放:

void test()
{
    char *p;
    p=(char *)malloc(100);
    //函数结束该内存未释放
    ...
    free(p);
}
int main()
{
    test();
}

 指针变量返回:

void test()
{
    char *p;
    p=(char *)malloc(100);
    //函数结束该内存未释放
    ...
    return p;
}
int main()
{
    char *q;
    q=test();
    /调用一次,内存就泄漏一次。
}

你可能感兴趣的:(C语言,c语言,开发语言,vscode,学习)