动态内存分配

动态内存分配

函数名 描述
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';

输出:
动态内存分配_第1张图片

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;
}

设置断点
动态内存分配_第2张图片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.

你可能感兴趣的:(C++,c++)