C/C++动态内存分配 malloc、new、vector(简单讲述)

路虽远,行则将至

事虽难,做则必成

今天来主要讲C++中动态内存分配

其中会穿插一些C的内容以及两者的比较

如果对C语言中的动态内存分配还不够理解的同学

可以看看我之前的博客:C语言动态分配


在讲解C++的动态内存分配之前

我们先讲一下C++内存模型 :

C++内存分配模型

C++程序在执行时,将内存大方向划分为4个区域:


代码区 :存放函数体的二进制代码,由操作系统进行管理的
全局区 :存放全局变量和静态变量以及常量
栈区 :由编译器自动分配释放,存放函数的参数值,局部变量等
堆区 :由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收



意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程

栈区内存和堆区内存的区别

栈区内存是由编译器管理的,出了定义域就会被系统销毁

这里用代码展示:

cpp 复制代码
#include<iostream>
using namespace std;
int* fun()
{
	int a = 10;              //局部变量存放在栈区,栈区的数据在函数执行完后释放
	return &a;               //返回变量a的地址
}
int main()
{
	int* p = fun();          //接受函数fun的返回值
	cout << "" << *p << endl;//这里能打印10是因为编译器在释放的会进行一次保留
	cout << "" << *p << endl;//这里出现乱码是因为空间被编译器销毁了
	system("pause");
	return 0;
}

1.第一次打印原值 是因为编译器在释放时会进行一次保留

2.第二次出现乱码 是因为出函数定义域空间被编译器销毁

由于栈区的内存出了定义域会被系统销毁不满足某些程序需求

于是我们引进了由程序员掌控的动态内存


堆区内存(也就是我们说的动态内存)是由我们程序员分配的,由程序员进行管理

C++中动态内存开辟关键字new

**我们可以通过new和****delete(关键字)**操作符进行动态内存管理

cpp 复制代码
#include<iostream>
using namespace std;
int* fun()
{
	                     //利用new关键字可以将数据开辟到堆区
	int* p = new int(10);//动态申请一个int类型的空间并初始化为10
	return p;
}
int main()
{
	int* ptr = fun();
	cout << "" << *ptr << endl;
	cout << "" << *ptr << endl;
	delete ptr;//释放空间
	system("pause");
	return 0;
}

1.数据10是开辟在堆区的在程序没有结束之前是由程序员控制
2.指针本质也是局部变量放在栈上指针保存的数据是放在堆区

new还可以申请连续的空间:

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
	int* a = new int[5];
	for (int i = 0; i < 5; i++)
	{
		a[i] = i;
	}
	for (int i = 0; i < 5; i++)
	{
		cout << "" << a[i] << endl;
	}
	delete[] a;
	system("pause");
	return 0;
}

注意:
申请和释放单个元素的空间,使用 new和delete
申请和释放连续的空间,使用new[]和delete[]
注意:匹配起来使用


C&C++的动态开辟的区别

首先我们在介绍一下C语言中malloc开辟动态空间

cpp 复制代码
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
using namespace std;
int* fun()
{
	int* p = (int*)malloc(sizeof(int));//开辟空间
	assert(p);//断言开辟释放成功
	*p = 10;
	return p;
}
int main()
{
	int* ptr = fun();
	printf("%d\n", *ptr);
	printf("%d\n", *ptr);
	free(ptr);//释放空间
	system("pause");
	return 0;
}

C&C++的动态开辟的区别:

相同点:

都是从堆上申请空间,并且需要用户手动释放

不同点:


  1. malloc 和 free 是 函数 , new 和 delete 是 操作符

  1. malloc申请的空间不会初始化,new可以初始化

  1. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
    如果是多个对象,[]中指定对象个数即可

  1. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

  1. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需
    要捕获异常

C++中vector开辟动态数组

cpp 复制代码
template < class T, class Alloc = allocator<T> > class vector

容器的大小:vector是一个动态数组,可以根据需要自动调整大小一 它会根据素的数量动态分配内存空间


vector还可以使用一些功能:


vector增删查改
接口说明
push_back (重点) 尾插
pop_back (重点) 尾删
find 查找(注意这个是算法模块实现,不是vector 的成员接口)
insert 在position 之前插入 val
erase 删除position 位置的数据
swap 交换两个vector 的数据空间
operator[ ] (重点) 像数组一样访问


选代器

vector提供了迭代器,可以用于遍历容器中的元素。可以使用 **begin()**函数获取指向第个元素的迭代器,使用 **end()**函数获取指向最后一个元素之后位置的迭代器


容器大小管理

可以使用 **size()**函数获取vector中元素的数量,使用 empty() 函数检查vector是否为空


元素访问

可以通过索引来访闻vector中的元素。索引从0开始,最后一个元素的索引是 size可以使用[]运算符或 **at()**函数来访元素

接下来我们将介绍vector的常见用法(记得包含头文件**#include <vector>**哦):

vector的初始化(1)

vector开辟5个整型大小的连续空间,未赋初值

<>尖括号为元素类型名,它可以是任何合法的数据类型

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> a(5);//开辟动态数组
	for (int i = 0; i < 5; i++)
	{
		a[i] = i;
	}
	for (int i = 0; i < 5; i++)
	{
		cout << a[i] << " ";
	}
	return 0;
} 

vector的初始化(2)

开辟5个整型大小的空间并赋值为1

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> a(5,1);
	for (int i = 0; i < 5; i++)
	{
		cout << a[i] << " ";
	}
	return 0;
} 

vector的初始化(3)

vector<int> v = { 1,3,5,7,9,2,4,6,8,0 };

可以直接给动态数组赋初值

vector的常见用法(1):push_back

作用:将元素添加到vector的末尾

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v;
	for (int i = 0; i < 10; ++i)
	{
		v.push_back(i);//尾插
	}
	for (int i = 0; i < 10; ++i)
	{
		cout << v[i] << " ";
	}
	return 0;
}
cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(5);
	v.push_back(2);
	v.push_back(8);
	v.push_back(1);
	v.push_back(5);
	for (int i = 0; i < v.size(); i++)//size计算数组的长度
	{
		cout << v[i] << " ";
	}
	return 0;
}

vector的常见用法(2):迭代器

常用于排序

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	vector<int> v = { 1,3,5,7,9,2,4,6,8,0 };
	sort(v.begin(), v.end());
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	return 0;
}

vector的常见用法(3):erase

常用于排序去重

首先,需要对vector进行排序,以便相同的元素相邻。

然后,unique函数将重复的元素移动到vector的末尾,并返回一个指向第一个重复元素的迭代器

最后,可以使用v.erase函数将重复元素从vector中删除

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
	vector<int> v = { 2,1,3,2,4,1,5,4 };
	sort(v.begin(), v.end());            //排序:1 1 2 2 3 4 4 5
	auto rs = unique(v.begin(), v.end());//将重复元素丢在后面:1 2 3 4 5 1 2 4
	v.erase(rs, v.end());                //从第一个重复元素开始到结束的都删除
	for (const auto& num : v)
	{
		cout << num << " ";
	}
	return 0;
}

vector的常见用法(4):empty

常用来检查vector是否为空

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(5);
	v.push_back(2);
	v.push_back(0);
	v.erase(v.begin() + 2);//删除位置3的元素
	if (v.empty())
	{
		cout << "vector为空" << endl;
	}
	else
	{
		cout << "vector不为空" << endl;
	}
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << "\n";
	v.clear();//清空vector中的元素
	if (v.empty())
	{
		cout << "vector为空" << endl;
	}
	else
	{
		cout << "vector不为空" << endl;
	}
	return 0;
}

vector的常见用法(5):find

在任何容器中查找指定元素,返回一个迭代器指向第一个匹配的元素

常用于在一组数据中查找某一元素是否存在

cpp 复制代码
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
    vector<int> v = { 1,3,5,7,9,2,4,6,8,0};
    auto it = find(v.begin(), v.end(), 3);
    if (it != v.end())
        cout << "找到了元素 " << *it << '\n';
    else
        cout << "找不到元素" << *it << '\n';
}

vector的常见用法(6):pop_back

常用于删除末尾元素

cpp 复制代码
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
    vector<int> v = { 1,3,5,7,9,2,4,6,8,0};
    v.pop_back();
    v.pop_back();
    v.pop_back();
    for (int i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    return 0;
}

我们可以清晰的看到末尾的三个元素被删除了

vector的功能很强大,我感觉完全碾压malloc、new但是每个代码都有自己的运用场景

今天我们就介绍到这里啦

祝大家新年快乐 !!!

相关推荐
Ajiang282473530432 分钟前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空36 分钟前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10224 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’5 小时前
C++ list (链表)容器
c++·链表·list
----云烟----6 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024066 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud