如何在程序运行的时候动态给程序分配内存?
1 动态内存分配的意义
在C语言中,一切操作都是基于内存的。变量和数组名都是内存别名。但是它们的内存分配却是在编译期间由编译器决定的。定义数组的长度的时候,必须指定长度,这是在编译期间就要确定的。
但是,需求总是有的。比如当我们无法在编译期间确定到底需要多大的内存块,此时就无法定义数组的大小(或者定义的数组大小不够)。此时就需要在运行的时候根据实际的情况(比如根据输入的数据的大小),来动态的申请内存空间,然后让数组(指针)指向这块新申请的内存。
这就是动态内存分配的意义。
1.1 C语言中如何动态申请内存空间
- malloc和free用于动态申请内存和释放内存
它们的操作对象是堆空间内存(内存池)如下图:
注意:malloc和free必须是成对出现的,这样可以避免内存泄露。关于内存泄露,后面还有文章进行学习。
1.2 malloc和free的用法
malloc和free的函数定义如下:
- malloc所分配的是一块连续的内存,参数size是所分配的内存字节数。
- malloc的返回值是void* ,具体使用的时候需要做强制类型转换
- free用于将申请的动态内存归还给系统
关于malloc和free,有以下几点需要注意:
- malloc和free是库函数,不是系统调用
- malloc实际分配的内存,可能比请求的多。这是因为CPU访问内存是按照一种内存对齐的方式来访问的。所以一般申请的内存都是对齐内存的整数倍
- 当请求的动态内存无法满足的时候,malloc返回NULL
- 当free的参数为NULL的时候,函数直接返回。
- malloc申请的动态内存中的数据是随机值,不会被初始化为0
至于malloc和free的用法,在前面的文章已经学会使用了,这里不再给出例子,直接看前面的文章吧:二维数组与二维指针
以及在后面的文章中,会给出一个内存泄露检测模块,来巩固malloc与free的使用。自行去后面的文章查看。
1.3 calloc与realloc
函数原型为;
- calloc的参数:num个类型长度为size的内存空间大小。也就是申请的内存的类型信息(大小和类型)
- calloc会将申请的内存空间初始化为0
- realloc用于修改原先已经分配的内存块大小
- 当realloc的第一个参数pointer为NULL时,realloc相当于malloc
- realloc一般是重新找一块新的内存块进行分配,而不是在原有的内存的结尾增加。
1.31 calloc和realloc的代码案例分析
- 代码:38-2.c
#include <stdio.h>
#include <malloc.h>
#define SIZE 5
int main() {
int i = 0;
int* pI = (int*)malloc(SIZE * sizeof(int));
short* pS = (short*)calloc(SIZE, sizeof(short));
for (i = 0; i < SIZE; i++) {
printf("pI[%d] = %d, pS[%d] = %d\n", i, pI[i], i, pS[i]);
}
printf("Before: pI = %p\n", pI);
pI = (int*)realloc(pI, 2 * SIZE * sizeof(int));
printf("After: pI = %p\n", pI);
for (i = 0; i < 10; i++) {
printf("pI[%d] = %d\n", i, pI[i]);
}
printf("\n");
pS = (short*)realloc(pS, 2 * SIZE * sizeof(short));
for (i = 0; i < 10; i++) {
printf("pS[%d] = %d\n", i, pS[i]);
}
free(pI);
free(pS);
return 0;
}
- 上述代码运行结果:
Linux下gcc 4.4.5编译:
Windows下 VS 2017运行如下:
- 分析:
- 首先代码很很简单。无非就是使用了malloc,calloc和realloc三个函数。其中我们可以看到,在Linux下的gcc4.4.5编译器将malloc申请的内存的内容也都是0,并不是随机值。但是这只是巧合或者gcc编译器优化了而已。在windows下的vs2017编译器就很明显,malloc申请的内存的内容都是随机值
- 根据两个结果,可知道,使用realloc后,内存的地址变了,也就是说realloc是重新选择一块内存进行分配,并不是在原有的内存空间结尾增加
- 也可以看到不管是在linux下还是在windows下,calloc申请的内存的内容都被初始化为0了
- 从windows下的编译运行结果来看,使用realloc对之前使用calloc申请的内存重新分配内存后,原有的内容不变,但是新添加的内容并不是0,而是随机值,这个也要注意。
所以最终总结为:只有calloc胡为分配的内存的内容初始化为0,malloc和realloc都是随机值。
2 总结
- 动态内存分配使得程序在需要的时候有机会获得更大的内存
- malloc单纯的从系统中申请固定字节大小的内存。内存中的内容是随机值
- calloc 申请的内存的内容被初始化为0
- realloc用于重置内存的大小。但是是重新在堆空间中选一块内存而不是在原有的内存后面增加。并且,重置的内存中,原有的内容不变,但是如果内存变大,多余的部分的内存的内容是随机值。
- 注意上述三者函数的参数与返回类型
- 学会使用上述三者函数