資料結構逆向分析-Vector

這個應該是家喻戶曉了的東西把,如果說C/C++程式設計師Vector都不用的話,可能就是一個不太好的程式設計師。

Vector就是一個STL封裝的動態陣列,陣列大家都知道是通過連續的地址空間來處理的,vector的原理就是如果原來的不夠了要擴充套件,就會開闢一段更大的記憶體,然後將原來的內容再複製到新的記憶體裡面,釋放掉原來的,然後再插入要擴充的。

Vector常用Api:

push_bak()  //尾部插入資料
Insert() //插入資料


pop_back() //刪除尾部資料
erase() //刪除資料

逆向分析:

插入資料

尾部插入

首先是最簡單的,一直往裡面插入資料

#include<iostream>
#include<vector>
using std::vector;

int main()
{
vector<int> MyVector;
MyVector.push_back(100);
MyVector.push_back(600);
MyVector.push_back(200);
MyVector.push_back(300);
MyVector.push_back(1000);
MyVector.push_back(150);


return 0;
}

一個只建立了的vector的大小隻有16

然後通過記憶體來檢視:

指向的這個地址:

又指回去了。

畫個圖就是這個樣子:

跑第一條插入資料的指令:

    MyVector.push_back(100);

記憶體變成了這樣:

這個vector指向的內容還是沒有改變。

然後新加入了三個挨著的地址:

目前的情況來看,應該是vector的第二個內容是陣列的首地址,然後第三第四個內容是陣列的結束地址。

執行:

    MyVector.push_back(600);

變成了這樣:

比較奇怪的是,如果是後面兩個欄位表示陣列的結束地址,為什麼會要兩個欄位來存放,一個就夠了呀,肯定有問題,所以我這裡多push幾個,且觀察這兩個欄位有沒有值不一樣的情況出現。

當執行完第五個push_back的時候終於變化了:

檢視一下我們這個MyVector的資料結構:

capacity是指不再分配記憶體的情況下容器的容量,然後size是指容器當前存放了的大小。再對比我們在記憶體中的情況,那麼很有可能就是size就是第三個欄位地址減去第二個欄位陣列首地址,然後除以結構體大小得到的內容,而capacity容器大小就是最後一個欄位和第二個欄位陣列首地址之間的差值。

再往下執行一個看看:

    MyVector.push_back(150);

破案了,就是我們想的那樣,vector會開闢一段空間,然後往裡面加內容,如果超過了容器大小再重新開闢一個。

任意位置插入資料:

紅色表示資料改動過,其實就是相當於往後移動,然後再插入進去,就是正常C語言裡面會有的動態陣列的操作。

刪除資料

尾部刪除

這裡你會發現,用尾刪除的辦法來說,並沒有刪除掉這塊地址,只是把範圍往上移動了。

任意位置刪除:

這裡也沒有刪除,只是把後面往前移動了,然後vector的陣列大小又縮小:

實質陣列大小和容器大小是不一樣的

總結

vector就是一個封裝好了動態陣列,裡面採取的還是C裡面的動態陣列的思想,只不過引入了容器大小的概念用的時候稍微會比純C動態陣列效率高。