个人主页:勇敢的小牛儿
推荐专栏:C语言知识点
⚠️座右铭⚠️:敢于尝试才有机会
今日鸡汤:出色一点 从能力到容貌
目录
思维导图:
一,malloc :
1.1:malloc函数简介:
1.2:malloc函数的使用:
代码:
二,calloc函数
2.1calloc函数简介:
2.2calloc函数的使用:
2.3,calloc函数与malloc函数的不同点:
三,realloc函数
3.1:realloc函数简介:
3.2:realloc函数的使用:
4.使用动态内存时的典型错误
4.1:对NULL进行解引用操作
4.2:越界访问
4.3:对非动态内存进行释放
4.4:对一个动态内存进行多次释放
4.5释放部分动态内存
4.6忘记对一个动态内存进行释放
4.7解决方案
结语:
1.作用:malloc函数是C语言内的一个开辟动态内存的函数,
使用这个函数可以向系统申请一段连续可用的空间,
并返回这块空间的起始地址。假如申请失败就返回一个NULL!!!
2.原型:void* malloc (size_t size);
3.善后:当你使用完这个函数申请的空间以后,要使用free()函数对申请到的空间进行释放。
第一步:使用malloc函数申请空间
1.包含头文件stdlib.h
2.调用函数malloc,调用时要记得需要强制类型转换一下。因为malloc的返回类型是void*。
3.判断是否为空指针,如果是空指针的话就表示空间申请不成功。因此使用strerror以及errno函数来打印错误提示信息。
4.使用就像数组那样使用。
5.使用完了以后就对申请到的空间进行释放,并将指针置为空指针。(防止出现野指针)
#include
#include
#include//strerror函数的头文件
#include//errno的头文件
int main() {
//申请空间
int* p = (int*)malloc(20);//申请的空间的单位是字节,这里表示申请20个字节。
//判断是否申请成功
if (p == NULL) {
printf("%s\n", strerror(errno));
return;
}
//使用
int i = 0;
for (i = 0;i < 5;i++) {
*(p+i) = i;
}
for (i = 0;i < 5;i++) {
printf("%d ", *(p + i));
}
//善后
free(p);
p = NULL;
return 0;
}
1.作用:向内存空间申请num个大小为sizeof大小的空间,并初始化为0。
申请成功就返回申请到的空间的地址,申请失败就返回NULL。
2.函数原型:void* calloc (size_t num, size_t size);
3.善后:使用完这块申请到的空间以后要对这块空间用free()进行释放,
并将管理这块空间的指针置为空指针。
第一步:使用malloc函数申请空间
1.包含头文件stdlib.h
2.调用函数calloc,调用时要记得需要强制类型转换一下。因为calloc函数的返回类型是void*。
3.判断是否为空指针,如果是空指针的话就表示空间申请不成功。因此使用strerror以及errno函数来打印错误提示信息。
4.使用就像数组那样使用。
5.使用完了以后就对申请到的空间进行释放,并将指针置为空指针。(防止出现野指针)
代码:
#include
#include
#include
#include
int main() {
//申请空间
int* p = (int*)calloc(20,sizeof(int));//20表示申请空间的个数,
//sizeof(int)表示申请到的空间的大小。
//判断是否申请成功
if (p == NULL) {
printf("%s\n", strerror(errno));//打印错误信息
return;//结束
}
//使用
int i = 0;
for (i = 0;i < 5;i++) {
*(p + i) = i;
}
for (i = 0;i < 5;i++) {
printf("%d ", *(p + i));
}
//善后
free(p);
p = NULL;
return 0;
}
1.函数的参数不同,malloc函数只有一个参数但是calloc函数有两个参数。
void* malloc ( size_t size ); void* calloc ( size_t num , size_t size );2.calloc函数有将申请到的空间初始化为0的功能,而malloc函数没有这个功能。
1. 作用:当malloc函数或者calloc函数申请的空间或者数组的空间
不够大或太大时就可以用realloc函数对空间的大小进行调整。
2.函数原型:void* realloc (void* ptr, size_t size);
1.包含头文件stdlib.h
2.调用realloc函数,因为函数的返回类型是void*型,
所以我们需要强制类型转换一下来确定类型。
3.判断一下返回类型是否为空指针,非空才能对这个指针进行使用。
是空指针那就打印一下错误信息(strerror(errno))。
4.realloc(NULL,20)==malloc(20)
代码:
#include
#include
#include
#include
int main() {
//申请空间
int* p = (int*)calloc(20, sizeof(int));//20表示申请空间的个数,
//sizeof(int)表示申请到的空间的大小。
//判断是否申请成功
if (p == NULL) {
printf("%s\n", strerror(errno));//打印错误信息
return;//结束
}
//使用
int i = 0;
for (i = 0;i < 5;i++) {
*(p + i) = i;
}
int* ptr = (int*)realloc(p, 40);//将p指向的20个字节的空间改为40个字节的空间
if (ptr != NULL) {//验货
p = ptr;
for (i = 5;i < 10;i++) {
*(p + i) = i;
}
for (i = 0;i < 10;i++) {
printf("%d ", p[i]);
}
}
else {
printf("realloc:%s\n", strerror(errno));
}
//善后
free(p);
p = NULL;
return 0;
}
3.2.1:realloc函数在成功使用时的两种情况:
3.2.1.1:返回旧地址:
当内存空间有足够的空间可以申请时,并且其它地址不会与我要申请的空间冲突时:返回旧地址
3.2.1.2:返回新地址:
当内存空间足够,但是其它被申请的空间与我要申请的空间冲突时:返回新地址
不能对空指针进行解引用操作
int main() {
int* p = (int*)malloc(4);//返回值可能是NULL
*p = 20;
printf("%d\n", *p);//对NULL解引用操作会报错
return 0;
}
int main() {
int* p = (int*)malloc(4);//返回值可能是NULL
if (p != NULL) {//判断不为NULL才执行赋值操作,除去第一种错误的可能
*p = 20;
*(p + 1) = 30;//越界访问
printf("%d %d\n", *p,*(p+1));
}
free(p);
p = NULL;
return 0;
}
对一个非堆区的空间进行释放是不行的
int main() {
int a[20] = { 0 };//a只是一个数组,存放在栈区
int* p = a;
free(p);//释放p指向的内存空间即释放a数组的空间
return 0;
}
因为 在第一次对p进行释放以后,p已经变成一个野指针,再次释放肯定会出现问题的。
int main() {
int* p = (int*)malloc(20);
if (p != NULL) {
int i = 0;
for (i = 0;i < 5;i++) {
*(p + i) = i;
}
for (i = 0;i < 5;i++) {
printf("%d ", *(p + i));
}
free(p);//第一次释放
}
free(p);//第二次释放
p = NULL;
return 0;
}
对动态内存进行释放的时候要提供动态内存的起始地址,否则就无法进行释放。
int main() {
int* p = (int*)malloc(40);
if (p == NULL) {
printf("%s\n", strerror(errno));
return;
}
int i = 0;
for (i = 0;i < 5;i++) {
*p++ = i;//p++的现象导致p指向的空间发生了变化
}
free(p);//对部分动态内存进行释放
p = NULL;
return 0;
}
忘记对一段动态内存空间进行释放时会发生内存泄漏。虽然发生这个错误以后你的代码还是能够跑起来,但是会导致你的电脑变得卡顿。
int main() {
int* p = (int*)malloc(20);
if (p == NULL) {
printf("%s\n", strerror(errno));
return;
}
int i = 0;
for (i = 0;i < 5;i++) {
*(p+i) = i;
}
for (i = 0;i < 5;i++) {
printf("%d ", *(p + i));
}
//没有free(p)释放内存
return 0;
}
1.使用开辟空间得到的地址时先判断一下是否为空指针再使用(避免对NULL进行使用)
2.使用时不要改变p指针的指向.(避免free时出现错误)
3.使用完成以后要对动态内存空间进行释放以及让释放以后的指针指向NULL.(避免出现内存泄漏和野指针)
4.不要对动态内存进行多次释放。也不要对不是动态内存的空间进行释放。(避免free一段已释放的空间以及对不是动态内存的空间进行释放)
代码:
int main() {
//申请空间
int* p = (int*)malloc(20);
//判断是否为NULL
if (p == NULL) {
printf("%s\n", strerror(errno));
return;
}
//使用(p不是NULL时才使用)
int i = 0;
for (i = 0;i < 5;i++) {
*(p + i) = i;//不改变p原来的指向
}
for (i = 0;i < 5;i++) {
printf("%d ", *(p + i));
}
//善后
free(p);//释放,避免内存泄漏
p = NULL;//置为空指针,避免野指针的出现
return 0;
}
小牛儿今天的分享就到这里了。