We can use the inverse examples of dynamic arrays to determine the characteristics of dynamic arrays. We all know that the following method is to define a static array.
int iCount[10];int iCount[10][10];
As can be seen from the above, after defining a static array, no matter whether the program makes this array, the size of the space occupied by the array in the memory remains unchanged.
We can conclude that for the compiler, the size and space of the static array are known, so the compiler can automatically allocate space for the array. The specific situation is: if you define a global array, the compiler will allocate a space for your array in the data area; if it is a local array (such as defined in a certain number of records ), the compiler allocates a Stack space for your array.
From the discussion of static arrays, we can get the characteristics that dynamic arrays should have: in the running of programs, the dynamic array size should be variable. Because the implementation of some dynamic groups should be based on dynamic memory allocation. The following is an example:
Suppose we create a database for factory workers. Multiple tables in the database represent different workshops. Each table stores information about employees in the workshop. To make the code simple, you can only let the database Save the employee's name.
The following is an InputWorkers function. enter the name of the employee in the workshop as the unit, and store the data in the database at one time.
Void InputWorkers () {int iCountOfWorkers, int iNo ;...... Enter the number of persons in the workshop and the number of persons in the workshop ...... String * iArray = new string [iCountOfWorkers];…… The user enters information about all employees in the workshop and the information is stored in the iArray ...... StoreInDatabase (iArray, iNo); // save it to the database delete [] iArray ;}
In the program, iArray is a string pointer, not an array. However, the principle of arrays is the same as that of pointers. For example, p [1] is the second element in the exponent group p, but in actual addressing, p + 1 is used. So we can use iArray [1] in this way.
The iArray in InputWorkers allocates space of different sizes based on the total number of workers in the workshop. In this sense, iArray implements the dynamic array function.
If iArray is defined as a static array, the size of iArray is fixed. Therefore, we must estimate the maximum number of persons in the workshop.
string iArray[100];
Static arrays are faster than dynamic arrays. In theory, the stack speed is faster than the heap speed. However, if we decide to use dynamic arrays, we will consider space saving. In addition, pay attention to the cost caused by changes to the static array ceiling. We must reset the upper limit to solve the bug and re-compile the program. If you can control program compilation, this is okay. However, you have to update the program for every user. Users without updates can encounter this bug. With this in mind, you will not be happy.
You may say that if I set a larger limit, the possibility of exceeding it will be very small, and the memory waste will not be much. For example, if there are at most 200 people in one workshop and at least 100 people in one workshop, it will only waste 100 space. At present, the memory of the machine does not care about such a waste of space. Yes. You can do this, but proceed to the further discussion.
Now we want to store the names of all employees in a two-dimensional array. Each row in the array represents a workshop, and each row contains the employee's name. Think about it. If static arrays are used, you will waste a lot of space. In addition, you need to add an upper limit for the number of workshops. This example is not good, because the number of workshops in the factory should be deterministic. But from another perspective, if I only need several workshops or all workshops, do you still stick to them?
After talking about the above, I just discussed the usage of dynamic arrays. In reality, especially in large software systems, dynamic arrays are widely used. In addition, arrays are implemented in various libraries of C ++. By calling corresponding class functions, you can add/delete elements in the array. In addition, two-dimensional dynamics can be achieved through nesting. These classes or class templates are easy to use. For example:
CAtlArray <int> iArray; iArray [0] = 1; // error. iArray does not contain the iArray element. add (1); // element 2 iArray [0] = 1; // Yes, iArray has one iArray [0] = 1; // error, iArray has only one element.
After reading the above, you will find it annoying. Every time you expand an array, you must use a function Add. But programmers will get used to it. We will think that this should be the price for dynamic arrays. Think about the two-dimensional array, and the Add action will make you very uncomfortable. You will miss the static Array Operation Method and use iArray [10] = 10 directly, as long as the defined upper limit is 10. Next, I will discuss the implementation of this method.
First, we hope to have such a one-dimensional array:
CDynamic1Dim <int> m_dim; // the size of m_dim is 1.
Then execute the following statement:
m_dim[4] = 710;
The m_dim size is 5.
How can I make m_dim [4] = 710 without errors when the array has only one element and increase the array size to make the statement successful? The simplest method is to overload the operator [] operator. Next we will discuss the implementation details.
template<typename T>class Dynamic1Dim{public: Dynamic1Dim(); ~Dynamic1Dim(); T& operator[](int index);protected: bool EnlargeDim(int iSize);public: T* m_pBuf; int m_iSize;};
The above defines a template class Dynamic1Dim <T>. The constructor is as follows:
// -------------------------------------------------- // Constructor template <typename T> Dynamic1Dim <T >:: Dynamic1Dim () {// One T-type object of the initial size of the array // allocate a piece of memory. Its size is the space occupied by the T-type class m_pBuf = (T *) malloc (sizeof (T); // create a T-type object in the memory space new (m_pBuf) T (); m_iSize = 1 ;}
In the initial function, we set the default length of the array to 1. When you use the statement m_dim [4] = 710, the overloaded operator is called.
// ------------------------------------------------ // Operator [] template <typename T> T & Dynamic1Dim <T>: operator [] (int index) {// If the subscript is negative, throw an exception if (index <0) throw std: out_of_range ("Index shouldn \ t be negative"); // check whether the subscript exceeds the array size, if this parameter is exceeded, EnlargeDim is called to expand the array. if (index> m_iSize-1) EnlargeDim (index + 1); Return m_pBuf [index];} // ------------------------------------------------ // Enlargetemplate <typename T> bool Dynamic1Dim <T>: EnlargeDim (int iSize) {// re-allocate a memory, the size of the expanded T-type array m_pBuf = (string *) realloc (m_pBuf, sizeof (T) * iSize ); // create a T-type array object in the extended part of the memory space and call its default constructor for (int I = m_iSize; I <iSize; I ++) {new (& m_pBuf [I]) T ();} m_iSize = iSize; return true ;}
The above code has basically met the requirements for a dynamic one-dimensional array. However, you must be careful when releasing the array space. The dynamic allocated space must be released in the Dynamic1Dim destructor.
// -------------------------------------------------- // Destructortemplate <typename T> Dynamic1Dim <T> ::~ Dynamic1Dim () {// call the T class destructor for (int I = 0; I <m_iSize; I ++) {m_pBuf [I]. ~ T () ;}// release the memory free (m_pBuf );}
Note: m_pElem [I]. ~ T () is necessary, because T objects may also have memory allocation. Without such a statement, the memory allocated to the T object cannot be released, which is also the cause of many memory leaks.
The above code implements a dynamic one-dimensional array template. Finally, we will discuss the implementation of a dynamic two-dimensional array.
We hope to have such a two-dimensional array:
CDynamic2Dim <int> m_dim; // the size of m_dim is 1*1.
Then execute the following statement:
m_dim[1][3] = 33;m_dim[4][10] = 710;
At this time, the m_dim size is: 0, 2, and 3 rows have only one element, one row has four elements, and four rows have 11 elements. We can imagine that a dynamic two-dimensional array is composed of an indefinite number of dynamic one-dimensional arrays. Based on this idea, let's take a look at the implementation of dynamic two-dimensional arrays.
template<typename T>class Dynamic2Dim{public: Dynamic2Dim(); ~Dynamic2Dim(); Dynamic1Dim<T>& operator[] (int index);protected: bool EnlargeY(int nYSize);private: int m_iYSize; Dynamic1Dim<T>* m_pYBuf; Dynamic1Dim<T> m;};
The initial two-dimensional array should be 1*1, so the Dynamic2Dim constructor should be as follows:
// Constructortemplate<typename T>Dynamic2Dim<T>::Dynamic2Dim(){ m_iYSize = 1; m_pYBuf = (Dynamic1Dim<T>*) malloc(sizeof(Dynamic1Dim<T>)); m_pYElem = new(m_pYBuf) Dynamic1Dim<T>();}
Release the allocated memory space in the Destructor:
// Desctructortemplate<typename T>Dynamic2Dim<T>::~Dynamic2Dim(){ for(int i = 0; i < m_iYSize; i++) { m_pYElem[i].~Dynamic1Dim(); } free(m_pYBuf);}
It must be a dynamic two-dimensional array overload operator []. Its implementation is as follows:
// operator[] overloadtemplate<typename T>Dynamic1Dim<T>& Dynamic2Dim<T>::operator[] (int index){ if(index < 0) throw std::out_of_range("negative index!"); if(index > m_iYSize - 1) EnlargeY(index + 1); return m_pYElem[index];}
As we can see from the above, what is implemented here is the vertical expansion of the two-dimensional array, that is, the first subscript of the Two-dimensional array determines whether to expand the two-dimensional array. Here