引言:随着大一期末的到来,想必许多学生都学到内存的动态管理这一部分了,看望这篇博客后,希望能解除你心中对这一章节的疑惑。
(・∀・(・∀・(・∀・*)
1.malloc详解
malloc的头文件是#include <sdtlib.h>,malloc - C++ Reference (cplusplus.com)
我们可以点进看看的malloc的详细内容
可以看到malloc返回值是void*类型,也就是说明在使用时我们还需要根据需要开辟空间的类型,强制类型转换成自己所要的类型。例如我们要开辟40个字节的空间,代码如下。
#include <stdlib.h>
int main()
{int* pa =(int *) malloc(10 * sizeof(int));return 0;
}
用数组的来写,如下
同样也可以实现空间的开辟,这里我们就来谈谈相同点与不同点。
#include <stdio.h>
int main()
{int pa[10];return 0;
}
相同点:
- 向内存申请一块空间
- 在程序结束时释放
不同点:
- 申请的内存位置不同,malloc在堆区,数组在栈区。
- 头文件不同,malloc头文件是<stdlib.h>,数组头文件是<stdio.h>
- 空间动态性,malloc所申请的空间是可变的,动态的可以通过使用realloc(下面会再讲解realloc的用法)来改变大小,数组所申请的空间是不可变的,定义完后就固定了。
- 数组定义时可以初始化空间内容,malloc申请空间时不能初始化内容,且其空间里的内容是随机值。
- malloc申请空间可能失败,数组不会。
如何理解这些不同点以及如何配套使用malloc我们看下面这一段代码
#include <stdlib.h>
int main()
{int* pa =(int *)malloc(10 * sizeof(int));if (pa == NULL){perror("malloc:");return 1;}int i = 0;for (i = 0; i < 10; i++){*(pa+i) = i;printf("%d ", *(pa+i));}free(pa);pa = NULL;return 0;
}
我们可以看到,用malloc申请完空间后,我们接着写了一段代码判断pa是否为NULL
我们接上不同点5,malloc申请空间可能会失败。所以我们要分类讨论malloc申请空间的情况
1.失败返回NULL(空指针)。
2.成功返回申请到空间的首地址。
至于perror是一种打印申请空间失败原因的库函数,我们可写可不写,为了可读性最好加上,接着如果失败我们return 1结束程序。因为以及申请失败了,下面的代码是针对成功的情况,如果不结束程序,代码就会出错。
for循环将0到9输入到这片空间中,并打印到屏幕中,
最后使用完了这块空间,我们free释放掉(free是编译器里的库函数,用来释放某一块空间的),还回去。释放完后free函数并不会将pa置为NULL,为了防止野指针的出现,我们需要手动设为NULL.
2.calloc详解
calloc和malloc很类似也是申请一块空间,我们接着看。
calloc的头文件是#include <sdtlib.h>calloc - C++ Reference (cplusplus.com)
我们可以点进看看的calloc的详细内容
同样我们可以看到calloc的返回值是void*,但calloc函数比malloc多了一个参数。我们具体分析
具体了解calloc。我们比较calloc与malloc
相同点:
1.都是向堆区申请一块空间。
2.都是动态的,可变的。
3.成功返回这块空间的首地址,失败返回NULL。
4.函数返回值都是void*。
不同点:
1.申请的空间成功时可以初始化为0,而malloc不可以。
至于不同点,我们看代码
#include <stdlib.h>
int main()
{int* pa =(int *)calloc(10 , sizeof(int));if (pa == NULL){perror("calloc:");return 1;}int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(pa+i));}free(pa);pa = NULL;return 0;
}
我们没有给calloc申请的空间赋值,我们看结果是
申请空间后初始化为0。
3.realloc详解
realloc的头文件是#include <sdtlib.h>realloc - C++ Reference (cplusplus.com)
我们可以点进看看的calloc的详细内容
看功能,realloc是来调整malloc/calooc申请的空间。与数组的不同就体现在这。
具体分析realloc的两个参数:
具体我们看代码操作:
#include <stdlib.h>
int main()
{int* pa = (int*)malloc(5 * sizeof(int));if (pa == NULL){perror("mallco:");return -1;}for (int i = 0; i < 5; i++){*(pa + i) = i;//pa需要+i指向下一个位置。printf("%d ", *(pa + i));}int* pb = (int*)realloc(pa, 10 * sizeof(int));if (pb == NULL){pb = pa;free(pb);pb = NULL;perror("realloc:");return 1;}elsepa = pb;for (int i = 5; i < 10; i++){*(pa + i) = i;//pa需要+i指向下一个位置。printf("%d ", *(pa + i));}free(pa);pa = NULL;return 0;
}
代码上半部分用malloc申请一块空间后,我们觉得20字节大小不够,我们就使用realloc函数增大空间至40个字节大小。同样申请完后我们要判断申请是否成功。
这里realloc比较复杂。我们一一述说:
1.失败返回NULL。
2.成功有分为两种情况
- 在申请时太大占用了其它已经占用空间时realloc会在内存的堆区重新找一个满足条件的空间,同时把旧的数据copy到新的空间,接着释放旧空间,同时返回新空间的起始地址。
- 在申请时空间够用时,返回起始地址。
所以如果pb==NULL时申请失败,我们需要把之前malloc申请的空间释放掉。并置为NULL。
总结:malloc,calloc,realloc三者都是void*类型函数,接收返回值时都要强制类型转换。在堆上申请的空间要即使释放,并置为空指针。每次申请完后要判断申请是否成功等等。
以上希望能够帮到你,让你对动态内存管理有跟深的理解。