在python中,列表元素需要增加时,我们可以直接使用append或者insert等函数进行。但是在C++中没有这么方便的方法,数组的长度是固定的,不可以无限制的为数组增加内。那么当我们申请的空间不能够存下足够的内容该怎么办呢?
1.malloc分配动态内存
molloc是C语言设计的一种用于开辟一块空间的函数,其用法为:
(指针类型)malloc(所需开辟空间的字节大小)
使用malloc函数需要引cstdlib头文件。malloc可以返回一个指向分配内存块的指针,我们需要把它转换成所需类型的指针才能使用。当分配内存失败时,返回nullptr。通常情况下,分配内存都不会失败,不过为了规范,我们在使用之前还是应该判断一下,例如:
# include<cstdlib>
int main()
{
int* ptr=(int*)malloc(sizeof(int));
if(ptr) // 判断空间开辟是否成功
{
*ptr=10;
cout<<*ptr<<endl;
free(ptr); // 释放开辟的动态空间
}
}
// 输出为:10
上例中,free用于释放使用malloc开辟的动态空间,这是防止内存泄漏。
当然我们也可以分配更大的空间,用于存储数组:
int main()
{
int* ptr=(int*)malloc(10*sizeof(int)); // 开辟一个可以存储10个整形元素的空间
if(ptr)
{
for(int i=0;i<10;i++)
{
ptr[i]=i;
cout<<*(ptr+i)<<" ";
}
free(ptr);
}
}
// 输出为:0 1 2 3 4 5 6 7 8 9
自定义类是C语言没有的类型,不过C++中malloc函数也适配了自定义类:
class MyClass { // 定义MyClass类
public:
int data;
MyClass(int d) : data(d) {}
};
int main()
{
MyClass* ptr=(MyClass*)malloc(sizeof(MyClass));
if(ptr)
{
*ptr={5}; // 初始化
cout<<ptr->data;
free(ptr);
}
}
// 输出为:5
结构体指针、函数指针都可以用malloc函数进行开辟,有兴趣的小伙伴可以自行尝试。
2.new分配动态内存
malloc函数虽然可以用于开辟动态空间,但是C++拥有一个更方便的方式,即new。new不是一个函数,只是一个运算符,用法如下:
int main() {
int* p=new int(5); // 直接初始化分配空间
int* p1=new int[5];
cout<<*p<<endl;
for(int i=0;i<5;i++)
{
p1[i]=i;
cout<<*(p1+i)<<" ";
}
// 释放开辟空间
delete p;
delete[] p1;
return 0;
}
// 输出为:5
// 0 1 2 3 4
用法与malloc还是比较类似的,new分配动态空间可以直接初始化,没必要声明开辟空间的字节大小,也没必要担心分配失败的问题。释放new分配的动态空间时,使用delete即可。如果动态分配的内存是数组类型,需要使用delete[]。我们也可以在动态开辟时为数组初始化:
int main() {
int* p=new int[5]();
// int* p=new int[5]{1,2,3,4,5}; // 按自己需求对数组进行初始化
for(int i=0;i<5;i++)
{
cout<<*(p+i)<<" ";
}
// 释放开辟空间
delete[] p;
return 0;
}
// 输出为:0 0 0 0 0
new用于为自定义类开辟动态空间也十分简单,可以直接初始化的特点会为我们节省很多代码量:
class MyClass {
public:
int data;
MyClass(int d) : data(d) {}
};
int main() {
// 动态分配并初始化一个 MyClass 对象
MyClass *obj = new MyClass(5);
cout << "obj->data= " << obj->data << endl;
// 动态分配和初始化一个包含3个 MyClass 对象的数组
MyClass *arr = new MyClass[3] {MyClass(1), MyClass(2), MyClass(3)};
for (int i = 0; i < 3; i++) {
std::cout<<"arr["<<i<<"].data="<<arr[i].data << " ";
}
// 释放动态分配的内存空间
delete obj;
delete[] arr;
return 0;
}
// 输出为:obj->data= 5
// arr[0].data=1 arr[1].data=2 arr[2].data=3
在C++中,new是更常用的分配动态内存的方法,因为它开辟空间的类型更安全,分配和初始化对象时更方便,不需要手动检查分配任务是否成功。
3.典型动态空间开辟的应用
下面我们写一个简单的函数,实现在数组末尾添加元素:
void append(int** nums,int max_sub,int val)
{
int*p=new int[max_sub+2];
p[max_sub+1]=val;
for(;max_sub>=0;max_sub--)
{
p[max_sub]=*((*nums)+max_sub);
}
delete[] *nums;
*nums=p;
}
int main()
{
int *nums=new int[4]{1,2,3,4};
int size=4,*p=nums;
append(&p,size-1,5);
append(&p,size,6);
for(int i=0;i<=size+1;i++)
{
cout<<p[i]<<" ";
}
}
// 输出为:1 2 3 4 5 6
这样的做法就实现了。实际上,python中的列表也是用类似的方法实现理论上可以装下无穷多个元素的功能。当动态数组超界时,申请一个更大的动态数组复制原数组内容并继续添加新内容就可以了。
这节我们介绍了C++中开辟动态空间的方法,并举了个实际应用中的例子。不过有个小遗憾,目前我们还不会计算动态数组的大小。如何解决这个问题我会在后续分享C++标准库时和大家一起学习。