calloc与realloc和malloc的区别以及new

news2024/11/14 4:20:10

 

目录

calloc、realloc 和 malloc

三个函数的区别在于

更详细的示例代码

交叉使用

内存泄漏

悬空指针

内存重叠

new 的语法

使用 new 运算符在堆上创建学生对象的示例

new和malloc都可以用于在堆上分配内存



calloc、realloc 和 malloc

是 C/C++ 中用于动态内存分配的函数。

  1. malloc 函数:malloc 函数用于在堆上分配指定大小的内存块。它接受一个参数,即所需内存块的字节数,返回一个指向分配内存的指针。如果分配失败,则返回 NULL。

  2. calloc 函数:calloc 函数类似于 malloc 函数,但它还会将分配的内存块初始化为零。它接受两个参数,即所需内存块的个数和每个内存块的字节数。它返回一个指向分配内存的指针。如果分配失败,则返回 NULL。

  3. realloc 函数:realloc 函数用于重新分配已分配内存的大小。它接受两个参数,即原始内存块的指针和新的内存块大小。如果内存分配成功,则返回一个指向新分配内存的指针。如果分配失败,则返回 NULL。同时,realloc 函数还会尝试保留原始内存块中的数据,将其复制到新分配的内存块中。

三个函数的区别在于

  • malloc 只负责分配指定字节数的内存块,不对其进行初始化。
  • calloc 在分配内存块的同时,将其初始化为零。
  • realloc 用于重新分配内存块的大小,并尝试保留原始内存块中的数据。

注意:虽然这些函数在 C 中广泛使用,但在 C++ 中,推荐使用 new 和 delete 运算符进行动态内存分配和释放,以便与对象的构造函数和析构函数配合使用,更好地管理内存和资源。

当涉及到内存分配和重新分配时,以下是

更详细的示例代码

#include <iostream>
#include <cstdlib>

int main() {
    // 例子1:使用 malloc 分配内存
    int* ptr = (int*)malloc(5 * sizeof(int)); // 在堆上分配 5 个 int 类型大小的内存块
    if (ptr == NULL) {
        std::cout << "内存分配失败" << std::endl;
        return 1;
    }

    // 例子2:使用 calloc 分配内存并初始化
    int* ptr2 = (int*)calloc(5, sizeof(int)); // 在堆上分配 5 个 int 类型大小的内存块,并初始化为零
    if (ptr2 == NULL) {
        std::cout << "内存分配失败" << std::endl;
        return 1;
    }

    // 例子3:使用 realloc 重新分配内存
    int* ptr3 = (int*)realloc(ptr, 10 * sizeof(int)); // 将之前分配的内存块大小重新调整为 10 个 int 类型大小
    if (ptr3 == NULL) {
        std::cout << "内存分配失败" << std::endl;
        free(ptr); // 释放之前分配的内存块
        return 1;
    }
    
    // 释放内存
    free(ptr);
    free(ptr2);
    free(ptr3);

    return 0;
}

在这个例子中,我们首先使用 malloc 函数分配了一个包含 5 个 int 类型大小的内存块,并将其分配给 ptr 指针。然后,我们使用 calloc 函数分配了另一个包含 5 个 int 类型大小的内存块,并将其初始化为零,并将其分配给 ptr2 指针。最后,我们使用 realloc 函数重新分配了 ptr 指针指向的内存块的大小,将其调整为包含 10 个 int 类型大小,并将其分配给 ptr3 指针。

请注意,在使用这些函数进行内存分配之后,需要使用 free 函数释放已分配的内存,以避免内存泄漏。

交叉使用

malloccallocrealloc 函数时,可能会导致一些问题,如内存泄漏、悬空指针和内存重叠等。下面是这些问题的一些例子:

内存泄漏

如果在分配内存后没有正确释放它,就会导致内存泄漏。这意味着分配的内存将无法再被使用,并且会占用系统资源。例如,在下面的代码中,内存块 ptr 分配后没有被释放:

int* ptr = (int*)malloc(10 * sizeof(int));
// 使用分配的内存块进行操作
// 忘记释放内存块

悬空指针

悬空指针是指指向已释放或未分配内存的指针。当你尝试访问悬空指针时,可能会导致程序崩溃或产生未定义的行为。例如,在下面的代码中,内存块 ptr 被释放后,但指针没有被置为 NULL:

int* ptr = (int*)malloc(10 * sizeof(int));
free(ptr);
// ptr 是一个悬空指针

内存重叠

当你使用 realloc 函数重新分配内存时,如果新的内存块与原始内存块重叠,会导致未定义的行为。这种情况可能会破坏数据或导致程序崩溃。例如,在下面的代码中,当 realloc 函数将原始内存块扩展到更大的大小时,与之前分配的内存块可能发生重叠:

int* ptr = (int*)malloc(5 * sizeof(int));
int* ptr2 = (int*)realloc(ptr, 10 * sizeof(int)); // 内存重叠

为了避免这些问题,建议在使用 malloccallocrealloc 函数时注意以下几点:

  • 确保在分配内存后及时调用 free 函数释放内存。
  • 在释放内存后将指针置为 NULL,以避免悬空指针。
  • 在使用 realloc 函数重新分配内存时,确保新的内存块与原始内存块没有重叠。

此外,C++ 中还提供了更安全和方便的动态内存分配和释放方式,推荐使用 newdelete 运算符进行管理动态内存。

C++ 中,new 运算符用于在动态存储区(堆)中分配指定大小的内存。

new 的语法

pointer = new type;

其中,type 指向要分配内存的类型,可以是基本类型、类类型或数组类型。pointer 是一个指针,它指向新分配的内存块的开头。

例如,下面是一个使用 new 运算符在堆上分配一个整数的示例:

int* ptr = new int;

在上面的示例中,new 运算符返回一个指向分配的内存块的指针,这个内存块的大小与 int 类型相同。我们将这个指针赋值给 ptr 变量,以便稍后可以使用它来访问这个内存块中的数据。

如果要在堆上分配一个数组,可以使用以下语法:

pointer = new type [number_of_elements];

其中,type 是数组元素的类型,number_of_elements 是数组元素的数量。

例如,下面是一个使用 new 运算符在堆上分配一个整数数组的示例:

int* ptr = new int[5];

在上面的示例中,new 运算符返回一个指向分配的内存块的指针,这个内存块的大小等于 5 * sizeof(int) 字节。我们将这个指针赋值给 ptr 变量,以便稍后可以使用它来访问这个内存块中的数据。

除了分配内存之外,new 运算符还可以调用构造函数来初始化新分配的内存。例如,下面是一个使用 new 运算符在堆上分配一个类的示例:

class MyClass {
public:
    MyClass() {
        std::cout << "MyClass 构造函数被调用" << std::endl;
    }
};

MyClass* ptr = new MyClass;

在上面的示例中,new 运算符返回一个指向分配的 MyClass 类型内存块的指针,并调用 MyClass 类的默认构造函数进行初始化。我们将这个指针赋值给 ptr 变量,以便稍后可以使用它来访问这个内存块中的数据。

需要注意的是,使用 new 运算符分配的内存必须使用 delete 运算符进行释放。例如,上面的示例应该如下释放内存:

delete ptr;

如果分配的是数组,则应使用以下语法释放内存:

delete[] pointer;

例如,下面是一个使用 delete 运算符释放整数数组的示例:

delete[] ptr;

需要注意的是,如果不释放使用 new 运算符分配的内存,就会导致内存泄漏。在释放内存之后,最好将指针置为 NULL,以避免悬空指针的问题。

当你使用 new 运算符在堆上分配内存时,可以考虑使用类来演示。下面是一个

使用 new 运算符在堆上创建学生对象的示例

#include <iostream>
#include <string>

class Student {
public:
    Student(const std::string& name, int age) : name(name), age(age) {
        std::cout << "学生对象 " << name << " 被创建" << std::endl;
    }

    ~Student() {
        std::cout << "学生对象 " << name << " 被销毁" << std::endl;
    }

    void DisplayInfo() {
        std::cout << "姓名:" << name << std::endl;
        std::cout << "年龄:" << age << std::endl;
    }

private:
    std::string name;
    int age;
};

int main() {
    // 使用 new 运算符在堆上创建一个学生对象
    Student* ptr = new Student("小明", 18);

    // 调用对象的成员函数
    ptr->DisplayInfo();

    // 释放内存
    delete ptr;

    return 0;
}

在上面的示例中,我们定义了一个 Student 类,它有一个带有姓名和年龄参数的构造函数、一个析构函数和一个显示信息的成员函数。在 main 函数中,我们使用 new 运算符在堆上创建一个 Student 对象,并将返回的指针赋给 ptr 变量。然后,我们调用 ptr 指向的对象的成员函数来显示学生的信息。最后,我们使用 delete 运算符释放了分配的内存。

运行上述代码,输出结果如下:

学生对象 小明 被创建
姓名:小明
年龄:18
学生对象 小明 被销毁

这个示例演示了如何使用 newdelete 运算符来动态分配和释放对象的内存。记得在使用完毕后及时释放内存,以避免内存泄漏。

这段代码是一个简单的C++示例,演示了如何使用new运算符在堆上创建对象,并使用delete释放内存。

首先,代码定义了一个名为Student的类,表示学生对象。该类有两个私有成员变量:name(姓名)和age(年龄)。构造函数Student用于初始化对象的姓名和年龄,并在创建对象时打印一条消息。析构函数~Student在对象销毁时被调用,用于释放资源并打印一条销毁消息。成员函数DisplayInfo用于打印学生对象的姓名和年龄。

std::string是C++标准库中的一个类,用于表示字符串。它是C++中处理字符串的一种常用方式。

std::string类提供了各种成员函数和操作符,用于对字符串进行操作,包括字符串的连接、截取、查找、替换等。它还提供了许多便捷的方法,如获取字符串长度、判断字符串是否为空、将字符串转换为整数等。

使用std::string类可以方便地进行字符串的操作和处理,而不需要手动管理内存或处理字符数组。它也提供了一些与C风格字符串的兼容性函数,以便与现有的C代码进行交互。

要在C++程序中使用std::string,需要包含头文件 <string>,并使用 std 命名空间。例如:

#include <string>
#include <iostream>

int main() {
    std::string str = "Hello, World!";
    std::cout << str << std::endl;
    return 0;
}

上述代码创建了一个名为 strstd::string 对象,并将其初始化为 "Hello, World!"。然后,通过 std::cout 输出该字符串到控制台。

std::string是C++中用于表示字符串的类,提供了丰富的字符串操作方法和功能。

main函数中,使用new运算符在堆上动态地创建了一个Student对象,并将指向该对象的指针赋值给ptr变量。创建对象时,构造函数会被调用,并打印一条创建消息。

接下来,通过ptr指针调用了对象的成员函数DisplayInfo,以打印学生对象的姓名和年龄。

最后,在程序结束前,使用delete运算符释放了通过new分配的内存。释放内存时,析构函数会被调用,并打印一条销毁消息。

这样,该程序就完成了对堆上动态分配对象的创建、使用和销毁的过程。使用newdelete可以在堆上分配和释放内存,使得对象的生命周期可以由程序控制,更加灵活。

newmalloc都可以用于在堆上分配内存

但它们之间有以下几个区别:

  1. new是C++的关键字,而malloc是C语言的库函数。因此,在C++中使用new更为方便和安全,而在C中则更常用malloc

  2. new会自动计算要分配的内存大小,并返回指向已分配内存的指针。而malloc需要手动计算内存大小,并返回一个void*类型的指针,需要进行类型转换后才能使用。这可能会导致一些潜在的错误。

  3. new会调用类的构造函数来初始化对象,而malloc只是简单地分配一块内存。因此,使用new可以确保对象被正确地初始化,而使用malloc需要手动调用构造函数。

  4. new会抛出异常,而malloc只会返回NULL。在内存分配失败时,new会抛出std::bad_alloc异常,而malloc则会返回NULL指针。因此,在使用new时需要考虑异常处理,而在使用malloc时需要检查返回值是否为NULL

虽然newmalloc都可以用于在堆上分配内存,但由于new更方便、更安全,而且可以自动初始化对象,因此在C++中更常用new。不过,对于一些特殊的内存分配场景,如需要对齐或不需要初始化等情况下,可能需要使用malloc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1397764.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PrestaShop购物系统 SQL注入漏洞复现(CVE-2023-30150)

0x01 产品简介 PrestaShop 是一个功能丰富,基于 PHP5 开发的 Web2.0 网上购物系统。PrestaShop 具有可定制,稳定等特点。整个系统只有 5.8MB,易于快速安装。 0x02 漏洞概述 PrestaShop 的部分主题中使用Leo Custom Ajax模块拓展,Leo Custom Ajax模块中可以在/modules/le…

ValueError: Unable to read workbook: could not read strings from data.xlsx解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

RNN:Long Short-term Memory(中)

目录 1 LSTM 的简图 2 LSTM 的整体结构 2.1 结构图 2.2 流程图 3 举个例子 3.1 简单看看 3.2 代入 LSTM 4 Original Network v.s. LSTM 5 细看 LSTM 原视频&#xff1a;李宏毅 2020&#xff1a;Recurrent Neural Network (Part I) 1 LSTM 的简图 LSTM 实际…

css3+javaScript实现一个左右钟摆-摇晃的红灯笼网页特效

css3javaScript实现一个左右钟摆-摇晃的红灯笼网页特效&#xff01;前天逛博客时无意中看见了&#xff0c;别人的博客顶部有一个会左右钟摆的摇晃的红灯笼&#xff0c;产生了想法&#xff0c;我也想给自己做一个&#xff0c;但是网上找了很多方案&#xff0c;都没有实现。终于在…

教您如何下载保存钉钉视频到电脑本地

教您如何下载保存钉钉视频到电脑和手机相册地瓜网络技术 大家好&#xff0c;我们这边是地瓜网络技术&#xff01;30秒教会你下载钉钉视频&#xff01;现在很多群管理员把视频设置为禁止下载&#xff0c;导致我们无法正常的下载群直播回放视频&#xff0c; 今天我们就教大家如何…

第十二篇【传奇开心果系列】Ant Design Mobile of React开发移动应用:内置组件实现酷炫CSS 动画

Ant Design Mobile of React 开发移动应用示例博文系列 第一篇【传奇开心果系列】Ant Design Mobile of React 开发移动应用:从helloworld开始 第二篇【传奇开心果系列】Ant Design Mobile of React 开发移动应用:天气应用 第三篇【传奇开心果系列】Ant Design Mobile of Reac…

flutter获取地理定位:geolocator依赖详细用法

本文使用geolocator插件实现app物理定位功能。 该插件的主要功能有&#xff1a; 获取最后已知位置&#xff1b;获取设备当前位置&#xff1b;获取连续的位置更新&#xff1b;检查设备是否启用了定位服务&#xff1b;计算两个地理坐标之间的距离&#xff08;米&#xff09;&am…

linux网络协议栈2--网络包接收发送流程

上文我们讲了报文格式&#xff0c;应该对数据传输格式有了一定了解&#xff0c;这篇文章主要讲述的是网络包接收和发送的流程&#xff0c;主要是大方面来介绍。 网络包接收流程 当网络数据帧通过网络传输到达网卡时&#xff0c;网卡会将网络数据帧通过DMA的方式放到环形缓冲区…

Flutter轮播图Banner

使用插件&#xff1a;flutter_swiper 实现轮播图 pubspec.yaml 增加 &#xff1a;flutter_swiper : ^lastest_version 在项目文件夹下打开命令行执行&#xff1a;flutter packages get 安装插件 home_page.dart中使用swiper 程序运行:先启动虚拟设备后&#xff0c;执行命令f…

【C语言】linux内核ipoib模块 - ipoib_send

一、ipoib_send函数定义 int ipoib_send(struct net_device *dev, struct sk_buff *skb,struct ib_ah *address, u32 dqpn) {struct ipoib_dev_priv *priv ipoib_priv(dev);struct ipoib_tx_buf *tx_req;int hlen, rc;void *phead;unsigned int usable_sge priv->max_sen…

redis数据安全(一)数据持久化

一、Redis数据安全措施: 1、将数据持久化至硬盘 2、将数据复制至其他机器&#xff1b; 复制是在数据持久化的基础上进行的。 二、将数据持久化至硬盘 1、介绍&#xff1a;Redis是一个基于内存的数据库&#xff0c;它的数据是存放在内存中&#xff0c;内存有个问题就是关闭…

大模型 RAG 面试篇

1.LLMs 存在模型幻觉问题&#xff0c;请问如何处理&#xff1f; 检索LLM。 先用问题在领域数据库里检索到候选答案&#xff0c;再用LLM对答案进行加工。 2.基于LLM向量库的文档对话 思路是怎么样&#xff1f; 加载文件读取文本文本分割文本向量化问句向量化在文本向量中匹配…

构建高效外卖系统:技术实践与代码示例

外卖系统在现代社会中扮演着重要的角色&#xff0c;为用户提供了便捷的用餐解决方案。在这篇文章中&#xff0c;我们将探讨构建高效外卖系统的技术实践&#xff0c;同时提供一些基础的代码示例&#xff0c;帮助开发者更好地理解和应用这些技术。 1. 技术栈选择 构建外卖系统…

Python爬虫从入门到入狱系列合集

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

【Qt5】QString的成员函数chop

2024年1月19日&#xff0c;周五下午 QString 的 chop 方法用于从字符串的末尾移除指定数量的字符。这个方法会修改原始字符串&#xff0c;并返回 void。 下面是一个简单的示例&#xff1a; #include <QString> #include <QDebug>int main() {QString originalStr…

python使用jupyter记笔记

目录 一、安装 二、运行jupyter 三、使用 四、记笔记 Jupyter Notebook&#xff08;此前被称为 IPython notebook&#xff09;是一个交互式笔记本&#xff0c;支持运行 40 多种编程语言。 Jupyter Notebook 的本质是一个 Web 应用程序&#xff0c;便于创建和共享程序文档&a…

接口的返回值中所需信息作为其他接口入参使用(postman与jmeter的使用)

一、背景&#xff1a; 偶尔会用到一个场景&#xff0c;两个接口之前的调用有依赖关系&#xff0c;将其中一个的返回参数中的部分信息取出来作为入参在第二个接口中使用&#xff0c;代码内是比较好实现&#xff0c;只要定义一个变量&#xff0c;用于参数传递。 如果是测试过程中…

java小项目:简单的收入明细记事本,超级简单(不涉及数据库,通过字符串来记录)

一、效果 二、代码 2.1 Acount类 package com.demo1;public class Acount {public static void main(String[] args) {String details "收支\t账户金额\t收支金额\t说 明\n"; //通过字符串来记录收入明细int balance 10000;boolean loopFlag true;//控制循…

关于datagrip的一个错误。Unexpected update count received (Actual: 3, Expected: 1).

这一行原本的值是<null><null><null>,现在我们把它修改为1,114&#xff0c;无名氏&#xff0c;但却报错。 这是对应的sql语句&#xff0c;原因在于有三行全为 <null><null><null>&#xff0c;where无法指定是哪一行&#xff0c;所以看起来…

电子学会C/C++编程等级考试2023年12月(七级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:迷宫 一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下…