怎么找人做动漫视频网站,如何辨别官方网站,百度资源搜索平台官网,企业网站策划书C语言之动态内存管理 文章目录 C语言之动态内存管理1. 为什么要有动态内存管理2. malloc 和 free2.1 malloc2.2 free2.3 例子 3. calloc 和 realloc3.1 calloc3.2 realloc 4. 常见的动态内存错误4.1 对NULL指针的解引⽤操作4.2 对动态开辟空间的越界访问4.3 对⾮动态开辟内存使…C语言之动态内存管理 文章目录 C语言之动态内存管理1. 为什么要有动态内存管理2. malloc 和 free2.1 malloc2.2 free2.3 例子 3. calloc 和 realloc3.1 calloc3.2 realloc 4. 常见的动态内存错误4.1 对NULL指针的解引⽤操作4.2 对动态开辟空间的越界访问4.3 对⾮动态开辟内存使⽤free释放4.4 使⽤free释放⼀块动态开辟内存的⼀部分4.5 对同⼀块动态内存多次释放4.6 动态开辟内存忘记释放内存泄漏 5. 总结 1. 为什么要有动态内存管理
我们已经掌握的内存开辟⽅式有
#include stdio.hint main()
{int val 20;int arr[10] { 0 };return 0;
}上述的开辟空间的⽅式有两个特点 • 空间开辟大小是固定的
•数组在申明的时候必须指定数组的⻓度数组空间⼀旦确定了⼤⼩不能调整
所以C语⾔引⼊了动态内存开辟让程序员⾃⼰可以申请和释放空间
2. malloc 和 free
malloc和free函数都是在stdlib.h头文件中声明的
2.1 malloc
C语言中提供了一个动态内存开辟的函数
void* malloc (size_t size);其中size为要开辟的内存空间的大小单位为字节
这个函数向内存申请⼀块连续可⽤的空间并返回指向这块空间的指针
•如果开辟成功则返回一个指向开辟好的内存空间的指针 •如果开辟失败则返回一个NULL指针 •返回类型为void *因为malloc函数不知道要开辟什么类型的内存空间只知道要开辟的大小 •如果参数为0,malloc函数的行为标准是未定义的取决于编译器
2.2 free
C语言还提供了一个的函数专门用来做动态内存的释放和回收的
void free (void* ptr);ptr为要释放内存空间的指针
•如果参数ptr指向的内存空间不是动态开辟的那么free函数的行为是未定义的 •如果参数ptr是NULL则函数什么都不做 如果不对malloc calloc realloc 开辟的空间进行释放即使出了作用域也不会销毁有可能导致内存泄漏 释放的方式 1. free 2. 直到程序结束由操作系统释放 2.3 例子
#include stdio.h
#include stdlib.h
#include string.hint main()
{int* p (int*)malloc(10 * sizeof(int)); //开辟40个字节的空间//判断是否为NULL指针if (p NULL){perror(malloc fail\n); //perror为错误信息打印return 1;}//使用int i 0;for (i 0; i 10; i){*(p i) i;//*p i; //如果使用这种方法p指针向后走了在下面打印时就找不到首元素的地址了//p;}//打印for (i 0; i 10; i){printf(%d , *(p i));}free(p); //释放p NULL; //将指针置NULL如果不置NULL下面解引用p时p就是野指针return 0;
}代码运行结果: 0 1 2 3 4 5 6 7 8 9 malloc开辟空间时是不会给空间初始化的如果直接打印会打印出随机值 3. calloc 和 realloc
3.1 calloc
C语⾔还提供了⼀个函数叫 calloc calloc 函数也⽤来动态内存分配
void* calloc (size_t num, size_t size);num为要开辟的元素个数 size为开辟元素的元素大小单位为字节
•calloc为开辟num个大小为size元素的内存空间并且将内存中每个字节初始化为0 •calloc的使用方法和malloc一样主要区别在于calloc会初始化元素
例子
#include stdio.h
#include stdlib.h
#include string.hint main()
{int* p (int*)calloc(10 ,sizeof(int));//判断是否为NULL指针if (p NULL){perror(calloc fail\n);return 1;}int i 0;for (i 0; i 10; i){printf(%d , *(p i));}return 0;
}代码运行结果: 0 0 0 0 0 0 0 0 0 0 3.2 realloc
C语言中有一个函数用来调整动态内存开辟后的大小
void* realloc (void* ptr, size_t size);ptr为要调整的内存地址 size为调整后的内存大小
• realloc函数的出现让动态内存管理更加灵活 • 当我们发现我们使用malloc calloc realloc申请的内存空间不够时我们可以使用realloc进行扩容
•返回值为调整之后的内存的起始位置不一定是原内存地址 •如果开辟失败则返回一个NULL •如果开辟成功则分以下两个情况 情况1:原有空间之后有⾜够⼤的空间 情况2原有空间之后没有⾜够⼤的空间 情况1在原有内存后边直接追加空间原来的空间的数据不变 情况2原有内存之后的空间不足以最加空间那么realloc会在堆区中找到一块足够开辟新大小的空间将旧空间中的数据拷贝到新空间并且将旧空间释放同时返回新空间起始位置的地址 realloc的用法除了为开辟的内存进行扩容也可以和malloc一样 例子
#include stdio.h
#include stdlib.h
#include string.hint main()
{int* p (int*)malloc(10 * sizeof(int));//判断是否为NULL指针if (p NULL){perror(malloc fail\n);return 1;}int* tmp (int*)realloc(p, 100*sizeof(int));if (tmp ! NULL){p tmp;}else{perror(relloc fail\n);return 1;}//使用//..........free(p);p NULL;return 0;
}这次的运行结果就是情况2开辟100个字节的大小时可能会出现当后面的空间不够时 realloc就会找一块新的空间 这次只开辟了40个字节的空间属于情况1后面的空间足够时 realloc会直接在后面追加空间
4. 常见的动态内存错误
4.1 对NULL指针的解引⽤操作
#include stdio.h
#include stdlib.hint main()
{int* p (int*)malloc(40);*p 20; //如果malloc开辟空间失败p可能是NULL此时p为野指针return 0;
}在VS2022中编译器会进行提示我们得对可能出现NULL的情况进行处理 在使用malloc calloc realloc开辟空间时最好对返回值进行判断当不为NULL再使用 4.2 对动态开辟空间的越界访问
#include stdio.h
#include stdlib.h
#include string.hint main()
{int* p (int*)malloc(40);if (p NULL){perror(malloc fail\n);return 1;}int i 0;for (i 0; i 10; i) //只有10个元素的空间却访问了第11个元素访问越界了{*(p i) i;}free(p);p NULL;return 0;
}4.3 对⾮动态开辟内存使⽤free释放
#include stdio.h
#include stdlib.hint main()
{int a 10;int* p a;free(p);return 0;
} 当用free释放了不是由malloc calloc realloc开辟的空间时就会报错
4.4 使⽤free释放⼀块动态开辟内存的⼀部分
#include stdio.h
#include stdlib.h
#include string.hint main()
{int a 10;int* p (int*)malloc(40);if (p NULL){perror(malloc fail\n);return 1;}//使用//......p;free(p);p NULL;return 0;
} 当用free释放了开辟空间的一部分时就会报错
4.5 对同⼀块动态内存多次释放
#include stdio.h
#include stdlib.h
#include string.hint main()
{int a 10;int* p (int*)malloc(40);if (p NULL){perror(malloc fail\n);return 1;}//使用//......free(p);free(p);p NULL;return 0;
} 对一块动态开辟的内存进行多次free释放
在上述代码中如果free释放NULL则没有问题因为free的参数为NULL时则什么都不做
#include stdio.h
#include stdlib.h
#include string.hint main()
{int a 10;int* p (int*)malloc(40);if (p NULL){perror(malloc fail\n);return 1;}//使用//......free(p);p NULL;free(p);p NULL;return 0;
}
4.6 动态开辟内存忘记释放内存泄漏
#include stdio.h
#include stdlib.hvoid test()
{int* p (int*)malloc(100);if (p ! NULL){*p 20;}
}
int main()
{test();while (1); //死循环让程序不结束return 0;
}当动态开辟的内存不释放时就会一存在在上述代码中调用了test函数开辟了100个字节的空间同时赋值出函数时p被销毁了但是开辟的空间并没有被销毁没人可以使用也没人可以释放就会导致内存泄漏
5. 总结
一丶 在使用malloc calloc realloc开辟的空间时要对其进行判断当不为NULL的再进行使用 二丶 当不使用动态开辟的内存时将其free释放同时将指针置NULL防止可能出现的内存泄露和野指针 三丶 不对不是动态开辟的空间free不连续对动态开辟的空间free同时free动态开辟的空间时要给开辟的起始地址不能free部分空间