目录
动态内存的申请空间位置
malloc calloc realloc 申请空间
malloc
calloc
realloc
free 释放空间
常见的动态内存的错误
错误1
错误2
错误3
错误4
错误5
错误6
动态内存的申请空间位置
计算器内存空间分布主要分为栈区、堆区、静态区(当然还有其他取于)
主函数内声明的变量:默认情况下,函数内声明的非静态局部变量(如int a;)存储在栈区,而非静态区。只有显式使用static关键字的局部变量(如static int b;)才会存储在静态区。
动态内存空间申请出来的变量是在内存的堆区里。
动态内存空间具有灵活性和动态分配。
灵活性是因为可以随意控制想要的大小
#include <stdio.h> int main(){ int i=0; scanf("%d",&i); int a[i];//error return 0; }象征着代码就是没办法控制想要打开的大小的,而动态内存就可以做到这些事情。
malloc calloc realloc 申请空间
malloc
malloc 函数 ,是申请空间里最常见,也是最基础的函数
void* malloc (size_t size);- 参数
size为需要分配的字节数。 - 返回值是一个
void*类型的指针,指向分配的内存起始地址;若分配失败则返回NULL。当malloc 在申请空间太大时,或者电脑内存不够时才会申请空间失败。
以为malloc 是void* 的返回形式,所以我们在使用的时候都需要进行一个强制类型转换操作。
int* a=(int*)malloc(sizeof(int));//单个变量申请操作 if(a==NULL){ perror("malloc"); return 1; } //判断空间是否申请成功 int i=0; scanf("%d",&i); int* arr=(int*)malloc(sizeof(int)*i);//可控制数组长度的多个变量申请操作 if(arr==NULL){ perror("malloc"); return 1; } //判断空间是否申请成功calloc
void *calloc(size_t num, size_t size);- 参数:
num:需要分配的元素数量。size:每个元素的大小(字节数)。
- 返回值:
- 成功时返回指向分配内存的指针。
- 失败时返回
NULL。
int i=0; scanf("%d",&i); int* arr=(int*)calloc(i,sizeof(int));//可控制数组长度的多个变量申请操作 if(arr==NULL){ perror("malloc"); return 1; } //判断空间是否申请成功int i=0; scanf("%d",&i); int* arr=(int*)malloc(sizeof(int)*i);//可控制数组长度的多个变量申请操作 if(arr==NULL){ perror("malloc"); return 1; } //判断空间是否申请成功calloc 也是生成动态内存,但与 malloc 有点不一样
void* malloc (size_t size); void* calloc(size_t num,size_t size); int* p = (int*)malloc(i * sizeof(int)); int* p = (int*)calloc(i , sizeof(int));
两个功能是一样的
但malloc生成出来的值是随机值,calloc生成出来的值会经行一个初始化0的操作
性能:由于calloc会初始化内存,其性能可能略低于malloc,但安全性更高。
realloc
realloc 的功能就是当你申请的空间太小或者太大时的时候
realloc 进行对与内存大小的调整
void* realloc (void* ptr ,size_t size );- 参数:
ptr 是要调整的内存的地址
size 是调整后的新大小,单位字节
返回值:
- 成功时返回指向分配内存的指针。
- 失败时返回
NULL。
int* ptr =(int*)malloc(sizeof(int)); if(ptr==NULL){ perror("malloc"); return 1; } realloc(ptr,sizeof(int)*5); if(ptr==NULL){ perror("realloc"); return 1; } //这种写法会容易出现问题 /* 当realloc申请空间失败时,容易把之前的空间一起变成空指针NULL */正确做法
#include <stdlib.h> int main(){ int* arr1=(int*)malloc(sizeof(int)*5);//内存申请空间 if(arr1==NULL){ perror("malloc"); return 1; } for(int i=1;i<=5;i++) arr1[i]=i;//赋值 int* arr2=realloc(arr1,sizeof(int)*10);//设置arr2 扩充文件内存 if(arr1==NULL){ perror("realloc"); return 1; } arr1=arr2; for(int i=6;i<=10;i++) arr1[i]=i;//赋值 free(arr1);//释放空间 arr1=NULL;//防止野指针 return 0; }realloc在调整内存空间的时候会出现一下两种情况
情况1: ptr
| 20bit | 尚未 | 分配 | 位置 | 已 | 被 | 占 | 取 |
内存空间扩展充沛的情况:
当是情况1的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
情况2: ptr
| 20bit | 已 | 被 | 占 | 取 | 尚未 | 分配 | 位置 |
内存空间扩展不充沛的情况:
当是情况2的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间
来使用。这样函数返回的是一个新的内存地址。
free 释放空间
当我们该内存不许要使用的时后 ,就可以通过内存空间释放来,减少计算机内存负担,避免空间的浪费。
free(ptr); ptr=NULL;如果没有及时释放空间,空间就一直被占用,着未正确释放内存会导致内存泄漏,长期运行的程序可能因内存耗尽而崩溃,直到程序结束。
所以内存空间释放是横有必要的存在。
常见的动态内存的错误
错误1
#include <stdio.h> char* get_mory(void){ char p[]="hello world"; return p; } void test(void){ char* str=NULL; str=get_mory(); printf(str); } int main(){ test(); return 0; }char p[]="hello world"是一个局部数组,存储在栈上。
当get_mory函数返回时,栈帧被释放,p的内存不再有效。返回的指针p成为悬挂指针,访问它会导致未定义行为。
相当于get_mory返回指针后,因为“hello world”是在栈区上的数组,却又因为是局部变量,就会导致出了函数后就会销毁,已经没有hello world 这个数据了。
正确做法:
char* get_mory(void){ static char p[]="hello world";//static 修饰的数组存在于内存的静态区 return p; }利用static 让hello world 保存在内存的静态区,hello world 进行输出。
错误2
#include <stdio.h> #include <stdlib.h> void GetMemory(char*p) { p = (char*)malloc(100); } void Test(void) { char* str = NULL; GetMemory(&str); strcpy(str, "hello world"); printf(str); } int main() { Test(); return 0; }1.程序崩溃
原因是:
str传递给GetMemory函数的时候,采用的值传递
形参变量p其实是str的一份拷贝
当我们把malloc申请的空间的起始地址存放在p中时
不会修改str,str依然为NULL
所以当GetMemory函数返回后,再去调用strcpy函数需要
将“hello world”拷贝到str指向的空间时,程序崩溃。
2.因为malloc申请的空间没有free释放,存在内存泄露
正确做法:
#include <stdio.h> #include <stdlib.h> void GetMemory(char** p) { *p = (char*)malloc(100); printf("%c", **p); } void Test(void) { char* str = NULL; GetMemory(&str); //经过这了从单个变量转变成数组 strcpy(str, "hello world"); printf(str); free(str); str = NULL; } int main() { Test(); return 0; }错误3
#include <stdio.h> #include <stdlib.h> void test(){ char* str=(char*)malloc(100); strcpy(str,"hello"); free(str); if(str!=NULL){ strcpy(str,"world"); printf(str); } } int main(){ test(); return 0; }错误操作:
1,野指针问题,会非法访问内存。程序崩溃。
2,什么都打印不出来。
所以free 内存被释放之后,但是str还是地址还真在的,所以为了防止无意识的使用到已经free 释放可空间的时候还是要经行str = NULL,操作
错误4
#include <stdlib.h> int main(){ int* ptr=(int*) malloc(sizeof(int)*10); if(ptr==NULL){ perror("malloc"); return 1; } for(int i=0;i<10;i++){ *ptr=i; ptr++; } free(ptr); ptr=NULL; return 0; }错误操作:
free释放空间,一定要在要在内存空间从起始位置。
*ptr=i;ptr++;
该成ptr[i]=i;
错误5
int test(){ int* ptr=(int*) malloc(sizeof(int)*10); if(ptr==NULL){ perror("malloc"); return 1; } //.... free(ptr); return p; } int main(){ int *ptr=test(); free(ptr); ptr=NULL; return 0; }错误操作:
内存的二次释放也是不行的。
错误6
int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; //.. free(p); p = NULL; return 0; }错误操作:
对非malloc的动态内存空间经行释放空间操作