一、静态分配和动态分配
- 静态分配
- 在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式,比如
int[10];
- 必须事先知道所需空间的大小。
- 分配在栈区或者全局变量区,一般以数组的形式。
- 按计划分配。
- 在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式,比如
- 动态分配
- 在程序运行过程中,根据需要大小自由分配所需空间。
- 按需分配。
- 分配在堆区,一般使用特定的函数进行分配。
- 需要包含头文件
include<stdlib.h>
二、动态分配函数
- malloc函数:
void *malloc(unsigned int size);
功能说明:在堆区中分配一块长度为size的连续区域,用来存放类型说明符指定的类型。函数原型返回void*指针,使用时必须做相应的强制类型转换,分配的空间内容不确定,一般用memset初始化。
注意:
- 在调用malloc后,一定要通过返回值判断是否申请内存成功,失败返回NULL。
- 如果多次使用malloc申请内存,第一次和第二次申请的内存不一定是连续的。
int* p = (int*)malloc(n * 4);
- free函数:
void free(void* ptr);
释放ptr所指向的内存,ptr指向的内存必须是malloc、calloc、relloc动态申请的内存。
注意:
- free某段内存后,原本指向该内存的指针还是没有变,但是内存已经不能够使用了。
- 一块动态申请的内存只能free一次。
free(p);
- calloc函数:
void* calloc(size_t nmemb, size_t size);
size_t,其实就是无符号整型,它是头文件中用typedef定义出来的。
在内存的堆区中,申请nmumb块,每块的大小为size个字节的连续区域。
注意:
- malloc和calloc都是用来申请内存的。区别在于malloc函数申请的内存内容是随机的,而calloc函数申请的内存内容为0。
- 同样必须判断是否申请成功,如果失败返回NULL。
int* p = (int*)calloc(n, 4);
- realloc函数:
void* realloc(void *s,unsigned int newsize);
在原先s指向的内存基础上重新申请内存,新的内容大小为newsize个字节,这样一来,就会出现三种情况:
- (旧的内存大小<newsize)原先内存后面有足够大的空间,那么直接追加。
- (旧的内存大小<newsize)原先内存后面内存不够用,realloc函数回在堆区找一个newsize个字节大小的内存申请,再将原先内存的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址。
- (旧的内存大小>newsize)会释放原先内存后面的存储空间,只保留newsize个字节的空间,返回新申请的首地址。
p = (char*)realloc(p,50);
- 内存泄漏(非常严重的问题)
申请的内存,首地址丢了,找不到并且再也没办法使用了,也没法释放,就成为内存泄露。
模拟:
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
char* p;
p = (char*)malloc(100);//指向新分配的内存
p = "hello world";//又指向了其他内存
return 0;
}
最后,一开那100个字节的内存已经无法被找到了,也没有办法进行释放,这就是内存泄漏。