本文主要介绍C语言中动态内存管理的相关知识
引入:所谓动态分配,就是需要的时候再分配,这是相对于静态分配而言的,静态分配就是一次分配完毕,不管你用多少。而动态分配则是按需分配。
- 第一点,也就是最简单的 你需要多少,你申请多少,不会造成浪费。
- 第二点,静态分配大多数都是在栈上分配的,栈的大小是有一定限制的,当你使用的超过栈的大小的时候,就需要到堆上去申请,当然堆也有大小限制,但一般说来堆比栈大很多很多
动态内存函数的介绍
malloc
void* malloc (size_t size);
这个函数的功能是向内存申请一块连续可用的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
例如:
int main() {
int size = 4;
int* p = (int*)malloc(size * sizeof(int));
for (int i = 0; i < size; i++) {
p[i] = i + 1;
printf("%d ", p[i]);
}
system("pause");
return 0;
}

从运行结果可以看出,我们用malloc函数开辟了一块内存大小为4 * 4个byte大小的空间,并初始化了4个int类型的值,分别为:1、2、3、4,但是这个函数存在一个问题,对于动态内存开辟的空间,我们还需要引入一个函数进行空间释放(free),并且将开辟空间的那块位置置为NULL。
free
void free (void* ptr);
free函数用来释放动态开辟的内存
- 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
- 如果参数 ptr 是NULL指针,则函数什么事都不做
例如:
int main() {
int size = 4;
int* p = (int*)malloc(size * sizeof(int));
//判断p是否为空
if (p != NULL) {
for (int i = 0; i < size; i++) {
p[i] = i + 1;
printf(" %d\n", p[i]);
}
}
//释放p
free(p);
p = NULL;
system("pause");
return 0;
}
calloc
void* calloc (size_t num, size_t size);
calloc也是用于动态内存分配
- 函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0;
例如:
int main() {
int size = 4;
int* p = (int*)calloc(size, sizeof(int));
//判断p是否为空
if (p != NULL) {
for (int i = 0; i < size; i++) {
printf(" %d\n", p[i]);
}
}
//释放p
free(p);
p = NULL;
system("pause");
return 0;
}

如果要求对申请的动态内存空间初始化为0,那么我们就可以考虑用calloc。
realloc
void* realloc (void* ptr, size_t size);
该函数的功能是重新分配内存块,更改ptr指向的内存块的大小。
- ptr 是动态内存申请空间的地址;
- size是调整之后的新大小;
- 返回值为调整之后内存的起始位置;
- 原有空间之后有足够大的空间,则直接向后申请;
- 原有空间之后没有足够大的空间,则重新申请一块空间,并且原空间的内容copy过来;
int main() {
int size = 4;
int* p = (int*)malloc(size * sizeof(int));
//判断p是否为空
if (p != NULL) {
for (int i = 0; i < size; i++) {
p[i] = i;
}
}
size = 10;
int* p1 = (int*)realloc(p, size * sizeof(int));
for (int i = 4; i < size; i++) {
p1[i] = i;
}
for (int i = 0; i < size; i++) {
printf("%d\n", p1[i]);
}
//释放p
free(p1);
p1 = NULL;
system("pause");
return 0;
}
