首页 > 系统相关 >C/C++ 动态分配:malloc()和free()所涉及的空指针和强制类型转换、与new和delete的对比、内存泄露是仅用指针来操作和锚定动态内存所导致的风险

C/C++ 动态分配:malloc()和free()所涉及的空指针和强制类型转换、与new和delete的对比、内存泄露是仅用指针来操作和锚定动态内存所导致的风险

时间:2024-08-15 12:56:54浏览次数:10  
标签:类型转换 malloc int free 动态分配 内存 指针

1、动态分配的内涵

所谓动态内存分配,是指在程序运行时根据需要分配和释放内存,而不是在编译时确定内存需求。动态分配包括两方面的内涵:

  • 在堆上分配内存
    对于linux的虚拟内存,可以分成以下5段:文本段、数据段(分初始化和未初始化数据段)、堆和栈。不使用动态分配定义一个变量,这个变量位于数据段(比如全局变量和静态变量)或者栈(比如函数体中的自动变量)中。关于虚拟内存,堆和栈,以后再专门开帖子讲。
  • 在运行阶段而不是编译阶段分配内存
    对比:#define和typedef分别是在预编译和编译阶段工作。

2、malloc()和free()

2.1 空指针和强制类型转换

malloc()和free()是c语言的动态内存分配函数。具体定义如下:

void* malloc(size_t size);

void free(void* ptr);

注意malloc()返回的是空指针/通用指针。实际上,为了增加函数的泛用性,许多库的封装函数都返回的空指针:创建成功时,返回指向该内存的空指针;若失败,则返回NULL。返回空指针的好处是,在使用时可以通过数据类型强制转换,将空指针转换成任意类型的指针,这极大提高了函数的泛用性。返回空指针空指针的函数一般是通过强制转换的方式进行使用,如下例所示:

int *arr = (int *)malloc(10 * sizeof(int));  //返回的空指针强转为int型指针

if (arr == NULL)     // 检查内存分配是否成功

{

printf("内存分配失败\n");

return 1;

}
......

free(arr);     

2.2 等式两边的独立性

使用malloc()在堆中分配内存时,除了空指针和强制类型转换,还有必要分别对等式左右两边的语句及其关系进行说明。

int *ptr = (int *)malloc(10 * sizeof(int));

等式左边定义了一个int型指针arr,等式右边调用malloc()函数在堆中分配了一个长度为10的int型数组。等式两边是彼此独立的两个语句,因此也可以把它们拆开写,语法上也是成立的:

int *ptr;
(int *)malloc(10 * sizeof(int));

但是这样做是不妥的,因为这么做涉及到动态分配的另一个关键特性:动态分配的变量(包括数据、结构体等)是没有变量名的,必须在定义时将其地址赋给一个指针,使用指针来操作变量。如果使用malloc()单独进行内存分配,那么所分配的内存是无法操作的,因为既不知道变量名,也不知道其具体位置。因此,实际进行内存分配时,都是指针定义和动态内存分配写在一个式子里边的。

3、new和delete

c++中,使用new和delete进行内存动态分配。和malloc()和free()一样,等式两边是彼此独立的两个语句,同样可以把它们拆开写。

和malloc()和free()不同的是,malloc()和free()是函数,但new和delete是关键字。并且new 关键字不仅仅分配内存,还会调用对象的构造函数来初始化对象。

另外还有一点很关键:delete释放的是堆中内存,而不是指向该内存的指针本身,后续该指针可以被继续使用

动态分配基本数据类型的变量:

int *ptr = new int; 

……

delete ptr;

动态分配数组:

int *ptr = new int [10];

……

delete [] ptr;

4、内存泄露

内存泄漏(Memory Leak)是指在计算机程序中,已分配的内存由于某种原因未能被释放,导致内存资源逐渐耗尽的现象。其实就是使用malloc()和free()(cpp中是new和delete)所存在的风险,更具体地说,是仅用指针来操作和锚定内存所存在的风险

发生内存泄露存在两种常见的情况:

  • 在函数中分配了一个堆,但是函数结束前忘记了使用free()或delete释放内存。所以malloc()和free()一定要成对使用。
    这是什么道理呢?我们知道,在函数体中定义的变量是自动变量,存放在对应的函数栈中,其生命期会随着函数调用的结束而结束。因此,随着函数调用的结束,在函数体内定义的用于操作和锚定动态内存的指针也就随之湮灭了。
    使用malloc()和new动态分配内存时,是在堆中进行分配,而不是分配在函数栈中。因此,即便动态分配所创建的内存并不会随着函数调用的结束而自动释放。
    于是就造成了这么一个情况:如果没有调用free()或delete及时释放内存,那么函数调用结束之后,原本唯一用于操作和锚定内存的指针消失了,而没有被释放的堆中内存就会一直存在下去,并且没有任何手段能找到它,这块内存成为了无用的内存碎片。每调用一次函数,就会产生一个内存碎片,久而久之,当内存被分割得支离破碎,再也找不到可被有效利用的内存块时,就会发生内存泄露。
  • 指向堆的指针被覆盖,指向了其他地方,导致无法再找到所分配的堆内存。
    对于这种情况,可以使用const常量指针。如果试图将pt指向别处,那么系统将会编译报错。
int* const ptr = (int *)malloc(10 * sizeof(int));  //c
int* const ptr = new int;  //cpp

标签:类型转换,malloc,int,free,动态分配,内存,指针
From: https://blog.csdn.net/hccgso1212/article/details/141217644

相关文章

  • C语言指针详解-上
    C语言指针详解-上前言1.指针的基本概念1.1指针是什么1.2指针的声明与初始化1.3取地址符`&`和解引用符`*``&`运算符用于**获取变量的地址**`*`运算符用于访问指针指向的值2.指针的类型常见数据类型的指针指针与数组、字符串数组指针结构体指针函数指针二级指针void指......
  • 深入了解指针(8)
    文章目录1.sizeof和strlen的对⽐1.1sizeof1.2strlen1.3sizeof和strlen的对⽐2.数组和指针笔试题分析2.1一维数组2.2字符数组2.3⼆维数组3.指针运算笔试题分析1.sizeof和strlen的对⽐1.1sizeof在学习操作符的时候,我们学习了sizeof,sizeof计算变量所占......
  • C语言基础11指针
    指针的引入为函数修改实参提供支持。为动态内存管理提供支持。为动态数据结构提供支持。为内存访问提供另一种途径。指针概述内存地址:系统为了内存管理的方便,将内存划分为一个个的内存单元(1个内存单元占1个字节),并为每一个内存单元进行了编号,内存单元的编号称为该......
  • 三:指针在数组中的应用
    1.使用指针访问数组指针的加减运算可以用来在内存中移动指针的地址。加上一个整数`n`,实际上就是移动了`n`个步长字节。步长是由指针指向的数据类型决定的。例如,假设有一个`int`类型的指针`p`:int*p=(int*)100;那么,执行`p+1`后,指针地址会向后移动`sizeof(in......
  • 【代码随想录】一、数组:3.双指针 - 977.有序数组的平方
    本文为977.有序数组的平方的解法,部分图文参考自代码随想录977.有序数组的平方。1.题目1:977.有序数组的平方1.1.解法1:直接排序classSolution{public:vector<int>sortedSquares(vector<int>&nums){for(inti=0;i<nums.size();i++){n......
  • C语言新手小白详细教程(7)指针和指针变量
    希望文章能够给到初学的你一些启发~如果觉得文章对你有帮助的话,点赞+关注+收藏支持一下笔者吧~阅读指南:开篇说明1、指针的定义接下来我们用图示的形式来解释一下指针:2、申明指针变量3、取地址符&4、为指针变量赋值5、间接运算符开篇说明本章节我们学习C语言......
  • C语言指针(3)
    野指针与空指针:野指针:概念:访问一个已经销毁或者访问受限的内存区域外的指针产生场景:·变量未初始化,通过指针访问该变量                       ·指针变量未初始化                           ·指......
  • [Lang] 智能指针
    [Lang]智能指针智能指针能够有效简化内存管理,避免内存泄漏和悬挂指针等问题。1.std::unique_ptr独占所有权:一个std::unique_ptr对象拥有其管理的对象的唯一所有权。不允许复制:不能进行复制操作,尝试复制会导致编译错误。允许移动:可以将std::unique_ptr对象移动到另一个......
  • 长度最小的子数组 滑动窗口法(双指针) 解决
    给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl,numsl+1,...,numsr-1,numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。示例1:输入:target=7,nums=[2,3,1,2,4,3]......
  • C语言——指针(数组,函数)
    通过指针引用数组数组元素的指针数组指针:数组中的第一个元素的地址,也就是数组的首地址指针数组:用来存放数组元素地址的数组(存放数组元素指针的变量),称之为指针数组。eg://定义一个一维数组inta[]={1,4,9};//使用指针变量存储数组的第一个元素的首地址,也就是数组......