动态内存分配

本文详细介绍了C/C++中malloc、calloc、realloc和free函数的用法,包括内存分配、数组操作、类型安全性比较,以及new与这些函数的区别。通过实例演示了如何正确管理内存并避免悬垂指针问题。

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

动态内存分配

函数名描述
malloc()保留一个被请求的字节数和返回一个指向第一个被保留的字节的指针。eg:malloc(50 * sizeof(int))保留足够字节数存储50个整数,malloc()返回一个指向被保留存储区第一个字节的指针。因为被返回的指针总是“指向”一个void,所以它中总是被强制转换成一个期望类型指针。
calloc()为一个被指定大小的n个元素的数组保留空间。返回第一个保留位置的地址并初始化所有保留的字节为0。或者返回NULL
realloc()改变前面分配存储区的数量(收缩/扩张)
free()释放前面保留的字节块。第一个保留位置的地址作为参数传递给free()函数
// An highlighted block
int *intPtr;
intPtr = (int*) malloc(50 * sizeof(int));

malloc()为数组请求空间

/*
1、用malloc分配空间,把首地址给grades
2、判断分配是否成功
3、把grades的内存用free归还
*/
#include <stdio.h>
#include <stdlib.h>

int main()
{
	int numgrades, i;
	int *grades;

	printf("\n输入个数 : ");
	scanf_s("%d", &numgrades);
	grades = (int*)malloc(numgrades * sizeof(int));

	//检查分配是否被满足,把NULL强制转换成一个指向转换整数的指针
	if (grades ==(int*) NULL)
	{
		printf("\nfailed");
		exit(1);
	}

	for (i = 0; i < numgrades; i++)
	{
		printf("输入数值:");
		scanf_s("%d", &grades[i]);
	}

	for ( i = 0; i < numgrades; i++)
		printf("%d\n",grades[i]);

	//把堆的内存归还给计算机
	free(grades);
	system("pause");
	return 0;
}
var foo = 'bar';

输出:
在这里插入图片描述

malloc()为结构体动态分配存储空间

// An highlighted block
typedef struct Rectangle
{
    uint64_t area_sign;
    int left;
    int top;
    int right;
    int bottom;
}Rectangle;

typedef struct rectangleSet
{
    int area_count;
    Rectangle area[0];
}rectangleSet;

#define MAX_AREA_COUNT 128
//创建指针将存储分配的地址
rectangleSet *area;
//为结构体请求空间,并且强制转换这个返回的地址为一个正确的结构类型指针
area = (rectangleSet*)malloc(sizeof(rectangleSet)+sizeof(Rectangle)*MAX_AREA_COUNT);
if(area == (rectangleSet*)NULL)
{
	printf("\nfailed");
	exit(1);
}
memset(area ,0, sizeof(rectangleSet)+sizeof(Rectangle)*MAX_AREA_COUNT);

malloc()和new的区别

(1)为对象申请内存位置
项目内存位置内存位置解释
new操作符自由存储区(free store)自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。自由存储区可以是堆,也可以是静态存储区。
malloc函数堆 (heap)堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。
(2)返回类型安全性
项目返回类型安全性
new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换符合类型安全性
malloc函数内存分配成功时,返回void * ,需要通过强制类型转换将void*指针强转成需要的类型不符合类型安全性
(3)内存分配失败时的返回值

new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
在使用C语言时,我们习惯在malloc分配内存后判断分配是否成功:

 int *a  = (int *) malloc (sizeof(int ));
 if(a ==(int*) NULL)
{
    ...
}
 else
{
    ...
} 

C++

 int * a = new int();
if(a== NULL)
{
    ...
}
else
{   
    ...
} 

new根本不会返回NULL,而且程序能够执行到if语句已经说明内存分配成功了,如果失败早就抛异常了。正确的做法应该是使用异常机制:

try
{
    int *a = new int();
}
catch (bad_alloc)
{
    ...
}
(4)是否需要指定内存大小

使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。

class A{…}
A * ptr = new A;
A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A);

(5)是否调用构造函数/析构函数

使用new操作符来分配对象内存时:

第一步:调用operator new 函数(对于数组是operator new[])分配一块足够大的,原始的,未命名的内存空间以便存储特定类型的对象。
第二步:编译器运行相应的构造函数以构造对象,并为其传入初值。
第三部:对象构造完成后,返回一个指向该对象的指针。
使用delete操作符来释放对象内存时会经历两个步骤:

使用delete操作符来释放对象内存时:

第一步:调用对象的析构函数。
第二步:编译器调用operator delete(或operator delete[])函数释放内存空间。
总之来说,new/delete会调用对象的构造函数/析构函数以完成对象的构造/析构。而malloc则不会。
例如:

#include <stdio.h>
#include <stdlib.h>
class A
{
public:
	A() :a(1), b(1.11) {}
private:
	int a;
	double b;
};
int main()
{
	A * ptr = (A*)malloc(sizeof(A));
	A *aPtr = new A();
	return 0;
}

设置断点
在这里插入图片描述malloc动态分配内存并没有调用A的默认构造函数,而new操作符分配空间调用默认构造函数初始化指针,所以使用malloc/free来分配C++的自定义类型内存不合适,其实不止自定义类型,标准库中凡是需要构造/析构的类型通通不合适。

(6)对数组的处理

C++提供了new[]与delete[]来专门处理数组类型:

A * ptr = new A[10];//分配10个A对象
使用new[]分配的内存必须使用delete[]进行释放:

delete [] ptr;
new对数组的支持体现在它会分别调用构造函数函数初始化每一个数组元素,释放对象时为每个对象调用析构函数。注意delete[]要与new[]配套使用,不然会找出数组对象部分释放的现象,造成内存泄漏。

malloc()/free()函数分配释放数组内存
int * ptr = (int *) malloc( 10 * sizeof(int) );//分配一个10个int元素的数组
free(ptr);

此外;

int *intPtr = new int();
delete intPtr;

执行完该语句后,intPtr变成了不确定的指针,在很多机器上,尽管intPtr值没有明确定义,但仍然存放了它之前所指对象的地址,然后intPtr所指向的内存已经被释放了,所以intPtr不再有效。此时,该指针变成了悬垂指针(悬垂指针指向曾经存放对象的内存,但该对象已经不存在了)。悬垂指针往往导致程序错误,而且很难检测出来。
因此释放指针之后要给他们重新赋空值

int *intPtr = new int();
delete intPtr;
intPtr = NULL;

链接: link.

### Frida 分配内存失败的原因分析 当遇到Frida分配内存失败的情况时,通常可能由多种因素引起。一种常见情况是在应用程序启动过程中尝试通过扫描特定关键词来检测是否存在附加的Frida进程[^1]。如果此过程出现问题,可能会间接影响到后续操作的成功率。 然而,具体针对Frida分配内存失败这一现象,可以从以下几个方面考虑: #### 1. 权限不足 确保执行环境拥有足够的权限来进行内存分配以及访问目标进程的相关资源。对于某些操作系统而言,这可能涉及到管理员权限或是特殊的安全策略设置。 #### 2. 内存空间限制 检查当前系统的可用物理内存和虚拟地址空间是否充足。特别是在嵌入式设备或移动平台上运行大型应用时,容易因为剩余内存过少而导致无法成功完成内存分配请求。 #### 3. API兼容性问题 不同平台上的编程接口可能存在差异,尤其是在跨编译环境下工作时更需注意API调用的一致性和合法性。例如,在Xcode环境中遇到了`implicit declaration of function 'swapcontext' is invalid in C99`这样的警告信息[^2],表明所使用的函数定义不符合C标准规定,进而可能导致程序行为异常甚至崩溃。 为了有效解决问题并实现稳定可靠的内存管理功能,建议采取以下措施之一: - **调整源码**:修改代码逻辑以适应新的开发工具链要求; - **更新依赖库**:确认所有外部依赖项均为最新版本,并且适用于当前项目架构; - **优化算法设计**:重新评估现有解决方案的有效性,寻找更加高效合理的替代方法。 ```c++ // 示例:处理 swapcontext 函数未声明的问题 #include <ucontext.h> void safe_swap_context(ucontext_t *old_ucp, const ucontext_t *new_ucp){ getcontext(old_ucp); setcontext(new_ucp); // 使用官方推荐的方式替换原始 swapcontext 调用 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Maccy37

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值