Contents  1-5  6-11  12-16  17-21  22-27   28-33  34 - 38  39-46  Projects   MFC

   Contact
   Search
   C
   C++
   Visual Basic
   Java
   JavaScript
   DHTML
   Style Sheets
   About
   Active X
   TDC Binding
   PHP
   Perl and CGI
   Flash
   XML
   SQL
   Messages
   Chat
   MCSE
   Linux
   Cabling   
   ActionScript
   Downloads
   E-Cards   
 
    
    

An array is a collection of data storage locations, each of which hold the same type of data.  As an analogy, let's travel
back to the golden era of the glorious seventies :) and revel in one of the miracles of modern plastics.  A time of
wonderful, colorful music and cool, colorful polyester and shirts with giant collars.  The age of muscle cars and gas
rationing.  Lava lamps and disco techs.  Oh blissful childhood that I had,  how my soul has been stirred with affection for those days!  Or is it nausea?

"With each passing year, because of advances in computer technology, there are more things,
each more sophisticated, that we aren't allowed to do any more.
" - Paul Lutus

My mother used to host Tupperware  parties, and had purchased a considerable amount of Tupperware items.  So let's use them as an example.  If a standard variable could be represented as a Tupperware container, for which we can use to store objects of the right type, then an array would be a series of those containers capable of storing the same type of object.  Tupperware containers were well-built for storing objects of a certain type - it was nothing short of miraculous the way they could keep a sandwich fresh for lunch!  Some could store single sandwiches or servings of casserole, but the really cool Tupperware containers were those that could store an entire meal - a series of objects. 

These colorful, catchy containers consisted of a series of smaller compartments which could hold all of the different items of yesterday's leftovers.  It was like making your own frozen entrees (at that time they were referred to as TV dinners), except that it was made with real food that actually tasted good.  This was especially appealing to me at the time, since I had an obsessive compulsion about my food not touching other types of food.  As interesting as this historical digression into the time of Tupperware
past may be, let us return to the time of Tupperware present and continue our discussion about arrays . . .

Arrays contain a series of objects that are indexed by a subscript.  The index-referenced storage location of each item is known as an element of the array.  Arrays can be composed of pre-defined data types such as integers, floats, and doubles or they can be composed of user-defined objects such as Monsters, Mammals, Employees, etc.  The important thing to remember is that arrays must contain objects of the SAME TYPE, not different types.  A string object is actually an array of ASCII char variables, so using a char array is synonymous with using string objects.

We declare an array by writing the type followed by the array name and then subscript.  The subscript is the number of elements in the array surrounded by square brackets.  This subscript becomes a reference and a handle for manipulating the object stored at its location.  Example:
long AReallyBigArray[25]; declares an array of 25 long integers.  The name of this array is AReallyBigArray.  The compiler sets aside enough memory to hold all 25 elements.  Since each long int requires 4 bytes, this sets aside 100 bytes of memory!  Bam!  Kick it up a notch.

Perhaps you are wondering what the hype is concerning arrays.  Perhaps groups of objects are things that you take for granted - multiple instances of a class.  But arrays warrant further consideration, my friend.  Arrays become incredibly powerful when combined with looping, repetition, and decision structures.  They can be use to create binary and linear searches, all kinds of recursion, and limitless useful algorithms, subroutines and functions.  They can become a very quick method of populating memory with instances of an object.

You access each of the array elements by referring to an offset from the array name.  Array elements are counted from 0, therefore, the first array element is arrayName[0].
 AReallyBigArray[25] would be numbered from 0-24, not 1-25.  This creates a situation where a common mistake is often made by programmers.  Many times our code syntax may be fine, and our projects will compile.  But they will not perform as expected.  We encounter logic errors, rather than syntax errors, and our programs do not behave as expected.  This results many times from an array out of bounds error, often referred to as an "off by one" or  "fencepost" error.  This is somthing to watch for.   To declare an array of 5 integers and fill each with a value, you would simply write the array name and type followed by the subscript for its number of elements:

#include <iostream.h>

int main()
{
    int myArray[5];

    for(int i=0; i<5; i++)
// 0-4
    {
         cout << "Value for myArray[" << i << "]: ";
         cin >> myArray[i];
    }

    for(i = 0; i<5; i++)
        cout << i << ": " << myArray[i] << "\n";

    return 0;
}
Output:
value for myArray[0]: 3
value for myArray[1]: 6
value for myArray[2]: 9
value for myArray[3]: 12
value for myArray[4]: 15
0: 3
1: 6
2: 9
3: 12
4: 15

In this example, the array myArray is declared to hold 5 int variables.  A loop is established that counts from 0 through 4, the proper set of offsets for a 5 element array.  The user is prompted for a value and the value is saved at the correct offset into the array, storing the value in the corresponding array element.  Remember: Arrays count from 0, not 1, so a 10-element array counts from 0-9.

When you write a value to an element in an array, the compiler stores the value based on the size of each element and indexes it by the subscript. If you tried to write to
AReallyBigArray[50] in the array AReallyBigArray[25], the compiler would ignore that there is no such element.  It computes how far past the 1st element it should look , in this case 200 bytes, and writes over whatever data is stored there.  This causes crashes and unpredictable errors - rather than syntax, we are speaking of logic errors, the more difficult kind to debug.  Don't forget:

fence post error - error resulting from writing to 1 past the end of an array. (You need 11 posts for a 10-foot fence.)

Initializing an array - To initialize an array, after the array name place an = sign and a list of comma separated values enclosed in braces:
int IntegerArray[5] = {10, 20, 30, 40, 50 }; declares IntegerArray to be an array of 5 integers.   It assigns the value 10 to IntegerArray[0], the value 20 to IntegerArray[1] and so forth.  If you OMIT the size of the array you will get one just big enough to hold the initialization.  Example:  int IntegerArray[] = {10, 20, 30, 40, 50 }; behaves exactly as the previous array, though the compiler determines the array size.  If you need to know the size of an array, ask the compiler to compute it for you by:

 const USHORT IntegerArrayLength = sizeof(IntegerArray)/sizeof(IntegerArray[0]);

This sets USHORT IntegerArrayLength to the size of the entire array, divided by the size of each individual entry in the array.  You may then display or use this value.

It is important to note that you cannot initialize more elements than you have declared for an array:  Using an example, writing the expression:
int IntegerArray[5] = {10, 20, 30, 40, 50, 60}; , would create a compile time error since you've declared a 5 member array, yet you have initialized 6 values.  Though we can not assign more elements than declared, we are permitted to assign less.  The following expression: int IntegerArray[5] = {10, 20}; is acceptable.  If you don't initialize an array member, its value is set to 0.

Arrays of objects - to access member data in an array of objects you must do 2 things:
1) Identify the member of the array by using the index operator([ ])
2) Add the member operator (.) or (->), depending on whether access is direct or indirect the particular member variable. Example:

//An array of objects
#include <iostream.h>
class Monster
{
      public:
      Monster() { itsAge = 1; itsWeight=5; }   
//default constructor
      ~Monster() {}                            
//destructor

     
//Accessor methods
      int GetAge() const { return itsAge; }
      int GetWeight() const { return itsWeight; }
      void SetAge(int age) { itsAge = age; }

      private:
      int itsAge;
      int itsWeight;
};

//------------------------------------------------------------------------------------------------------------------

int
main()
{
   
//Create an array of Monster objects.
    Monster MotleyCrew[5];

    int i;

   
//The following will count up on odd numbers
    for(i = 0; i < 5; i++)
        MotleyCrew[i].SetAge(2*i + 1);

    for(i = 0; i < 5; i++)
        cout << "Monster #" << i+1<< ": " << MotleyCrew[i].GetAge() << endl;

    return 0;
}

Output: 
Monster #1: 1
Monster #2: 3
Monster #3: 5
Monster #4: 7
Monster #5: 9


The example above declares the Monster class.  It must have a default constructor so that Monster objects can be created in an array.  The first for loop sets age of each of the 5 Monsters in array.  The algorithm will count up by odd numbers by multiplying each loop iteration by 2 and then adding 1.  The second for loop accesses each member of the array and calls GetAge() vis the dot operator and array subscript, since access is direct in this case.  If we were dealing with the indirection of pointers or references, we would have to use -> in this case.  Again, notice that each individual Monster's GetAge() method is called by accessing the appropriate element in the array MotleyCrew[i] followed by the dot operator (.) and the name of member function.

Multidimensional arrays - In multi dimensional arrays, each dimension is represented as a separate subscript in the array.  A two dimensional array has two subscripts, a three dimensional array has three subscripts, and so on.  Using our chess game example, in a class named SQUARE, to create a two dimensional 64 square array, you'd write
SQUARE Board[8][8]; , which is the same as writing SQUARE Board[64].  In chess, when the game begins, the king is located in the 4th position of the 1st row. Counting from 0, that position corresponds to Board[0][3]; where the first subscript corresponds to row and the second subscript to column.  In this way we can employ an (x,y) coordinate system.

Multidimensional arrays are great for coding database tables.  In a two dimensional array, one dimension can represent rows and the other columns.  To initialize a multidimensional array, assign the list of values to the array elements in corresponding order, with the last array subscript changing while each of the former subscripts hold steady.  If you have
int theArray[5][3];  the first 3 elements go into the theArray [0][x], the next 3 into theArray[1][x] and so on in sets of 3 done 5 distinct times.  You could initialize this array by writing:

 int theArray[5][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};.

To make things clearer, you could group the initializations with nested braces like:

int theArray[5][3] = { {1, 2, 3,},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12},
{13, 14, 15} };

The compiler ignores the inner braces, they simply make this easier to read.  This illustrates more clearly that we are assigning our objects to 5 sets of 3 objects each, for a total of 15.  Each value must be separated by a comma, and the entire set must be enclosed in braces and must end in a semicolon.  Listed elow is a two dimensional array.  The first dimension is the set of numbers from 0 to 5.  The second dimension consists of the double of each value that was stored in the first dimension:

#include <iostream.h>
int main()
{
    int SomeArray[5][2] = { {0,0}, {1,2}, {2,4}, {3,6}, {4,8}};
    for(int i = 0; i<5; i++) {
        for(int j=0; j<2; j++)
        {
            cout << "SomeArray[" << i << "][" << j << "]: ";
            cout << SomeArray[i][j]<< endl;
        }
//end 2nd loop
    }
//end 1st loop

    return 0;
}
Output:
SomeArray[0][0]: 0
SomeArray[0][1]: 0
SomeArray[1][0]: 1
SomeArray[1][1]: 2
SomeArray[2][0]: 2
SomeArray[2][1]: 4
SomeArray[3][0]: 3
SomeArray[3][1]: 6
SomeArray[4][0]: 4
SomeArray[4][1]: 8

After declaring the multi-dimensional array, SomeArray, we dive into a nested for loop.  The first for loop that iterates 5 times corresponds to the first subscript of the array.  The second for loop that iterates twice accesses the second subscript of the array.  In this way, for each iteration of the first loop, the second loop will iterate 2 times.  This becomes the foundation for accessing and manipulating the data stored in multidimensional arrays.  

Parallel Arrays - Parallel arrays consist of two or more arrays with data or objects that have a relationship.  the elements inthe arrays are grouped together by this relationship.  Recall that a string is an array of type char, so to hold an array of 5 strings we could create a multidimensional array of chars.  The array, People[5][20], would therefore hold 5 strings of up to 20 char's each.  If we combine these 5 strings with 5 ages, the data contained within the two arrays has a relationship, therefore they are parallel arrays.  Example:

//A Parallel Array
#include <iostream.h>

void main() {

     char People[5][20] = { "Harry", "Susie", "Sally", "Charles", "Drew" };
     int ages[5] = { 15, 24, 13, 34, 35 };

     for(int x = 0; x < 5; x++) {

         cout << People[x] << " is " << ages[x] << endl;

     }
}

Output:
Harry is 15
Susie is 24
Sally is 13
Charles is 34
Drew is 35

When we declare an array, the compiler sets aside memory for all its objects, even if you never use them.  This isn't a problem when you know how many objects you need, but when you don't, you must use more advanced data structures such as pointers and references to create objects on the heap (free store).  By declaring objects on the free store and storing only a pointer to the object in an array, you can leave the limited constraint of stack memory and use free store memory which is far larger.  This greatly reduces amount of stack memory used.  It also increases efficiency because you can iterate, search and recurse indexed memory locations rather than entire objects.  Example:

#include <iostream.h>

//------------------------------------------------------------------------------------------------------------------

class Monster
{
      public:
      Monster() { itsAge = 1; itsWeight=5; }
      ~Monster() {}

    
 //Accessor methods
      int GetAge() const { return itsAge; }
      int GetWeight() const { return itsWeight; }
      void SetAge(int age) { itsAge = age; }

      private:
      int itsAge;
      int itsWeight;
};

//------------------------------------------------------------------------------------------------------------------

int main()
{
   
//Create an array of 500 pointers to Monster objects
    Monster *ArmyOfDarkness[500];
   
    int
x;
   
   
//Create a pointer to a Monster object
    Monster *MonsterPointer;
 
    for(x = 0; x < 500; x++)
    {
     
   //Create a new Monster object on the heap and point to it with MonsterPointer
        MonsterPointer = new Monster;
        MonsterPointer->SetAge(2*x + x);

       
//Copy the object pointed to by MonsterPointer to the corresponding pointer element of the array
        ArmyOfDarkness[x] = MonsterPointer;
    }

    for(x = 0; x < 500; x++)
        cout << "Monster #" << x+1 << ": " << ArmyOfDarkness[x]->GetAge() << endl;

    return 0;
}
Output:
Monster #1: 1
Monster #2: 3
Monster #3: 5
Monster #4: 7
... and so on and so on . . .
Monster #499: 997
Monster #500: 999

This illustrates an array of 500 pointers to Monster objects.  In this example, a Monster object is declared.  The array , ArmyofDarkness[500],  is declared to hold 500 pointers to Monster objects.  In the first initial loop, 500 new Monster objects are created on free store, and each has its age set to 2 times the number of the loop iteration plus 1.   In this way, ages ascend by odd numbers, so that the first Monster is 1, the second 3, the 3rd 5, and so on and so on.  Then a pointer is added to the array.  Because the array has been declared to hold pointers, the pointer rather than the dereferenced value of the pointer, is added to the array. 
Finally, the second for loop prints each of the values.  The pointer is accessed by the index,
ArmyOfDarkness[x] and that address is used to access the GetAge() method.  The array, ArmyOfDarkness[500], and all its pointers, are stored on the stack but the 500 Monsters that are created using "new" are stored on the free store(heap).

We can also create an array declaring arrays on the free store - you can place an entire array on the free store(heap).  To do this, call "new" and use the subscript operator.  The result is a pointer to an area on the free store that holds the array.  In the first example, we had an array of 500 pointers to Monster objects on the heap.  In this next example, we will create a single pointer to an array of 500 Monster objects on the heap.  Example: 

Monster *MotleyCrew = new Monster[500];

This declares MotleyCrew to be a pointer to the first element in an array of 500 Monsters.  MotleyCrew points to, that is it has the address of, MotleyCrew[0].  The advantage of this is that you can use pointer arithmetic to access each member of MotleyCrew.  Example:

Monster *MotleyCrew = new Monster[500];
Monster *MonsterPointer = MotleyCrew;           
//MonsterPointer points to MotleyCrew[0]
MonsterPointer ->SetAge(10);               
      //set MotleyCrew[0] to 10
MonsterPointer++;                           
     //advance to element MotleyCrew[1]
MonsterPointer->SetAge(20);               
        //set MotleyCrew[1] to 20

This declares a new array of 500 Monsters on the heap and a pointer that points to the start of the array.  Using that pointer, the first Monster's SetAge() function is called with the value 10.  The pointer is then incremented to point to the next Monster, and the second Monster's SetAge() method is then called.   Observe:

A pointer to an array versus an array of pointers - Observe the differences:

1)
Monster MonsterMashOne[500];                                           //this is an array of 500 Monsters on the free store.
2)
Monster *MonsterMashTwo[500];                                     //this is an array of 500 pointers to Monsters. 
3)
Monster *MonsterMashThree = new Monster[500];           //this is a single pointer to an array of 500 Monsters on the heap. 

The differences among these three different types of arrays dramatically affect how they operate.  The address of MonsterMashThree is the address of the first item that array, which is the same case for MonsterMashOne. MonsterMashThree is only a variant of MonsterMashOne, but very different from MonsterMashTwo

An array name is a const pointer to the first element of the array.  In the declaration
Monster MotleyCrew[50]; , MotleyCrew is a pointer to  &MotleyCrew[0] .  It is legal to use array names as const pointers and vice versa, so MotleyCrew + 4 is a legitimate way of accessing the data at MotleyCrew[4] . The compiler does all the arithmetic when adding, incrementing and decrementing pointers.  The address accessed when writing Family+4 isn't 4 bytes past the address of Family, it is 4 objects.  If each object is 4 bytes long, then Family+4 is 16 bytes. Below is an example of declaring and using an array on the free store:

#include <iostream.h>

//------------------------------------------------------------------------------------------------------------------

class Monster
{
      public:
      Monster() { itsAge = 1; itsWeight=5; }
      ~Monster();

      //Accessor methods
      int GetAge() const { return itsAge; }
      int GetWeight() const { return itsWeight; }
      void SetAge(int age) { itsAge = age; }

      private:
      int itsAge;
      int itsWeight;
};


Monster :: ~Monster()
{
   cout << "Destructor called!\n";
}

//------------------------------------------------------------------------------------------------------------------

int main()
{
    Monster *CookieMonster = new Monster[500];

    int i;

    Monster *MonsterPointer;


    for(i = 0; i < 500; i++)
    {
        MonsterPointer = new Monster;

        MonsterPointer->SetAge(2*i +1);
        CookieMonster[i] = *MonsterPointer;

        delete MonsterPointer;
    }


   for(i = 0; i < 500; i++)
       cout << "CookieMonster #" << i+1 << ": " << CookieMonster[i].GetAge() << endl;

   delete [] CookieMonster;

   return 0;
}
 
Output:
CookieMonster #1: 1
CookieMonster #2: 3
CookieMonster #3: 5
CookieMonster #4: 7
... and so on and so on . . .
CookieMonster #499: 997
CookieMonster #500: 999

The example above declares the array CookieMonster, which holds 500 Monster objects.  The entire array is created on the free store with the call to new Monster[500] .  Each Monster object added to the array is also created on the free store(heap).  The pointer to the object isn't added to the array this time, the object itself is.  This isn't an array of pointers to Monsters, it is an array of Monsters on the heap pointed to by a single pointer - CookieMonster.  Memory consumed by the entire array is cleared with "delete".

Deleting arrays on the free store - CookieMonster is a pointer to the array of Monster objects on the free store.  The pointer, MonsterPointer, is dereferenced and the Monster object itself is stored in the array (the array is on the free store, not the stack, so why not?)  MonsterPointer is used again in the next iteration of the loop.  Isn't there a danger that there will now be no pointer to the Monster object and a memory leak will occur? This would be a problem, but deleting the single pointer, CookieMonster, frees all the memory set aside for the array of 500 Monster objects on the heap.  The compiler destroys each object on the array and restores its memory to the free store.  To see this, change the size of the array from 500 to 10, then re-compile and run the program.  Then uncomment the cout statement in the destructor implementation.  When the end of main is reached and the array is destroyed, each Monster object destructor is called. 

Note: When you create an item on the heap by using "new", you always delete the item and free its memory with "delete".  Likewise, when you create an array using "new + class + [size]", you must delete the array and free all its memory with "delete[ ]".  The brackets signal to the compiler that this entire array is being deleted.  If you leave the brackets off, only the first object in the array will be deleted.  The others will continue to exist and consume memory.

String - a series of characters, an array of variables of type char.  Example of an unnamed string constant: 
cout << "Hello world.\n";  This brings us to char arrays.  In C++, a string is an array of chars ending with a null character.  You declare and initialize a string as you do any other array:  char Greeting[ ] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' }; The last character '\0', is the null character, which many functions recognize as the terminator for the string.  So each character in a char array is stored in a separate element.  You can use a shorthand mode to auto-allocate: char Greeting[ ] = "Hello World";  You don't need to add the null character, the compiler adds it for you.  The string "Hello World" is 12 bytes.  Hello is 5, the space is 1, and World is 5.  Don't place more into the buffer than there is room for.  Example:

#include <iostream.h>
int main()
{
    char buffer[80];
    cout << "Enter the string: ";
    cin >> buffer;
    cout << "Here's the buffer: " << buffer << endl;

    return 0;
}

Output:
Enter the string: Hello World
Here's the buffer: Hello


Above, the char array, buffer[80], is declared to hold 80 characters, large enough for a 79 character string and the additional terminating null character.  The user prompted to enter a string.  The user-entered string is entered into the buffer[80].  It is the syntax of cin to write a terminating null to the buffer after it writes the string. 

There are two outstanding problems here.  First, if user enters more than 79 characters, cin writes past the end of the buffer and will overwrite what they previously entered.  Second, if the user enters a space, cin thinks it is the end of the string and stops writing to the buffer[].  To solve these problems, call a special method on cin - get().  The method cin.get() takes 3 parameters:

1) The buffer to fill
2) The max # of characters to get
3) The delimiter that terminates input. (The default delimiter is newline.)

#include <iostream.h>
int main()
{
    char buffer[80];
    cout << "Enter the string: ";

    cin.get(buffer, 79);       
//get up to 79 or newline

    cout << "Here's the buffer: " << buffer << endl;

    return 0;
}

Output:
Enter the string: Hello World
Here's the buffer: Hello World


Here buffer is again declared.  For input, a call to the method  cin.get() is placed.  The array declared buffer[] is passed in as the first argument. The number of characters, 79, is passed in as the second argument.  For the 3rd argument, there is no need to provide a terminating character because the default value of "newline" is sufficient.   Now let's look a t a few String class functions:

strcpy() - The strcpy() method copies the entire contents of one string into a designated buffer.  To use strcpy(), remember that you must include the string.h header file into your source code.  Example:

#include <iostream.h>
#include <string.h>

int main()
{
    const int MaxLength = 80;

    char String1[] = "Fun with LEGOS!";

    char String2[MaxLength+1];

    strcpy(String2,String1);

    cout << "String1: " << String1 << endl;
    cout << "String2: " << String2 << endl;

    return 0;
}

Output:
String1: Fun with LEGOS!
String2: Fun with LEGOS!

In this example, the method strcpy() takes 2 character arrays, the destination to copy to followed by the source being copied from.  If the source were larger than the destination, strcpy would overwrite past the end of the buffer.  To protect against this, the standard library string.h includes the method strncpy().

strncpy() - The strncpy() method takes the maximum number of characters to copy, and copies up to the first null character or to the max # of characters specified in the destination buffer.  Example:

#include <iostream.h>
#include <string.h>
int main()
{
    const int MaxLength = 80;

    char String1[] = "Fun with LEGOS!";

    char String2[MaxLength+1];

    strncpy(String2,String1,MaxLength);

    cout << "String1: " << String1 << endl;
    cout << "String2: " << String2 << endl;

    return 0;
}

Output:
String1: Fun with LEGOS!
String2: Fun with LEGOS!


Let's list some of these "string" char array functions:
1) cin.get() - captures a whole line of input, including spaces.
2) strcpy() - copies one string to another.
3) strncpy() - copies up to a specified length of a string. 
4) getline() - captures a whole line of input, including spaces.

String classes - standard component of a class library.  C++ inherited strcpy() and strncpy() from C, but they don't fit into object oriented programming philosophy as well as string class methods.  A String class provides an encapsulated, hidden set of data and functions. 

Note:  It is worth noting the limitation that all arrays, char arrays included, are static.  A good String class should be dynamic and allocate only as much memory as it needs: always enough, yet not too much.  If it can't allocate enough memory, it should fail gracefully. 

Search Routines Using Arrays

Remember that part about arrays and loops possessing vast search capabilities?  Let's look at some examples.  The first is a typical linear search.  In this example, we will cycle through all the elements in an array, looking for a particular item until we find it: 

//A linear search routine using arrays

#include <iostream.h>

//------------------------------------------------------------------------------------------------------------------
int LinearSearch(int *ArrayPointer, int key, int NItems) { int n; for(n=0; n<NItems; ++n) if (ArrayPointer[n] == key) return n; return -1; } //------------------------------------------------------------------------------------------------------------------
void SearchInputAndValidate(int *ArrayPointer, int NumItems) {
     int ValueToSearchFor;
     int ArrayElement;
     cout << "Enter a number between 1 and " << NumItems << ":  ";
     cin >> ValueToSearchFor;
     ArrayElement = LinearSearch(ArrayPointer, ValueToSearchFor, NumItems);
    
     if(ArrayElement != -1)
          cout << "Found value in element " << ArrayElement << ".\n\n";
     else
          cout << "Sorry, value not found.\n\n";
}

//------------------------------------------------------------------------------------------------------------------
void main() {
     int x;
     int NumberOfItems;
     NumberOfItems = 100;
     int *ArrayOfIntegers = new int[NumberOfItems];
     
     //Populate Array with even integer values from 0 to 198
     for(x=0; x<NumberOfItems; ++x) {
            ArrayOfIntegers[x] = 2 * x; }
     SearchInputAndValidate(ArrayOfIntegers, NumberOfItems);
     
}  // close main()

In this next example we use a binary search algorithm, in which case we continuously halve the range where we look for our value.  While not impressive on a small scale, on a large scale this would dramatically reduce the amount of time it takes to search through elements in an array.  In a linear search, element 999,999 in a 1,000,000 elements array would only be found after searching through 999,998 elements, as the loop iterates scanning the elements one by one.  In a binary search, 1,000,000 elements would be split into two sets: one set = 1 - 500,000 and the other set = 500,001 - 1,000,000.  The item being searched for would then be compared to both ranges and depending on its relationship (< or >), one of the half ranges would be selected and it would in turn be halved and so on and so on.  In this way, we could reach item 999,998 in a few dozen or so iterations, rather than 999,999.  Example:

//A binary search using arrays

#include <iostream.h>

//------------------------------------------------------------------------------------------------------------------
int BinarySearch(int *ArrayPointer, int key, int NItems) { int n; int High = NItems; int Low = -1; int Range; while(High-Low > 1) { Range = (High + Low) / 2; if(ArrayPointer[Range] > key) High = Range; else Low = Range; } //end while loop if(Low == -1 || ArrayPointer[Low] != key) return -1; else return Low; } //close function //------------------------------------------------------------------------------------------------------------------
void SearchInputAndValidate(int *ArrayPointer, int NumItems) {
     int ValueToSearchFor;
     int ArrayElement;
     cout << "Enter a number between 1 and " << NumItems << ":  ";
     cin >> ValueToSearchFor;
     ArrayElement = BinarySearch(ArrayPointer, ValueToSearchFor, NumItems);
    
     if(ArrayElement != -1)
          cout << "Found value in element " << ArrayElement << ".\n\n";
     else
          cout << "Sorry, value not found.\n\n";
}

//------------------------------------------------------------------------------------------------------------------
void main() {
     int x;
     int NumberOfItems;
     NumberOfItems = 100;
     int *ArrayOfIntegers = new int[NumberOfItems];
     
     //Populate Array with even integer values from 0 to 198
     for(x=0; x<NumberOfItems; ++x) {
         ArrayOfIntegers[x] = 2 * x; }
     SearchInputAndValidate(ArrayOfIntegers, NumberOfItems);
     
}  // close main()

More multi-dimensional array examples:
 

// Multidimensional Array
#include <iostream>

using namespace std;

int main()
{

    int sales[6][2] = {{12000, 10000},
                       {45000, 56000},
                       {32000, 42000},
                       {67000, 23000},
                       {24000, 12000},
                       {55000, 34000}};

    int row = 0;
    int DomesticSales = 0;
    int InternationalSales = 0;

    while(row < 6)
    {
        DomesticSales = DomesticSales + sales[row][0];
        InternationalSales = InternationalSales + sales[row][1];
        row = row + 1;
    }

    cout << "Total domestic sales: $" << DomesticSales << endl;
    cout << "Total international sales: $" << InternationalSales << endl;
    cout << "Total sales: $" << DomesticSales + InternationalSales << endl;

    return 0;
}

 

//Calculates highest score on midterm and final
#include <iostream>
using namespace std;

int main()
{
    int scores[10][2] = {  {98, 99}, {67, 54}, {78, 43},
                           {90, 86}, {88, 56}, {78, 56},
                           {87, 88}, {72, 96}, {44, 67},
                           {66, 34}  };

    int row = 0;
    int col = 0;
    int midHigh = 0;
    int finalHigh = 0;

    midHigh = scores[0][0];
    finalHigh = scores[0][1];

    while(row < 10)
    {
         col = 0;
//reset column subscript

         while(col < 2)
         {
             if(scores[row][0] > midHigh)
                midHigh = scores[row][col];


             if(scores[row][1] > finalHigh)
                finalHigh = scores[row][col];

             col = col + 1;   
//update column subscript
         }
//end 2nd while

         row = row + 1;
          //update row subscript

    }
//end 1st while

    cout << "Highest score earned on midterm: " << midHigh << endl;
    cout << "Highest score earned on final: " << finalHigh << endl;

    return 0;
}


Let's determine our gas mileage:

 

// Calculating gas mileage
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
   const int MAX = 20;                     // Maximum number of values
   double gas[ MAX ];                      // Gas quantity in gallons
   long miles[ MAX ];                      // Odometer readings
   int count = 0;                          // Loop counter
   char indicator = 'y';                   // Input indicator
   while( (indicator == 'y' || indicator == 'Y') && count < MAX ) 
   {
      cout << endl
           << "Enter gas quantity: ";
      cin >> gas[count];                        // Read gas quantity
      cout << "Enter odometer reading: ";
      cin >> miles[count];                      // Read odometer value
	  ++count;
      cout << "Do you want to enter another(y or n)? ";
      cin >> indicator;      
   }
   if(count <= 1)                          // count = 1 after 1 entry completed -  
   {                                       // we need at least 2.
      cout << endl
           << "Sorry - at least two readings are necessary.";
      return 0;
   }
   // Output results from 2nd entry to last entry
   for(int i=1; i < count; i++)            
   cout << endl
        << setw(2) << i << "."                 // Output sequence number
        << "Gas purchased = " << gas[ i] << " gallons" // Output gas
        << " resulted in "                     // Output miles per gallon
        << (miles[i] - miles[i-1])/gas[i] << " miles per gallon.";
   cout << endl;
   return 0;
}

Shortcut way to initialize arrays:
 

int AnArray[5000] = { 0 };    //Initializing the first element will initialize all 5000 to 0

Strings via pointer to char arrays:

// Initializing pointers with strings

#include <iostream>
using namespace std;
int main()
{
   char * pstr1 = "Robert Redford";
   char * pstr2 = "Hopalong Cassidy";
   char * pstr3 = "Lassie";
   char * pstr4 = "Slim Pickens";
   char * pstr5 = "Boris Karloff";
   char * pstr6 = "Oliver Hardy";
   char * pstr  = "Your lucky star is ";
   int dice = 0;
   cout << endl
        << " Pick a lucky star!"
        << " Enter a number between 1 and 6: ";
   cin >> dice;
   cout << endl;
   switch(dice)
   {
      case 1: cout << pstr << pstr1;
              break;
      case 2: cout << pstr << pstr2;
              break;
      case 3: cout << pstr << pstr3;
              break;
      case 4: cout << pstr << pstr4;
              break;
      case 5: cout << pstr << pstr5;
              break;
      case 6: cout << pstr << pstr6;
              break;
      default: cout << "Sorry, you haven't got a lucky star.";
   }
   cout << endl;
   return 0;
}

 

// Initializing an array of char pointers

#include <iostream>
using namespace std;
int main()
{
   char * pstr[] =  { "Robert Redford",  
                     "Hopalong Cassidy",
                     "Lassie",
                     "Slim Pickens",
                     "Boris Karloff",
                     "Oliver Hardy"
                   };
   char* pstart = "Your lucky star is ";
   int dice = 0;
   cout << endl
        << " Pick a lucky star!"
        << " Enter a number between 1 and 6: ";
   cin >> dice;
   cout << endl;
   if(dice >= 1 && dice <= 6)                      // Check input validity
      cout << pstart << pstr[dice-1];               // Output star name
   else
      cout << "Sorry, you haven't got a lucky star."; // Invalid input
   cout << endl;
   return 0;
}

Using sizeof() to compute the number of elements in an array:

int NumElements = ( sizeof(pstr) )  / ( sizeof(pstr[0]) )

Example:

// Flexible array management using sizeof

#include <iostream>
using namespace std;
int main()
{
   const char* pstr[] = { "Robert Redford",      // Initializing a pointer array
                    "Hopalong Cassidy",
                    "Lassie",
                    "Slim Pickens",
                    "Boris Karloff",
                    "Oliver Hardy"
                  };  
   char* pstart = "Your lucky star is ";
   int count = (sizeof pstr)/(sizeof pstr[0]); // Number of array elements
   int dice = 0;
   cout << endl
        << " Pick a lucky star!"
        << " Enter a number between 1 and " << count << ": ";
   cin >> dice;
   cout << endl;
   if(dice >= 1 && dice <= count)                     // Check input validity
      cout << pstart << pstr[dice-1];                  // Output star name
   else
      cout << "Sorry, you haven't got a lucky star."; // Invalid input
   cout << endl;
   return 0;
}

Note on using const with char pointer strings:

A string literal is a const char array, so once we assign it, we can not alter it.  This holds true even if we do not declare the pointer to char to be constant.  If we therefore try to change a pointer to a char array that was initialized with a string literal, we will crash our program.  Example:

char * CharArray = { "Test 1", "Test 2", "Test 3" };
*CharArray[0] = 'A';  //This reassignment should crash the program

It is therefore safer to write:  const char * CharArray = { "Test 1", "Test 2", "Test 3" };

This would declare the strings to be constant.  This would not prevent the pointer being reassigned to different elements, however.  Therefore, it is also useful to write:

const char * const CharArray = { "Test 1", "Test 2", "Test 3" };

The statement above indicates that not only are the char arrays (strings) constant, but the pointers as well - they can not be reassigned. 

When using pointers and arrays together, you can increment or decrement the array by performing arithmetic operations with the pointer.  Example - please take note:

pIntPointer += 1;   //increments pIntPointer to the next array element
pIntPointer++;       //increments pIntPointer to the next array element

So, if pIntPointer points to ArrayOfIntegers[5], then the expression:

*(pIntPointer + 1) = *(pIntPointer + 2);      

is equivalent to the expression:

ArrayOfIntegers[6] = ArrayOfIntegers[7];

An array name can be used exactly as though it were a pointer to itself, such that given the declaration:

int ArrayOfIntegers[100];

The element

ArrayOfIntegers[50];

can also be referred to as:

*(ArrayOfIntegers + 50);

Example of Array names as pointers:

// Calculating primes using dynamic memory allocation

#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;
int main()
{
   long* pprime=0;                // Pointer to prime array
   long trial = 5;                // Candidate prime
   int count = 3;                 // Count of primes found
   int found = 0;                 // Indicates when a prime is found
   int max = 0;                   // Number of primes required
   cout << endl
        << "Enter the number of primes you would like: ";
   cin >> max;                    // Number of primes required
   if(!(pprime=new long[max]))
   {
      cout << endl
           << "Memory allocation failed.";
      exit(1);                   // Terminate program
   }
   *pprime = 2;                  // Insert three
   *(pprime+1) = 3;              // seed primes
   *(pprime+2) = 5;
   do
   {
      trial += 2;                         // Next value for checking
      found = 0;                          // Set found indicator
      for(int i = 0; i < count; i++)    // Division by existing primes
      {
         found =(trial % *(pprime+i)) == 0;   // True for exact division
         if(found)                            // If division is exact
            break;                            // it's not a prime
      }
      if (found == 0)                     // We got one...
         *(pprime+count++) = trial;       // ...so save it in primes array
   } while(count < max);
   // Output primes 5 to a line
   for(int i = 0; i < max; i++)
   {
      if(i%5 == 0)               // New line on 1st, and every 5th line
         cout << endl;
      cout << setw(10) << *(pprime+i);
   }
   delete [] pprime;             // Free up memory
   cout << endl;
   return 0;
}

 


©2004 C. Germany