目录
一、静态分配和动态分配
二、内存管理函数
1、malloc 申请堆区空间
2、calloc 申请堆区空间
3、free回收堆区空间权限
4、memset内存设置函数
5、realloc内存增减函数
三、内存泄漏(了解)
一、静态分配和动态分配
1、静态分配
在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式。如int a [10]
必须事先知道所需空间的大小。
分配在栈区或全局变量区,一般以数组的形式。
2、动态分配
在程序运行过程中,根据需要大小自由分配所需空间。
按需分配。
分配在堆区,一般使用特定的函数进行分配。
二、内存管理函数
C语言提供了一些内存管理函数,用以按需动态分配与回收内存空间。
1、malloc 申请堆区空间
在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。函数原型返回void*指针,使用时必须做相应的强制类型转换,分配的内存空间内容不确定,一般使用memset初始化。
头文件:#include<stdlib.h>
用法:void *malloc(size_t size);//size表示申请的空间字节数,void *(万能指针)
函数的返回值成功:返回空间起始地址
失败:NULL
特点:malloc申请的堆区空间 需要使用memset对原有内容清0,即不自动清0
2、calloc 申请堆区空间
头文件:#include<stdio.h>
用法:void *calloc(size_t nmemb, size_t size);
nmemb:内存的块数
size:每一块的字节数
函数返回值成功:返回堆区空间起始地址
失败:为NULL
calloc会对申请的空间 自动清0
3、free回收堆区空间权限
头文件:#include<stdlib.h>
用法:void free(void *ptr);
ptr为需要释放的堆区空间的起始地址
若未用free回收空间,进程结束会全部申请的空间都会被回收。
实际应用举例:申请n个元素的动态数组
malloc(n*sizeof(int));
calloc(n, sizeof(int));
综合案例分析:
4、memset内存设置函数
头文件:#include<string.h>
用法:void *memset(void *s, int c, size_t n);
s是空间的起始地址
c是空间中每个字节填充的值
n是空间的字节宽度
案例:动态数组
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
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<stdlib.h>
用法:void *realloc(void *ptr, size_t size);
ptr为旧空间起始地址
size为旧空间大小加新空间大小
返回值为增减空间后整个空间的起始地址注:必须使用指针变量获取realloc返回值,p=realloc(p,20+20);
#include <stdio.h>
#include<stdlib.h>
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();
/调用一次,内存就泄漏一次。
}