推荐一个 C 语言手册网站:cplusplus.com
头文件: #include<stdlib.h>
#include<malloc.h>
内存的三个区域
如下图所示
为什么要使用动态内存开辟
目前我们所知道的向内存申请空间的方法有两种:
(1)创建一个变量(如 int a; 就向内存申请了四个字节的空间大小)。
(2)创建一个数组。
但比如创建一个 50 元素的数组(int a[50])就一定会发生内存浪费或者不够的现象,为了使用多大内存就申请多大内存的空间,我们就可以使用动态内存开辟(在堆区)。
动态内存分配的函数
free
函数 free 专门是用来做动态内存的释放和回收的,即当动态申请的空间不再使用时,应还给操作系统。
说简单点就是你申请了就要还回去。
虽然不用 free 函数,在程序执行结束后,系统会自动将你申请的内存释放,但如果你申请过一次,还剩空间不想用了,主程序又没执行完,那你应该先释放掉这些内存,让给别人申请使用。
使用方法:
比如之前你定义了一个指针 p,在结尾用
free(p);p=NULL;
Q:为什么还要把 p 赋值成空指针呢?我不是已经释放掉了吗?
A:p 虽然还给操作系统,但依然有能力找到你刚才申请的这块空间,所以再给 p 赋一个空指针。
malloc
翻阅手册我们可以看到 malloc 函数的使用为
void* malloc (size_t size);
直接上案例
int* p = (int*) malloc (10* sizeof(int));
(1)上面的代码就是向内存申请了 10 个 int 字节的空间,现在的编译器中 int 一般为 4 字节大小,10 个 int 就是 40 字节大小,也可以直接打 40。
(2)因为 malloc 的返回类型为 void* ,会报警告,需要强制类型转换。
(3)当没有足够的空间时,malloc 会返回一个空指针(NULL)。
打印错误原因的一种方式
这个算是题外话了。
当我们想知道我们程序什么出错时(比如内存申请失败)。可以用下面的函数。
#include<string.h>#include<errno.h>#include<stdio.h>printf("%s\n",strerror(errno));
stdio.h 对应 printf , errno.h 对应 errno , string.h 对应 strerror
由 malloc 和 free 的实例演示
#include<stdio.h>#include<malloc.h>#include<stdlib.h>#include<string.h>#include<errno.h> int main(){ int* p = (int*)malloc(10 * sizeof(int)); if (p == NULL) printf("%s\n", strerror(errno)); else { int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i; } for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); } } free(p); p = NULL; return 0;}
注释:(1)引入头文件不可少。
(2)这里我申请了 40 个字节空间大小(10*sizeof(int) ),并用一个 int *类型的指针 p 指向了这个空间的首地址。
(3)if 语句判断申请内存成不成功,还记得我们上面说的吗?当没有足够的空间时,malloc 会返回一个空指针(NULL)。
(4)else 语句里是将 0-9 这些数字放入这些内存当中,i=0 时 p=0,i=1 时,(p+1)=1。以此类推
(5)打印出放入到这块空间的数字。
(6)释放掉这块空间,将 p 赋为空指针。
打印出的结果如下
注:如果使用比较新的 vs(比如 2022 版)使用 strerror 时要在程序最上面加上
#define _CRT_SECURE_NO_WARNINGS
realloc
realloc 的作用是可以调整动态开辟内存空间的大小。
假设本来使用 malloc 申请 20 字节空间,不够了,我希望有 40 字节空间。
那么就可以使用以下代码
int* p = (int*)malloc(20);int* p2 = realloc(p, 40);
注意事项:
Q:为什么用一个新的 p2 不再用 p?
(1)如果 p 指向的空间之后有足够的内存空间可以追加,则直接追加,后返回 p。
(2)如果 p 指向的空间之后没有足够的空间可以追加,则 ralloc 函数会重新找一个新的内存南区域开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟的内存空间地址。
Q:如果我还是想用原来的 p 不用 p2 怎么办?
(3)要用一个新变量接受 realloc 函数的返回值(上面就用的是 p2)
看代码如下
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<errno.h> int main(){ int* p = (int*)malloc(20); if (p == NULL) { printf("%s\n", strerror(errno)); } else { int i = 0; for (i = 0; i < 5; i++) { *(p + i) = i; } } int* p2 = realloc(p, 40); if (p2 != NULL) { p = p2; //把p2的首地址又给了p,做到了衔接 int i = 0; for (i = 5; i < 10; i++) { *(p + i) = i; } for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); } } free(p); p = NULL; return 0;}