C/C++内存使用之malloc/free,new/delete

本文详细介绍了C/C++中常用的内存管理方法,包括malloc/free、memcpy、new/delete的使用及区别,提供了丰富的代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文汇总了一下C/C++中用到的一些关于内存使用方面的用法~

-----------------------------malloc/free---------------------

百度百科 名称解释:malloc的全称是memory allocation,中文叫动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。

malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针。

函数原型:

void *malloc(unsigned int num_bytes);
头文件:
#include <stdlib.h>
或者
#include <malloc.h>
返回值:

如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。关于该函数的原型,在以前malloc返回的是char型指针,新的ANSIC标准规定,该函数返回为void型指针,因此必要时要进行类型转换。

工作机制:

malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针,因此在调用malloc动态申请内存块时,一定要进行返回值的判断。
正确的使用实例:

typedef struct data_type
{
    int age;
    char name[20];
}data; 
data*bob=NULL;
bob=(data*)malloc(sizeof(data));
if(bob!=NULL)
{
    bob->age=22;
    strcpy(bob->name,"Robert");        
    printf("%sis%dyearsold\n",bob->name,bob->age);
 
 
}    
else
{
    printf("mallocerror!\n");       
    exit(-1);  
}    
free(bob);
bob=NULL;

注:1. 根据malloc的使用机制,在写程序时需要验证malloc是否正确申请到内存,即验证是否==NULL,并在使用结束后free().否则可能会出现内存泄漏的意外情况。

2. malloc与free一定要配对使用,否则会出现问题,如果申请了空间但未释放这就会造成内存泄漏,而释放只能进行一次,释放多次会出现错误;(释放空指针例外,释放空指针等于什么也没做,所以释放多次也无所谓)
3. 虽然void*可以指向任意类型的指针,但是最好在使用前,将其强转成指定类型,这样可以更好的避过有些编译器的优化;

----------------------------memcpy---------------------------

C语言memccpy()函数:复制内存内容(忽略\0),头文件:

#include <string.h>

定义函数:

void * memcpy ( void * dest, const void * src, size_t num );

memcpy() 会复制 src 所指的内存内容的前 num 个字节到 dest 所指的内存地址上。memcpy() 不关心被复制的数据类型,只是逐字节地进行复制,可以面向任何数据类型进行复制。
需要注意的是:
dest 指针要分配足够的空间,即大于等于 num 字节的空间。如果没有分配空间,会出现错误。
dest 和 src 所指的内存空间不能重叠(如果发生了重叠,使用 memmove() 会更加安全)。
另外,memcpy()与 strcpy() 的不同点事,memcpy() 会完整的复制 num 个字节,不会因为遇到“\0”而结束。
//memcpy实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N (10)
int main()
{
	char* p1 = "fcqing"; //注意,这里p1字节数需要小于N,否则会出现错误。
	char* p2 = (char*)malloc(sizeof(char)* N);
	char* p3 = (char*)memcpy(p2, p1, N);
	printf("p2 = %s\np3 = %s\n", p2, p3);
	free(p2);
	p2 = NULL;
	p3 = NULL;
	system("pause");
	return 0;
}
memcpy对内存空间有要求的,dest和src所指向的内存空间不能重叠,否则复制的数据是错误的.如果内存空间布局入下图所示:

src所指向的内存空间后面部分数据被新拷贝的数据给覆盖了(也就是dest<=src+size).所以拷贝到最后,原来的数据肯定不是原来的数据,拷贝的数据也不是想要的数据,使用memcpy函数可以得到错误的结果.

----------------------------new/free--------------------------

new 和 delete 是 C++ 用于管理堆内存的两个运算符,对应于 C 语言中的 malloc 和 free,但是 malloc 和 free 是函数,new 和 delete 是运算符。除此之外,new 在申请内存的同时,还会调用对象的构造函数,而 malloc 只会申请内存;同样,delete 在释放内存之前,会调用对象的析构函数,而 free 只会释放内存。

当使用关键字new在堆上动态创建一个对象时,new 运算符的内部实现分为两步

(1)内存分配
调用相应的 operator new(size_t) 函数,动态分配内存。如果 operator new(size_t) 不能成功获得内存,则调用 new_handler() 函数用于处理new失败问题。如果没有设置 new_handler() 函数或者 new_handler() 未能分配足够内存,则抛出 std::bad_alloc 异常。“new运算符”所调用的 operator new(size_t) 函数,按照C++的名字查找规则,首先做依赖于实参的名字查找(即ADL规则),在要申请内存的数据类型T的 内部(成员函数)、数据类型T定义处的命名空间查找;如果没有查找到,则直接调用全局的 ::operator new(size_t) 函数。
(2)构造函数
在分配到的动态内存块上 初始化 相应类型的对象(构造函数)并返回其首地址。如果调用构造函数初始化对象时抛出异常,则自动调用 operator delete(void*, void*) 函数释放已经分配到的内存。

delete 运算符的内部实现分为两步:

(1)析构函数

调用相应类型的析构函数,处理类内部可能涉及的资源释放。
(2)内存释放
调用相应的 operator delete(void *) 函数。调用顺序参考上述 operator new(size_t) 函数(ADL规则)。

每个 new 获取的对象,必须用 delete 析构并释放内存,以免 内存泄漏。


new语法:

1)new int;
开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a.
2)int *a = new int(5) 作用同上,但是同时将整数赋值为5
2. 开辟数组空间
一维: int *a = new int[100];开辟一个大小为100的整型数组空间
二维: int **a = new int[5][6]
三维及其以上,依此类推.

实例:

#include <iostream>
using namespace std;

class Test
{
public:
	Test()
	{
		cout << "Test构造函数" << endl;
		str = new char[2];
	}
	~Test(){
		cout << "Test析构函数" << endl;
		delete[] str;
	}
private:
	char * str;
};

int main(int argc, char* argv[])
{
	char buf[100]; 
	Test *p = new(buf)Test(); // Test()产生的临时变量用于初始化 指定内存地址
	p->~Test(); // 主动调用析构函数,避免内存泄漏。

	char * buf2 = new char[100];
	Test * p2 = new(buf2)Test();
	p2->~Test(); // 切记,主动调用析构函数
	delete[] buf2; // 堆内存需要主动释放

	return 0;
}

------------------------malloc与new的区别----------------------

特征new/deletemalloc/free
分配内存的位置 自由存储区
内存分配失败返回值 完整类型指针 void*
内存分配失败返回值 默认抛出异常 返回NULL
分配内存的大小 由编译器根据类型计算得出 必须显式指定字节数
处理数组 有处理数组的new版本new[] 需要用户计算数组的大小后进行内存分配
已分配内存的扩充 无法直观地处理 使用realloc简单完成
是否相互调用 可以,看具体的operator new/delete实现 不可调用new
分配内存时内存不足 客户能够指定处理函数或重新制定分配器 无法通过用户代码进行处理
函数重载 允许 不允许
构造函数与析构函数 调用 不调用

参考:

http://www.cnblogs.com/GarfieldEr007/p/5594524.html

http://www.jb51.net/article/71559.htm

http://www.linuxidc.com/Linux/2016-01/127591.htm

http://blog.youkuaiyun.com/hihozoo/article/details/51441521

http://blog.youkuaiyun.com/he_shuai20/article/details/68482993?ref=myread
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值