目录
7.1 概述
数据的长度是预先定义好的,在整个程序中固定不变,容量不能改变。但实际编程时往往会发生所需的内存空间取决于实际输入的数据,无法预先确定。
C语言提供了一些内存管理函数,可以按需动态的分配内存空间,也可把不再使用的内存空间回收再次利用。
7.2 静态分配、动态分配
1、静态分配
在程序编译或运行过程中,按事先规定的大小分配内存空间的分配方式:int a[10],
(1)必须事先知道所需空间的大小
(2)分配在栈区或全局变量区,一般以数组的形式
(3)按计划分配
2、动态分配
在程序运行过程中,根据需要的大小自由分配所需的空间,分配在堆区,一般使用特定的函数进行分配
7.3 动态分配函数
7.3.1 malloc函数
include<stdlib.h>
void* malloc(unsigned int size);
参数是无符号整形,返回值是void指针。
在内存的动态存储区(堆区)分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型,分配的内存空间内容不确定,一般使用memset初始化。
注意:
(1)函数原型返回void*指针,使用时必须做相应的强制类型转换
char* p;
p = (char*)malloc(20); //强制类型转换,将申请的内存空间转换为存储字符类型数据的内存空间。
(2)调用malloc后一定要判断一下申请内存是否成功,如果成功,返回值是分配空间的起始地址,如果失败,返回值是NULL。
(3)如果多次malloc申请的内存,第一次和第二次申请的内存并不一定是连续的。
例如:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p;
int i, n;
printf("请输入您要申请的int数组的元素个数\n");
scanf_s("%d", &n);
p = (int*)malloc(n*sizeof(int));
if (p == NULL)
{
printf("malloc error\n");
return 0;
}
for (i = 0; i < n; i++)
{
p[i] = i;
}
for (i = 0; i < n; i++)
{
printf("p[%d] = %d\n", i, p[i]);
}
free(p);
return 0;
}
请输入您要申请的int数组的元素个数
4
p[0] = 0
p[1] = 1
p[2] = 2
p[3] = 3
7.3.2 free函数
#include<stdlib.h>
void free(void *ptr)
free函数释放的是ptr指向的内存,而ptr指向的内存必须是malloc、calloc、relloc动态申请的内存。
注意:
(1)free后由于没有给p赋值,所以p还是指向原先动态申请的内存,但是内存已经不能再使用了,p变成野指针;
(2)同一块动态申请的内存不能多次free
7.7.3 calloc函数
#include<stdlib.h>
void calloc(size_t nmemb, size_t size);
有两个参数,size_t实际上是无符号整形,是在头文件中用typedef定义出来的,nmemb是申请的内存块数量,size是每块的字节大小,返回值是通用指针void*。
在内存的堆中,动态申请nmemb块,每块的大小都是size字节的连续区域。
注意:
(1)调用calloc后一定要判断一下申请内存是否成功,如果成功,返回值是分配空间的起始地址,如果失败,返回值是NULL。
(2)申请的总字节数是nmemb * size。
(3)malloc申请的内存,内存中存放的内容是随机不确定的;而calloc函数申请的内存中的内容是0。
(4)malloc多次申请的内存不一定连续,而calloc申请的多个内存块是连续的,它申请了nmemb * size个字节的连续内存空间。
使用方法类似于malloc,同样需要强制类型转换:p = (int*)calloc(1 ,n * sizeof(int));
7.3.4 realloc函数(重新申请内存)
(1)在malloc或calloc申请的内存后,紧挨着继续申请内存
(2)释放malloc或calloc申请的内存中的最后一部分
#include<stdlib.h>
void* realloc(void*s, unsigned int newsize);
在原先s指向的内存基础上重新申请内存,新内存大小为newsize字节,如果原先内存后面有足够大的空间则追加,如果后面内存不够用,就在堆区找一块newsize字节大小的内存申请,将原先内存上的内容拷贝过来,然后释放原来的内存,最后返回新内存的地址。
如果newsize比原先的内存小,则释放原先内存后面的存储空间,只保留前面的newsize字节。
返回值:新申请的内存的首地址
注意:malloc、calloc、realloc申请的内存从申请开始,直到free或者程序结束才释放。
7.4 内存泄漏
1、概念:申请的内存首地址丢了,找不到了,没办法使用了,也没办法释放了,这块内存就被泄露了。
例1:
int main()
{
char* p;
p = (char*)malloc(100);
p = "hello world";
return 0;
}
p不再指向申请的内存,而是指向了别的地方,也没有其他指针指向申请的内存,那么申请的那100个字节再也找不到了,动态申请的100个字节就被泄露了。
例2:
void fun()
{
char* p;
p = (char*)malloc(100);
}
int main()
{
fun();
fun();
return 0;
}
这时每次调用一个fun都会动态申请一个100字节的内存块,但没有释放,程序没有结束就会继续占用内存,这时就会内存泄漏。
解决方案1:谁申请谁释放
void fun()
{
char* p;
p = (char*)malloc(100);
free(p);
}
int main()
{
fun();
fun();
return 0;
}
解决方案2:申请后给别人,别人要释放
void fun()
{
char* p;
p = (char*)malloc(100);
free(p);
}
int main()
{
char* q;
q = fun();
free(q);
return 0;
}