🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
目录
🐰动态内存管理
其实我们创建数组的时候,系统为我们就是开辟了一段连续的空间(这个空间一般是在栈区开辟的),现在我们可以自己开辟一段空间。与动态开辟相关的函数: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,所以我们开辟好空间的话,需要去判断一下
1. #include<stdio.h> 2. #include<stdlib.h> 3. #include<errno.h> 4. #include<string.h> 5. int main() 6. { 7. int *p=(int *)malloc(20);//开辟了20个字节的空间 8. if(p==NULL) 9. { 10. printf("%s\n",strerror(errno));//打印开辟失败的原因 11. } 12. free(p); 13. p=NULL; 14. return 0; 15. }
malloc开辟空间,不初始化,里面存放的随机值
1. #include<stdio.h> 2. #include<stdlib.h> 3. int main() 4. { 5. int *p=(int *)malloc(20);//开辟了20个字节的空间 6. for(int i=0;i<5;i++) 7. { 8. printf("%d ",*(p+i)); 9. } 10. //使用 11. for(int i=0;i<5;i++) 12. { 13. *(p+i)=i+1; 14. } 15. for(int i=0;i<5;i++) 16. { 17. printf("%d ",*(p+i)); 18. } 19. free(p); 20. p=NULL; 21. return 0; 22. }
🐰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
1. #include<stdio.h> 2. #include<stdlib.h> 3. int main() 4. { 5. 6. int *p=(int *)calloc(20,sizeof(int));//开辟了20个int类型的空间 7. for(int i=0;i<20;i++) 8. { 9. printf("%d ",*(p+i)); 10. } 11. free(p); 12. p=NULL; 13. return 0; 14. }
🐰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的使用:
1. #include<stdio.h> 2. #include<stdlib.h> 3. #include<string.h> 4. #include<errno.h> 5. int main() 6. { 7. int *p=(int *)malloc(20);//开辟了20个int类型的空间 8. if(p==NULL) 9. { 10. printf("%s\n",strerror(errno)); 11. } 12. for(int i=0;i<5;i++) 13. { 14. printf("%d ",*(p+i)); 15. } 16. int* pc=(int*)realloc(p,sizeof(p)*2);//在原空间进行扩展 17. if(pc!=NULL) 18. { 19. p=pc;//把空间首地址还是赋给p 20. for(int i=0;i<10;i++) 21. { 22. printf("%d ",*(p+i)); 23. } 24. } 25. else 26. { 27. printf("realloc:%s\n",strerror(errno));//如果开辟失败,打印原因 28. } 29. free(p); 30. p=NULL; 31. return 0; 32. }
🐰free
free用于释放动态开辟的空间,引用头文件#include<stdlib.h>
free的原型:
void free (void* ptr);
void* ptr:动态开辟空间的首地址
注意:释放的空间一定是动态开辟的(就是在堆上开辟的),不然free是不起作用的。
free的使用:
1. #include<stdio.h> 2. #include<stdlib.h> 3. int main() 4. { 5. int* p=(int *)malloc(20);//开辟了20个字节的空间 6. free(p);//将20个字节的空间还给了系统 7. p=NULL;//如果不把p置为空指针,那么p就是野指针 8. return 0; 9. }
🐰动态开辟常见的错误
可能开辟空间失败,然后再去解引用会发生错误,所以malloc的返回值要去判断和越界访问。
1. #include<stdio.h> 2. #include<stdlib.h> 3. #include<string.h> 4. #include<errno.h> 5. int main() 6. { 7. int* p=(int*)malloc(20); 8. //可能开辟空间失败,然后再去解引用会发生错误,所以malloc的返回值要去判断 9. //所以我们需要判断 10. if(p==NULL) 11. { 12. printf("%s",strerror(errno));//打印发生的错误 13. return; 14. } 15. for(int i=0;i<5;i++) 16. { 17. p[i]=i; 18. } 19. 20. //越界访问 21. for(int i=0;i<10;i++)//只开辟了5个int类型的空间,却访问了10个int类型的空间 22. { 23. p[i]=i; 24. } 25. 26. free(p); 27. p=NULL; 28. return 0; 29. }
对非动态开辟的空间进行释放
1. #include<stdio.h> 2. #include<stdlib.h> 3. int main() 4. { 5. int arr[10]={1,2,3}; 6. int *p=arr; 7. free(p);//对非动态开辟的空间进行释放 8. return 0; 9. }
释放一部分动态开辟的空间
1. #include<stdio.h> 2. #include<stdlib.h> 3. int main() 4. { 5. int* p=(int*)malloc(40); 6. for(int i=0;i<10;i++) 7. { 8. p[i]=i; 9. } 10. p++;//p指向的就不是动态开辟空间的首地址 11. free(p);//使用free释放一块动态开辟内存的一部分,不是从开辟空间的首地址开始释放的 12. p=NULL; 13. return 0; 14. }
对一块空间多次释放
1. #include<stdio.h> 2. #include<stdlib.h> 3. int main() 4. { 5. int* p=(int*)malloc(40); 6. free(p); 7. //p=NULL;//如果释放了指针之后,再次释放是不会出错的,因为指针为空时,free不会做出任何反应 8. free(p);//重复释放 9. p=NULL; 10. return 0; 11. }
不能对空指针进行解引用操作
1. #include<stdio.h> 2. #include<string.h> 3. #include<stdlib.h> 4. void GetMemory(char* str) 5. { 6. str=(char *)malloc(20); 7. //str是p的临时拷贝,malloc动态开辟的空间,将首地址给了str,p仍然是空指针 8. } 9. int main() 10. { 11. char* p=NULL; 12. GetMemory(p); 13. strcpy(p,"hello world");//这里对空指针进行了解引用操作 14. printf("%s",p); 15. return 0; 16. }
野指针问题
1. #include<stdio.h> 2. #include<string.h> 3. #include<stdlib.h> 4. char* GetMemory(void) 5. { 6. char str[]="hello world"; 7. //返回栈区空间的问题 8. //GetMemory函数内部创建的数组str,str是临时创建,虽然返回了str数组的首地址,但是离开GetMemory函数之后,str内存会归还给系统,p的值虽然还是str数组的首地址,但是str空间已经归还给系统,str再去访问就是非法访问了。(栈区开辟的空间,离开作用域,栈区开辟的空间会被销毁) 9. return str; 10. } 11. int main() 12. { 13. char* p=NULL; 14. p=GetMemory(); 15. printf("%s",p); 16. return 0; 17. }
注:一定要记住
栈区:局部变量,函数形参
堆区:动态管理的空间(malloc,realloc,calloc,free)
静态区:静态变量,全局变量
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸