动态数组详解Dynamic Arrays

来源:互联网 发布:微信扫码支付java开发 编辑:程序博客网 时间:2024/05/22 10:47

Arrays are simplistic yet extremely powerful data structures. Their basic limitation is their size normally has to be determined at compile time, not run time. A standard array also cannot change its size while an application is running.

The linked list data structure was designed to get around the limitations of an array -- specifically the ability to define its size at run time and to be able to add or remove elements in the list as the application required it. Linked lists, however, carry with them their own baggage, including coding complexity and inherent confusion by most beginning programmers.

C and C++, however, provide a alternative approach to the data structure that is implemented in most programming languages using linked lists. It is called a dynamic array. This is an array whose size can be determined at run time. In addition, it is also possible to change the size of a dynamic array at run time,giving you basically the best of both worlds: the expandability features of the linked list, and the ease of use of an array.

Defining a Dynamic Array

You define a dynamic array as a pointer to the data structure. It can be as simple as an integer:
int *array1;

Or it can be a more complicated structure:
struct RECORD {  char name[20+1];  char address[40+1];  int dependents;  float salary;  };RECORD *array2;

RunTime Allocation of a Dynamic Array

When you determine what size you would like the dynamic array to be, it is then that you can allocate the memory for it. In C, you would use the malloc() function, while in C++ you can use the new operator. The general syntax for both are:
arrayname = (type *) malloc (numberOfElements * sizeof(type));arrayname = new type [numberOfElements];

In the program example below, we'll ask the user to specify the size he would like the array to be, and then allocate the array accordingly:
int *da;int numElements;cout << "Enter number of elements: " << flush;cin >> numElements;da = (int *) malloc (numElements * sizeof(int));da = new int [numElements];

NOTE that you must use new when you want to dynamically allocate an array of a class, since new will call the class' constructor method, while malloc() will not.

Referencing Elements in Dynamic Arrays

This is the part I like the best. To reference an element in a dynamic array, you use exactly the same notation that you use to reference a static array. Each element can be referenced using the bracketed notation.

In the code below, we've assumed the user specified he wants four elements in the dynamic array. This therefore allocates index positions of 0, 1, 2, and 3. We can assign and reference these positions in the following way:
da[0] = 16;da[1] = 7;da[2] = -3;da[3] = 5;

The following picture shows how this dynamic array appears in memory:

One further note on the dynamic array referencing notation:
Since a dynamic array begins as a pointer,if we want to, we can use the standard pointer dereferencing notation in order to access each element in the dynamic array. The general form of this notation is:

*(name + elementPosition)

So, in the example above, to assign a value to index 2 in the dynamic array, you could say the following:
*(da + 2) = -3;


I don't know about you, but da[2] sure seems easier.

Freeing Space Assigned to a Dynamic Array

In many instances (especially in the old DOS and Windows 3.1 environment), in order to conserve the use of memory, the use of memory in dynamic structures (whether they are linked lists or arrays) should be released before a program terminates.

For dynamic arrays, you would use the free (dynamicArrayPtr); instruction for arrays allocated with malloc(), while for arrays allocated with new, you should usedelete [] dynamicArrayPtr;. Examples are shown below:

int *da1;float *da2;da1 = (int *) malloc (10 * sizeof(int));da2 = new float [10];// ... Do whatever with the arraysfree (da1);delete [] da2;

NOTE that the use of malloc()/free() and new/delete can happily coexist in the same program, as long as you don't intermix them.

Dynamically Reallocateable Arrays

Dynamic arrays (as we've shown them) already provide a very powerful capability to a programmer, and this feature alone can dramatically affect how an application would be designed. Linked lists, however, still have the advantage that they can grow (shrink) in size after they are initially allocated, depending upon the demands of the application.

Using the basis of the dynamic array that we've already seen, C goes beyond the malloc() function and provides the realloc() function. This gives us the ability to change the size of a dynamic array, AND properly maintain any data that has already been loaded into it.

Here is the general syntax for the realloc() function:

arrayname = (type *) realloc (arrayname,newsize * sizeof(type));

Using the da dynamic array from the previous example, let's increase its size from 4 integers to 6 -- and we want to make sure the original four values are unaffected by the increase in size. Here is the call to realloc():
da = (int *) realloc (da,6 * sizeof(int));

This is what memory will look like when realloc() is finished:

The following graphic shows the actual steps that realloc() is using to
increase the dynamic array's size:


NOTE that:

C++ does not have an equivalent function for realloc() that can be used with new
To gain this capability, you would have to perform these four steps yourself, making sure your object had the proper method to handle copying its internal data values to the new version.

Here is an example program showing the simple use of a dynamically reallocateable array. The user is prompted for a series of integer values until he enters 0. These values are added to the dynamic array, as the numbers are entered, increasing the size of the array as it goes. It will then print the contents of the array, and then free it.

Also NOTE that the very first allocation is not considered a special case. We don't have to use malloc() the first time. If the pointer is initially set to NULL, realloc()acts the same as malloc().

#include <cstdlib>#include <iostream>using namespace std;#define dountilbreak  while (1)int main (void) {  int *intarray = NULL;  int num, numValues = 0;  dountilbreak {  // Build the dynamic array    cout << "Enter num (0 to stop): " << flush;    cin >> num;    if (num == 0) break;    intarray = (int *) realloc (intarray,                          (numValues+1) * sizeof(int));    intarray[numValues++] = num;    }  // Print the array  for (int i=0; i < numValues; i++)    cout << intarray[i] << endl;  // Finally, free the array  free (intarray);    return 0;}

Generalizing Dynamically Reallocateable Arrays

The technique shown previously works great for simple structures, such as arrays of integers or floats. This approach, however, doesn't work quite as nicely for more complicated structures, especially if you plan to manipulate the array in various ways, such as: deleting elements or rearranging them.

Forstructuresthat have a varying size (such as an array of strings), the dynamic array approach won't work unless you force each element to allocate the same amount of space -- the basic rule that each element in an array has to be thesame size still holds for reallocateable arrays as well.

To eliminate the varying size problem, the technique uses a dynamic array of pointers to the data structure in question, rather than a dynamic array of the actual data structures. This makes it so when the dynamic array has to be manipulated,you are simply working with pointers, which are fixed in size and small in comparison to the actual data. The graphic below shows the appearance of the generalized dynamic reallocateable array:

All you declare is a pointer that will point to the dynamic array of pointers. When you add an element to the array, you now need two steps:

  1. You increase the size of the array of pointers;
  2. You dynamically allocate an element and assign its address to the new element in the array of pointers
Here is the generalized sequence of instructions to add an element:
array = (type **) realloc (array,(numElements+1) * sizeof(type *));array[numElements] = (type *) malloc (sizeof(type));Load array[numElements] with datanumElements++;

Here is an example using a dynamic array of strings:
#include <cstdlib>#include <iostream>#include <string>using namespace std;int main (void) {  char **strarray = NULL;  int i, numStrings = 0;  char line[80+1];    while (1) {  // Build the dynamic array of strings    cout << "Enter a string (Enter to stop): " << flush;    cin.getline(line,80);    if (strlen(line) == 0) break;        strarray = (char **) realloc (strarray,                            (numStrings+1) * sizeof(char *));    strarray[numStrings++] = strdup(line);    }      // Display the array  for (i=0; i < numStrings; i++)    cout << strarray[i] << endl;      // Free the array: You MUST delete each individual   //   string before you delete the array of pointers  for (i=0; i < numStrings; i++)    free (strarray[i]);  free (strarray);    return 0;}

Now we show an example that uses a more complicated structure:
#include <cstdlib>#include <iostream>using namespace std;struct RECORD {  char name[30+1];  char address[40+1];  float salary;  };int main (void) {  int numElements = 0;  RECORD rec, **recarray = NULL;  FILE *infile = fopen("infile.dat","rb");  while (!feof(infile)) { // Load the array of records    fread (&rec,1,sizeof(REC),infile);    if (feof(infile)) break;    recarray = (RECORD **) realloc                        (recarray,(numElements+1) * sizeof(RECORD *));    recarray[numElements] = (RECORD *) malloc (sizeof(RECORD));    *recarray[numElements++] = rec;    }  fclose (infile);  // Display the values loaded  for (int i=0; i < numElements; i++)    cout << recarray[i]->name << endl;  return 0;}

When trying to create a dynamic array of object classes in C++, you still can use the realloc() function for the array of pointers to the object class, yet new will need to be used for the allocation of the class itself in order for the constructor method to be called. Here is an example demonstrating this:
#include <cstdlib>using namespace std;class DEMO {  ...};DEMO **array = NULL;int num = 0;while (1) {    array = (DEMO **) realloc (array,(num+1) * sizeof(DEMO *));  array[num++] = new DEMO;    // To reference a method in one of the classes  array[index]->method();    }

原文地址:http://www.cse.unt.edu/~donr/courses/4410/dynamicArrays/dynamicArrays.html

原创粉丝点击