动态内存的开辟方法(动态内存的开辟)
🐶博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️🔥专栏系列:线性代数 ,C初学者入门训练 ,题解C ,C的使用文章 ,「初学」C++
🔥座右铭:“不要等到什么都没有了 ,才下定决心去做 ”
🚀🚀🚀大家觉不错的话 ,就恳求大家点点关注 ,点点小爱心 ,指点指点🚀🚀🚀
目录
🐰动态内存管理
🐰malloc
🐰calloc
🐰realloc
🐰free
🐰动态开辟常见的错误
🐰动态内存管理
其实我们创建数组的时候 ,系统为我们就是开辟了一段连续的空间(这个空间一般是在栈区开辟的) ,现在我们可以自己开辟一段空间 。与动态开辟相关的函数:malloc free calloc realloc
注意:数组离开作用域时 ,系统会自动释放这段空间 ,如果我们自己动态开辟的空间,离开作用域时 ,系统是不会帮我们释放这段空间的 ,如果要求释放这段动态开辟的空间,我们就需要使用free函数去释放 。
🐰malloc
malloc用于动态开辟内存 ,引用的头文件是#include<stdlib.h>
malloc的原型:
void* malloc (size_t size);size_t size:开辟的字节数
注意:返回的类型是void*类型 ,如果想要使用这段空间 ,就必须强制性转化为自己想使用的类型 ,例如:int* p=(int*)malloc(20);这就是开辟了20个字节 ,然后把20个字节空间的首地址赋值给了p 。
malloc的使用:
malloc开辟成功会返回开辟好的空间的首地址 , malloc如果申请内存失败会返回空指针NULL ,所以我们开辟好空间的话 ,需要去判断一下
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> int main() { int *p=(int *)malloc(20);//开辟了20个字节的空间 if(p==NULL) { printf("%s\n",strerror(errno));//打印开辟失败的原因 } free(p); p=NULL; return 0; }malloc开辟空间 ,不初始化 ,里面存放的随机值
#include<stdio.h> #include<stdlib.h> int main() { int *p=(int *)malloc(20);//开辟了20个字节的空间 for(int i=0;i<5;i++) { printf("%d ",*(p+i)); } //使用 for(int i=0;i<5;i++) { *(p+i)=i+1; } for(int i=0;i<5;i++) { printf("%d ",*(p+i)); } free(p); p=NULL; return 0; }🐰calloc
calloc用于动态开辟内存 ,区别于malloc的是 ,calloc会初始化开辟的空间,将开辟的空间全部初始化为0 ,引用的头文件是#include<stdlib.h>
calloc的原型:
void* calloc (size_t num, size_t size);size_t num:开辟的个数
size_t size:开辟的类型的大小
注意:返回的类型是void*类型 ,如果想要使用这段空间,就必须强制性转化为自己想使用的类型 ,例如:int* p=(int*)calloc(20,sizeof(int));这就是开辟了20个整形的空间 ,然后把20个整形空间的首地址赋值给了p 。
calloc的使用:
calloc开辟空间 ,初始化 ,里面存放的0
#include<stdio.h> #include<stdlib.h> int main() { int *p=(int *)calloc(20,sizeof(int));//开辟了20个int类型的空间 for(int i=0;i<20;i++) { printf("%d ",*(p+i)); } free(p); p=NULL; return 0; }🐰realloc
realloc用于原空间不足继续开辟更大的空间 ,引用头文件为#include<stdlib.h>
realloc的原型:
void* realloc (void* ptr, size_t size);void* ptr:原空间的首地址
size_t size:开辟新空间的大小
注意:realloc开辟空间会遇到两种情况
1.如果原空间后面空间充足
在原空间后面继续开辟空间(返回的地址与原来的地址相同)
2.如果原空间后面空间不足
(1)realloc会找更大的空间
(2)将原来的数据拷贝到新空间
(3)释放原来的旧的空间
(4)返回新空间的地址(返回的地址与原来的地址不同)
realloc的使用:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> int main() { int *p=(int *)malloc(20);//开辟了20个int类型的空间 if(p==NULL) { printf("%s\n",strerror(errno)); } for(int i=0;i<5;i++) { printf("%d ",*(p+i)); } int* pc=(int*)realloc(p,sizeof(p)*2);//在原空间进行扩展 if(pc!=NULL) { p=pc;//把空间首地址还是赋给p for(int i=0;i<10;i++) { printf("%d ",*(p+i)); } } else { printf("realloc:%s\n",strerror(errno));//如果开辟失败 ,打印原因 } free(p); p=NULL; return 0; }🐰free
free用于释放动态开辟的空间 ,引用头文件#include<stdlib.h>
free的原型:
void free (void* ptr);void* ptr:动态开辟空间的首地址
注意:释放的空间一定是动态开辟的(就是在堆上开辟的) ,不然free是不起作用的 。
free的使用:
#include<stdio.h> #include<stdlib.h> int main() { int* p=(int *)malloc(20);//开辟了20个字节的空间 free(p);//将20个字节的空间还给了系统 p=NULL;//如果不把p置为空指针 ,那么p就是野指针 return 0; }🐰动态开辟常见的错误
可能开辟空间失败 ,然后再去解引用会发生错误 ,所以malloc的返回值要去判断和越界访问 。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> int main() { int* p=(int*)malloc(20); //可能开辟空间失败 ,然后再去解引用会发生错误,所以malloc的返回值要去判断 //所以我们需要判断 if(p==NULL) { printf("%s",strerror(errno));//打印发生的错误 return; } for(int i=0;i<5;i++) { p[i]=i; } //越界访问 for(int i=0;i<10;i++)//只开辟了5个int类型的空间 ,却访问了10个int类型的空间 { p[i]=i; } free(p); p=NULL; return 0; }对非动态开辟的空间进行释放
#include<stdio.h> #include<stdlib.h> int main() { int arr[10]={1,2,3}; int *p=arr; free(p);//对非动态开辟的空间进行释放 return 0; }释放一部分动态开辟的空间
#include<stdio.h> #include<stdlib.h> int main() { int* p=(int*)malloc(40); for(int i=0;i<10;i++) { p[i]=i; } p++;//p指向的就不是动态开辟空间的首地址 free(p);//使用free释放一块动态开辟内存的一部分,不是从开辟空间的首地址开始释放的 p=NULL; return 0; }对一块空间多次释放
#include<stdio.h> #include<stdlib.h> int main() { int* p=(int*)malloc(40); free(p); //p=NULL;//如果释放了指针之后 ,再次释放是不会出错的,因为指针为空时 ,free不会做出任何反应 free(p);//重复释放 p=NULL; return 0; }不能对空指针进行解引用操作
#include<stdio.h> #include<string.h> #include<stdlib.h> void GetMemory(char* str) { str=(char *)malloc(20); //str是p的临时拷贝 ,malloc动态开辟的空间 ,将首地址给了str ,p仍然是空指针 } int main() { char* p=NULL; GetMemory(p); strcpy(p,"hello world");//这里对空指针进行了解引用操作 printf("%s",p); return 0; }野指针问题
#include<stdio.h> #include<string.h> #include<stdlib.h> char* GetMemory(void) { char str[]="hello world"; //返回栈区空间的问题 //GetMemory函数内部创建的数组str ,str是临时创建 ,虽然返回了str数组的首地址 ,但是离开GetMemory函数之后 ,str内存会归还给系统 ,p的值虽然还是str数组的首地址 ,但是str空间已经归还给系统 ,str再去访问就是非法访问了 。(栈区开辟的空间 ,离开作用域,栈区开辟的空间会被销毁) return str; } int main() { char* p=NULL; p=GetMemory(); printf("%s",p); return 0; }注:一定要记住
栈区:局部变量 ,函数形参
堆区:动态管理的空间(malloc,realloc,calloc,free)
静态区:静态变量 ,全局变量
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨 ,共同学习 ,共同进步 。谢谢大家! 🌸🌸🌸
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!