滴水逆向笔记系列-c++总结4-41.new-delete-vector-42.链表
第四十课 c++8 new-delete-vector
1.内存空间复习
2.跟踪调试反汇编函数
我们调用malloc
函数申请内存,但是不是malloc一个函数完成整个申请内存的操作的,一般在系统内层层调用一些函数,比如检测内存之类的一系列才做后,最后才能完成申请内存的操作,所以我们可以反汇编后看看具体是哪个函数做了申请内存的操作
比如下面有两个函数,我们想看看哪个函数做了申请内存的操作,我们直接盯着p的地址看看f10步过哪个函数时内存被申请了,发生了变化,哪个函数就是,这样子一层层找进去
疑问:
这里课程里面是先编译运行一次找出p指针的地址,然后再重新反汇编一次,盯着刚刚找出的p指针的地址,看看步过哪个函数内存空间发生了变化就可以定位了,但是我在本机,每次编译反汇编后的p指针地址都不一样,根本没办法去定位
而且除了上面的imp_malloc,后面跟进去的call都没写函数名字,不知道是不是vs的问题
跟到最后其实是调用了windows的api**HeapAlloc**
去申请的内存空间,只是我们通过库函数帮我们去调用了这个windows api,比较方便,当然我们也可以直接调用这个api去申请内存,只是比较麻烦需要设置一些参数
图中的间接call,其实不是call 0042d16c这个地址,而是call 0042d16c这个地址里面的值,也就是IAT表
追进去后看到地址已经到了dll的领空了
3.new-delete
其实new就和上面演示的malloc一样,只不过new更方便点,他们底层反汇编看最后都是调用windows的apiheapmalloc
示例代码
int* pi = new int(5);
//在堆创建一个int对象的内存空间,初始值为5int* p = new int[5];
//在堆创建五个int对象的内存空间,没有初始值person* pp = new person[5];
//在堆创建五个person类型对象的内存空间
4.vector
作业
1、实现一个Vector类
2、读懂每一个方法的反汇编实现
1、
#define SUCCESS 1 // 成功
#define ERROR -1 // 失败
#define MALLOC_ERROR -2 // 申请内存失败
#define INDEX_ERROR -3 // 错误的索引号
template <class T_ELE>
class Vector
{
public:
Vector();
Vector(DWORD dwSize);
~Vector();
public:
DWORD at(DWORD dwIndex,OUT T_ELE* pEle); //根据给定的索引得到元素
DWORD push_back(T_ELE Element); //将元素存储到容器最后一个位置
VOID pop_back(); //删除最后一个元素
DWORD insert(DWORD dwIndex, T_ELE Element); //向指定位置新增一个元素
DWORD capacity(); //返回在不增容的情况下,还能存储多少元素
VOID clear(); //清空所有元素
BOOL empty(); //判断Vector是否为空 返回true时为空
VOID erase(DWORD dwIndex); //删除指定元素
DWORD size(); //返回Vector元素数量的大小
private:
BOOL expand();
private:
DWORD m_dwIndex; //下一个可用索引
DWORD m_dwIncrement; //每次增容的大小
DWORD m_dwLen; //当前容器的长度
DWORD m_dwInitSize; //默认初始化大小
T_ELE *m_pVector; //容器指针
};
template <class T_ELE>
Vector<T_ELE>::Vector()
:m_dwInitSize(100),m_dwIncrement(5)
{
//1.创建长度为m_dwInitSize个T_ELE对象
//2.将新创建的空间初始化
//3.设置其他值
}
template <class T_ELE>
Vector<T_ELE>::Vector(DWORD dwSize)
:m_dwIncrement(5)
{
//1.创建长度为dwSize个T_ELE对象
//2.将新创建的空间初始化
} //3.设置其他值
template <class T_ELE>
Vector<T_ELE>::~Vector()
{
//释放空间 delete[]
}
template <class T_ELE>
BOOL Vector<T_ELE>::expand()
{
// 1. 计算增加后的长度
// 2. 申请空间
// 3. 将数据复制到新的空间
// 4. 释放原来空间
// 5. 为各种属性赋值
}
template <class T_ELE>
DWORD Vector<T_ELE>::push_back(T_ELE Element)
{
//1.判断是否需要增容,如果需要就调用增容的函数
//2.将新的元素复制到容器的最后一个位置
//3.修改属性值
}
template <class T_ELE>
DWORD Vector<T_ELE>::insert(DWORD dwIndex, T_ELE Element)
{
//1.判断是否需要增容,如果需要就调用增容的函数
//2.判断索引是否在合理区间
//3.将dwIndex只后的元素后移
//4.将Element元素复制到dwIndex位置
//5.修改属性值
}
template <class T_ELE>
DWORD Vector<T_ELE>::at(DWORD dwIndex,T_ELE* pEle)
{
//判断索引是否在合理区间
//将dwIndex的值复制到pEle指定的内存
}
//其他函数。。自己实现
注意:**
- 一般容器比较大,创建容器不会在全局变量区和栈里创建,所以我们使用指针接收,容器就会被分配在堆上
- 构造函数不小心重复声明了变量,害我调试了半小时md
实现代码:
#include<windows.h>
#define SUCCESS 1 // 成功
#define ERROR -1 // 失败
#define MALLOC_ERROR -2 // 申请内存失败
#define INDEX_ERROR -3 // 错误的索引号
template <class T_ELE>
class Vector
{
public:
Vector();
Vector(DWORD dwSize);
~Vector();
public:
DWORD at(DWORD dwIndex, OUT T_ELE* pEle); //根据给定的索引得到元素
DWORD push_back(T_ELE Element); //将元素存储到容器最后一个位置
VOID pop_back(); //删除最后一个元素
DWORD insert(DWORD dwIndex, T_ELE Element); //向指定位置新增一个元素
DWORD capacity(); //返回在不增容的情况下,还能存储多少元素
VOID clear(); //清空所有元素
BOOL empty(); //判断Vector是否为空 返回true时为空
VOID erase(DWORD dwIndex); //删除指定元素
DWORD size(); //返回Vector元素数量的大小
private:
BOOL expand();
private:
DWORD m_dwIndex; //下一个可用索引
DWORD m_dwIncrement; //每次增容的大小
DWORD m_dwLen; //当前容器的长度
DWORD m_dwInitSize; //默认初始化大小
T_ELE* m_pVector; //容器指针
};
template <class T_ELE>
Vector<T_ELE>::Vector()
:m_dwInitSize(100), m_dwIncrement(5)
{
//1.创建长度为m_dwInitSize个T_ELE对象
T_ELE* m_pVector = new T_ELE[m_dwInitSize];
//2.将新创建的空间初始化
memset(m_pVector,0,sizeof(T_ELE) * m_dwInitSize);
//3.设置其他值
m_dwIndex = 0;
m_dwLen = m_dwInitSize;
}
template <class T_ELE>
Vector<T_ELE>::Vector(DWORD dwSize)
:m_dwIncrement(5)
{
//1.创建长度为dwSize个T_ELE对象
m_pVector = new T_ELE[dwSize];
//2.将新创建的空间初始化
memset(m_pVector, 0, sizeof(T_ELE) * dwSize);
//3.设置其他值
m_dwIndex = 0;
m_dwLen = dwSize;
}
template <class T_ELE>
Vector<T_ELE>::~Vector()
{
//释放空间 delete[]
delete[] m_pVector;
m_pVector = NULL;
}
template <class T_ELE>
BOOL Vector<T_ELE>::expand()
{
DWORD dwLenTemp = 0;
T_ELE* pTemp = NULL;
// 1. 计算增加后的长度
dwLenTemp = m_dwLen + m_dwIncrement;
// 2. 申请空间
pTemp = new T_ELE[dwLenTemp];
// 3. 将数据复制到新的空间
memcpy(pTemp, m_pVector, sizeof(T_ELE)*m_dwLen);
// 4. 释放原来空间
delete[] m_pVector;
m_pVector = pTemp;
pTemp = NULL;
// 5. 为各种属性赋值
m_dwLen = dwLenTemp;
return SUCCESS;
}
template <class T_ELE>
DWORD Vector<T_ELE>::push_back(T_ELE Element)
{
//1.判断是否需要增容,如果需要就调用增容的函数
if ( m_dwIndex >= m_dwLen )
{
expand();
}
//2.将新的元素复制到容器的最后一个位置
memcpy(&m_pVector[m_dwIndex], &Element, sizeof(T_ELE));
////3.修改属性值
m_dwIndex++;
return SUCCESS;
}
template <class T_ELE>
DWORD Vector<T_ELE>::insert(DWORD dwIndex, T_ELE Element)
{
//1.判断是否需要增容,如果需要就调用增容的函数
if (m_dwIndex >= m_dwLen)
{
expand();
}
//2.判断索引是否在合理区间
if (dwIndex < 0 || dwIndex >= m_dwLen)
{
return INDEX_ERROR;
}
//3.将dwIndex只后的元素后移
T_ELE* pTmp = m_pVector + dwIndex;
T_ELE* pTmp1 = m_pVector + dwIndex + 1;
memcpy(pTmp1,pTmp,sizeof(T_ELE)*(m_dwLen-dwIndex));
//4.将Element元素复制到dwIndex位置
memcpy(pTmp,&Element,sizeof(T_ELE));
//5.修改属性值
m_dwIndex++;
}
template <class T_ELE>
DWORD Vector<T_ELE>::at(DWORD dwIndex, T_ELE* pEle)
{
//判断索引是否在合理区间
if (dwIndex < 0 || dwIndex >= m_dwLen)
{
return INDEX_ERROR;
}
//将dwIndex的值复制到pEle指定的内存
memcpy(pEle,&m_pVector[dwIndex],sizeof(T_ELE));
}
void TestVector()
{
//Vector<int>* pVector = new Vector<int>;
Vector<int>* pVector = new Vector<int>(5);
pVector->push_back(1);
pVector->push_back(2);
pVector->push_back(3);
pVector->push_back(4);
pVector->insert(2,6);
int x = 0;
pVector->at(2,&x);
}
int main()
{
TestVector();
}
第四十一课 c++9 链表
感觉这节课没什么记的,老老实实慢慢写代码自己调试
特点:
1、数据分散存储
2、查询性能没有Vector?好
3、新增与删除的性能好于Vector
4、内存动态分配在堆里,所以删除元素时记得释放内存
5、链表在析构时需要多次delete
6、链表在构造时不用定义长度了,需要的时候在new
7、定义节点结构体的时候地址的类型就是节点结构体的指针类型
作业
完善下面代码
#define SUCCESS 1 // 执行成功
#define ERROR -1 // 执行失败
#define INDEX_IS_ERROR -2 // 错误的索引号
#define BUFFER_IS_EMPTY -3 // 缓冲区已空
template <class T_ELE>
class LinkedList
{
public:
LinkedList();
~LinkedList();
public:
BOOL IsEmpty(); //判断链表是否为空 空返回1 非空返回0
void Clear(); //清空链表
DWORD GetElement(IN DWORD dwIndex,OUT T_ELE& Element); //根据索引获取元素
DWORD GetElementIndex(IN T_ELE& Element); //根据元素获取链表中的索引
DWORD Insert(IN T_ELE Element); //新增元素
DWORD Insert(IN DWORD dwIndex, IN T_ELE Element); //根据索引新增元素
DWORD Delete(IN DWORD dwIndex); //根据索引删除元素
DWORD GetSize(); //获取链表中元素的数量
private:
typedef struct _NODE
{
T_ELE Data;
_NODE *pNext;
}NODE,*PNODE;
PNODE GetIndexCurrentNode(DWORD dwIndex); //获取索引为dwIndex的指针
PNODE GetIndexPreviousNode(DWORD dwIndex); //获取索引为dwIndex的前一个节点指针
PNODE GetIndexNextNode(DWORD dwIndex); //获取索引为dwIndex的后一个节点指针
private:
PNODE m_pList; //链表头指针,指向第一个节点
DWORD m_dwLength; //元素的数量
};
//无参构造函数 初始化成员
template<class T_ELE> LinkedList<T_ELE>::LinkedList()
:m_pList(NULL),m_dwLength(0)
{
}
//析构函数 清空元素
template<class T_ELE> LinkedList<T_ELE>::~LinkedList()
{
Clear();
}
//判断链表是否为空
template<class T_ELE> BOOL LinkedList<T_ELE>::IsEmpty()
{
0 1 2 3 4 5
}
//清空链表
template<class T_ELE> void LinkedList<T_ELE>::Clear()
{
// 1. 判断链表是否为空
// 2. 循环删除链表中的节点
// 3. 删除最后一个节点并将链表长度置为0
}
//根据索引获取元素
template<class T_ELE> DWORD LinkedList<T_ELE>::GetElement(IN DWORD dwIndex,OUT T_ELE& Element)
{
// 1. 判断索引是否有效
// 2. 取得索引指向的节点
// 3. 将索引指向节点的值复制到OUT参数
}
//根据元素内容获取索引
template<class T_ELE> DWORD LinkedList<T_ELE>::GetElementIndex(IN T_ELE& Element)
{
// 1. 判断链表是否为空
// 2. 循环遍历链表,找到与Element相同的元素
}
//在链表尾部新增节点
template<class T_ELE> DWORD LinkedList<T_ELE>::Insert(IN T_ELE Element)
{
// 1. 判断链表是否为空
// 2. 如果链表中已经有元素
}
//将节点新增到指定索引的位置 0 1 2 3 4
template<class T_ELE> DWORD LinkedList<T_ELE>::Insert(IN DWORD dwIndex, IN T_ELE Element)
{
// 1. 判断链表是否为空
// 2. 判断索引值是否有效
// 3. 如果索引为0
// 4. 如果索引为链表尾
// 5. 如果索引为链表中
}
//根据索引删除节点
template<class T_ELE> DWORD LinkedList<T_ELE>::Delete(IN DWORD dwIndex)
{
// 1. 判断链表是否为空
// 2. 判断索引值是否有效
// 3. 如果链表中只有头节点,且要删除头节点
// 4. 如果要删除头节点
// 5. 如果是其他情况
}
//获取链表中节点的数量
template<class T_ELE> DWORD LinkedList<T_ELE>::GetSize()
{
}
//获取dwIndex前面节点的地址
template<class T_ELE>
LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexPreviousNode(DWORD dwIndex)
{
// 就是一个循环
}
//获取dwIndex节点的地址
template<class T_ELE>
LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexCurrentNode(DWORD dwIndex)
{
// 就是一个循环
}
//获取dwIndex后面节点的地址
template<class T_ELE>
LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexNextNode(DWORD dwIndex)
{
// 就是一个循环
}
注意:
- insert插入函数中可以先创建一个节点对象,把我们的参数元素赋值给节点对象,插入的时候直接把节点对象的地址赋值给链表即可
- 遍历链表时需要注意
for (int y = 0; y < m_dwLength-1; y++)
,因为只有一个值、第二个值想插入的时候,是不需要遍历的,直接给第一个值的pNext元素赋值第二个值的地址即可 - 最后三个私有函数有报错解决不了
#include <windows.h>
#include <stdio.h>
#define SUCCESS 1 // 执行成功
#define ERROR -1 // 执行失败
#define INDEX_IS_ERROR -2 // 错误的索引号
#define BUFFER_IS_EMPTY -3 // 缓冲区已空
template <class T_ELE>
class LinkedList
{
public:
LinkedList();
~LinkedList();
public:
BOOL IsEmpty(); //判断链表是否为空 空返回1 非空返回0
void Clear(); //清空链表
DWORD GetElement(IN DWORD dwIndex, OUT T_ELE& Element); //根据索引获取元素
DWORD GetElementIndex(IN T_ELE& Element); //根据元素获取链表中的索引
DWORD Insert(IN T_ELE Element); //新增元素
DWORD Insert(IN DWORD dwIndex, IN T_ELE Element); //根据索引新增元素
DWORD Delete(IN DWORD dwIndex); //根据索引删除元素
DWORD GetSize(); //获取链表中元素的数量
private:
typedef struct _NODE
{
T_ELE Data;
_NODE* pNext;
}NODE, * PNODE;
PNODE GetIndexCurrentNode(DWORD dwIndex); //获取索引为dwIndex的指针
PNODE GetIndexPreviousNode(DWORD dwIndex); //获取索引为dwIndex的前一个节点指针
PNODE GetIndexNextNode(DWORD dwIndex); //获取索引为dwIndex的后一个节点指针
private:
PNODE m_pList; //链表头指针,指向第一个节点
DWORD m_dwLength; //元素的数量
};
//无参构造函数 初始化成员
template<class T_ELE> LinkedList<T_ELE>::LinkedList()
:m_pList(NULL), m_dwLength(0)
{
}
//析构函数 清空元素
template<class T_ELE> LinkedList<T_ELE>::~LinkedList()
{
Clear();
}
//判断链表是否为空
template<class T_ELE> BOOL LinkedList<T_ELE>::IsEmpty()
{
if (m_pList == NULL)
{
return 1;
}
else
{
return 0;
}
}
//清空链表
template<class T_ELE> void LinkedList<T_ELE>::Clear()
{
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
printf("链表为空\n");
}
else {
// 2. 循环删除链表中的节点
NODE* pList = m_pList;
NODE* pDeleteList = NULL;
for (int i = 0; i < m_dwLength; i++)
{
pDeleteList = pList;
pList = pList->pNext;
delete pDeleteList;
}
// 3. 删除最后一个节点并将链表长度置为0
delete pList;
m_dwLength = 0;
}
}
//根据索引获取元素
template<class T_ELE> DWORD LinkedList<T_ELE>::GetElement(IN DWORD dwIndex, OUT T_ELE& Element)
{
// 1. 判断索引是否有效
if (dwIndex <0 || dwIndex > m_dwLength)
{
return INDEX_IS_ERROR;
}
// 2. 取得索引指向的节点
NODE* pCList = m_pList;
for (int i = 0; i < dwIndex; i++)
{
pCList = pCList->pNext;
}
// 3. 将索引指向节点的值复制到OUT参数
Element = pCList->Data;
return SUCCESS;
}
//根据元素内容获取索引
template<class T_ELE> DWORD LinkedList<T_ELE>::GetElementIndex(IN T_ELE& Element)
{
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
return BUFFER_IS_EMPTY;
}
// 2. 循环遍历链表,找到与Element相同的元素
int Index = 0;
NODE* pCList = m_pList;
for (int i = 0; i < m_dwLength; i++)
{
if (pCList->Data == Element)
{
Index = i;
}
else
{
pCList = pCList->pNext;
}
}
return Index;
}
//在链表尾部新增节点
template<class T_ELE> DWORD LinkedList<T_ELE>::Insert(IN T_ELE Element)
{
NODE* pNewList = new NODE;
memset(pNewList, 0, sizeof(NODE));
memcpy(pNewList,&Element, sizeof(T_ELE));
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
m_pList = pNewList;
m_dwLength++;
return SUCCESS;
}
else {
// 2. 如果链表中已经有元素
NODE* pCList = m_pList;
for (int y = 0; y < m_dwLength-1; y++)
{
pCList = pCList->pNext;
}
pCList->pNext = pNewList;
m_dwLength++;
return SUCCESS;
}
return SUCCESS;
}
//将节点新增到指定索引的位置 0 1 2 3 4
template<class T_ELE> DWORD LinkedList<T_ELE>::Insert(IN DWORD dwIndex, IN T_ELE Element)
{
NODE* pNewList = new NODE;
memset(pNewList, 0, sizeof(NODE));
memcpy(pNewList, &Element, sizeof(T_ELE));
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
if (dwIndex == 0)
{
m_pList = pNewList;
m_dwLength++;
return SUCCESS;
}
return INDEX_IS_ERROR;
}
// 2. 判断索引值是否有效
if (dwIndex <0 || dwIndex > m_dwLength)
{
return INDEX_IS_ERROR;
}
// 3. 如果索引为0
if (dwIndex == 0)
{
pNewList->pNext = m_pList;
m_pList = pNewList;
m_dwLength++;
return SUCCESS;
}
// 4. 如果索引为链表尾
NODE* pCList = m_pList;
for (int i = 0; i < m_dwLength - 1; i++)
{
pCList = pCList->pNext;
}
pCList->pNext = pNewList;
m_dwLength++;
// 5. 如果索引为链表中
}
//根据索引删除节点
template<class T_ELE> DWORD LinkedList<T_ELE>::Delete(IN DWORD dwIndex)
{
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex <0 || dwIndex > m_dwLength)
{
return INDEX_IS_ERROR;
}
// 3. 如果链表中只有头节点,且要删除头节点
if (m_pList->pNext == NULL && dwIndex == 0)
{
delete m_pList;
m_dwLength--;
return SUCCESS;
}
// 4. 如果要删除头节点
if (dwIndex == 0)
{
NODE* pTempList = m_pList;
m_pList = m_pList->pNext;
delete pTempList;
m_dwLength--;
return SUCCESS;
}
else// 5. 如果是其他情况
{
NODE* pNList = m_pList;
GetIndexPreviousNode(dwIndex)->pNext = GetIndexCurrentNode(dwIndex)->pNext;
delete GetIndexCurrentNode(dwIndex);
m_dwLength--;
}
}
////获取链表中节点的数量
//template<class T_ELE> DWORD LinkedList<T_ELE>::GetSize()
//{
//
//}
//获取dwIndex前面节点的地址
template<class T_ELE>
LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexPreviousNode(DWORD dwIndex)
{
// 就是一个循环
NODE* pCList = m_pList;
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex <0 || dwIndex > m_dwLength)
{
return INDEX_IS_ERROR;
}
for (int i = 0; i < dwIndex - 1; i++)
pCList = pCList->pNext;
return pCList;
}
//获取dwIndex节点的地址
template<class T_ELE>
LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexCurrentNode(DWORD dwIndex)
{
// 就是一个循环
NODE* pCList = m_pList;
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex <0 || dwIndex > m_dwLength)
{
return INDEX_IS_ERROR;
}
for (int i = 0; i < dwIndex ; i++)
pCList = pCList->pNext;
return pCList;
}
//获取dwIndex后面节点的地址
template<class T_ELE>
LinkedList<T_ELE>::PNODE LinkedList<T_ELE>::GetIndexNextNode(DWORD dwIndex)
{
// 就是一个循环
NODE* pCList = m_pList;
// 1. 判断链表是否为空
if (IsEmpty() == 1)
{
return BUFFER_IS_EMPTY;
}
// 2. 判断索引值是否有效
if (dwIndex <0 || dwIndex > m_dwLength)
{
return INDEX_IS_ERROR;
}
for (int i = 0; i < dwIndex + 1; i++)
pCList = pCList->pNext;
return pCList;
}
void TestList()
{
int a ;
int y = 0;
LinkedList<int>* pLinkedList = new LinkedList<int>;
pLinkedList->Insert(3);
pLinkedList->Insert(4);
pLinkedList->Insert(5);
pLinkedList->Insert(6);
/*pLinkedList->GetElement(3, a);
printf("GetElement:%x",a);*/
//pLinkedList->GetElementIndex(y);
pLinkedList->Clear();
}
int main()
{
TestList();
return 0;
}