Reverse - data structure

string

Source code:

void test(int n) {
	// Sample test, test the function of initializing string object
	string str1 = "hello";
	string str2 = "hello123";
	string str3 = "hello123456";
	string str4 = "hello123456789";
	string str5 = "hello123456789123";
	string str6 = "hello123456789123456";
	string str7 = "hello123456789123456789";
}

int main()
{
	int n = 1;
	scanf_s("%d", &n);
	test(n);
}

Disassembly view  

Now we put ecx in the data window and find that it is filled with CC

  Address after calling constructor    Let's see 00ab560 is the four bytes of the first address of a string

When we came over, we found it was a heap space   Two data (FD is the end of the heap) 0059f880 find that it points to the address of our string, so it may be more convenient for him to find himself

Let's go on

  The length of this string is 0E and the maximum buffer is 0f

  If we continue to expand our string, how will string store our string???

  The length of our string is 11 and the maximum number of bytes stored in the buffer is 1F. The main reason is that the second field is no longer our string and becomes an address  

  Let's go over and save our string  

   So you can define the following structure

struct MyString {
	struct MyString* pSelf;
	union MyUnion
	{
		char szString[16];
		char* pString;
	}u;
	int nStringLen;
	int nMaxStringLen;
};

//Define this structure pointer to operate on it
string str1 = "hello";
MyString* pString = (MyString*)&str1;
	strcpy(pString->u.szString, "hello");
	pString->nStringLen = 9;

CString

It's relatively simple

His object has only four bytes.

Is a pointer to the heap space, where strings are stored. Too simple to look at disassembly

  Come and see our string

list

void testList() {
	// Bidirectional circular linked list, node
	list<int> listObj;

	listObj.push_back(1);
	listObj.push_back(2);
	listObj.push_back(3);
	listObj.pop_back();

	listObj.push_back(4);
}

  First initialization after calling the initialization function

  The list container calls the initialization function twice   Zero for the first time, and there will be data for the second time

  Address after two initialization

  Then push_back a data to see the change

  The number of elements becomes 1. Next, let's look at 00e9cd98 the address of the header of the linked list

  A total of two elements are the precursor and successor of the linked list   We see that the precursors and successors of the linked list point to one place because we have only one element. It can be seen that this is a two-way circular linked list

  Because adding an element doesn't look good, let's add one

  Look, there are two elements in memory, namely, push_back   1 and 2 of

The position of the header is now different from that of the predecessor and successor

  We continued to look along the linked list

  Or the predecessor and successor

2 is our data   Continue backward

It's our data 1. The front is still the predecessor and successor

  Continue back to our header

So the structure is like this

Therefore, the following structure can be defined

struct MyNode
{
	struct MyNode* pNext;
	struct MyNode* pPrev;
	int nData;
};

struct MyList
{
	struct MyList* pSelf;
	struct MyNode* pRoot;
	int nNodeCount;
};
	MyList* pList = (MyList*)&listObj;
	int size = pList->nNodeCount;
	MyNode* pNode = pList->pRoot;
	while (pNode->pNext != pList->pRoot)
	{
		pNode = pNode->pNext;
		int n = pNode->nData;
		printf("element=%d\n", n);
	}

  Vector

void testVector() {
	// Dynamic array, data stored in heap memory
	// When the element changes, the memory will be increased dynamically.
	vector<int> vecObj;

	vecObj.push_back(1);
	vecObj.push_back(2);
	vecObj.push_back(3);
	vecObj.pop_back();
	vecObj.push_back(4);
	vecObj.push_back(5);
	vecObj.push_back(6);
	vecObj.push_back(7);
	//-------------------------------------
	// Traverse vector
	for (size_t i = 0; i < vecObj.size(); i++)
	{
		printf("vecObj[%d] = %d", i, vecObj[i]);
	}

	//-------------------------------------
	// Traverse vector
	vector<int>::iterator iter = vecObj.begin();
	while (iter != vecObj.end())
	{
		int n = *iter;
		printf("vecObj i = %d", n);
		iter++;  // Temporary object generation
		//++iter;//  No temporary objects
	}

}

 

  The second initialization will fill in the pointer to itself

 

  push_back has two elements

  The first is a pointer to yourself

The second is a pointer to the buffer

The third is a pointer to the last byte of the element

The fourth is a pointer to the last byte of the requested buffer

 

  0134e148 is the first two elements 1 and 2 of the array address   The last two pointers in the figure above point to the position of FD  

 

  Add a data in

  After adding a data, it is found that the buffer used to put the data has been released  

 

The buffer for the second field of our dynamic array has also changed position

We can guess that in push_back, dynamically apply for new space and copy the data.

If the space is insufficient, apply for a new and larger space and copy the original data in.

Pop is executed again_ back

We see that the pointer to the last element of the array has changed because there are fewer array elements

  In fact, the data is still there, but it changes the pointer, that is, the valid data are 1 and 2

  Continue to add 4 5 6 7  

For the current dynamic array structure, let's look at the location where 0134F4E8 stores data

  The last two pointers in the figure above point to the last byte of the valid element and the last byte of the valid buffer respectively

The structure is like this

  You can define this structure

struct MyVector
{
	struct MyVector* pSelf;
	int* pDataStart;
	int* pDataEnd;
	int* pBufEnd;
};
	// Define structure, operate vector
	MyVector* pVector = (MyVector*)&vecObj;
	int size = ((int)pVector->pDataEnd - (int)pVector->pDataStart) / sizeof(int);
	for (size_t i = 0; i < size; i++)
	{
		//pVector->pDataStart[i] = 3;
		int n = pVector->pDataStart[i];
		printf("element=%d\n", n);
	}

 

Next, let's look at the traversal dynamic array. We look at the source code. It will call three functions, one is size, and the other is [] operation symbol overload

There is also a printf ordinary loop traversal

	// Traverse vector
	for (size_t i = 0; i < vecObj.size(); i++)
	{
		printf("vecObj[%d] = %d", i, vecObj[i]);
	}

  Next, look at iterator traversal

	//-------------------------------------
	// Traverse vector
	vector<int>::iterator iter = vecObj.begin();
	while (iter != vecObj.end())
	{
		int n = *iter;
		printf("vecObj i = %d", n);
		iter++;  // Temporary object generation
		//++iter;//  No temporary objects
	}

Twice initialization   Let's look at memory

0134E0E0 points to two four byte data

The first four bytes point to the address of the vector

The second four bytes point to itself

00000000 useless

0134f4e8 points to the buffer where the data is stored

  Let's go to 0134e0e0 and have a look

Let's look at 0134F4E8, which is the data we store

 

  So the structure is like this

 

Added by mattison on Sun, 28 Nov 2021 12:59:11 +0200