23. Windows Applications Using the MFC

Chapter 9 - Arrays

Visual C++ 6: The Complete Reference
Chris H. Pappas and William H. Murray, III
  Copyright 1998 The McGraw-Hill Companies

Arrays as Function Arguments
Just like other variables, arrays can be passed from one function to another. Because arrays as function arguments can be discussed in full only after an introduction to pointers, this chapter begins the topic and Chapter 10 expands upon this base.
Passing Arrays to C Functions
Consider a function isum( ) that computes the sum of the array elements inumeric_values[0], inumeric_values[1],..., numeric_values[n]. Two parameters are required—an array parameter called iarray_address_received to hold a copy of the array’s address and a parameter called imax_size to hold the index of the last item in the array to be summed. Assuming that the array is an array of integers and that the index is also of type int, the parameters in isum( ) can be described as
int isum(int iarray_address_received[], int imax_size)
The parameter declaration for the array includes square brackets to signal the function isum( ) that iarray_address_received is an array name and not the name of an ordinary parameter. Note that the number of cells is not enclosed in the square brackets. Of course, the simple parameter imax_size is declared as previously described. Invoking the function is as simple as this:
isum(inumeric_values,iactual_index);
Passing the array inumeric_values is a simple process of entering its name as the argument. When passing an array’s name to a function, you are actually passing the address of the array’s first element. Look at the following expression:
inumeric_values
is really shorthand for
&inumeric_values[0]
Technically, you can invoke the function isum( ) with either of the following two valid statements:
isum(inumeric_values,iactual_index);
itotal = isum(&inumeric_values[0],iactual_index);
In either case, within the function isum( ) you can access every cell in the array.
When a function is going to process an array, the calling function includes the name of the array in the function’s argument list. This means that the function receives and carries out its processing on the actual elements of the array, not on a local copy as in single-value variables where functions pass only their values.
By default all arrays are passed call-by-variable or call-by-reference. This prevents the frequent “stack overruns heap” error message many Pascal programmers encounter if they have forgotten to include the var modifier for formal array argument declarations. In contrast, the Pascal language passes all array arguments call-by-value. A call-by-value forces the compiler to duplicate the array’s contents. For large arrays, this is time consuming and wastes memory.
When a function is to receive an array name as an argument, there are two ways to declare the argument locally: as an array or as a pointer. Which one you use depends on how the function processes the set of values. If the function steps through the elements with an index, the declaration should be an array with square brackets following the name. The size can be empty since the declaration does not reserve space for the entire array, just for the address where it begins. Having seen the array declaration at the beginning of the function, the compiler then permits brackets with an index to appear after the array name anywhere in the function.
The following example declares an array of five elements, and after printing its values, calls in a function to determine what the smallest value in the array is. To do this, it passes the array name and its size to the function iminimum( ), which declares them as an array called iarray[] and an integer called isize. The function then passes through the array, comparing each element against the smallest value it has seen so far, and every time it encounters a smaller value, it stores that new value in the variable icurrent_minimum. At the end, it returns the smallest value it has seen for the main( ) to print.
/*
*   pasary.c
*   A C program using arrays as parameters
*   Copyright (c) Chris H. Pappas and William H. Murray, 1998
*/

#include <stdio.h>

#define iMAX 10
#define iUPPER_LIMIT 100

main( )
{
 int iarray[iMAX] = {3,7,2,1,5,6,8,9,0,4};
 int i, ismallest;
 int iminimum(int iarray[],int imax);

 printf(“The original list looks like: ”);
 for(i = 0; i < iMAX; i++)
   printf(“%d ”,iarray[i]);
 ismallest = iminimum(iarray,iMAX);
 printf(“\nThe smallest value is: %d: \n”,ismallest);

 return(0);
}

int iminimum(int iarray[], int imax)
{
 int i, icurrent_minimum;

 icurrent_minimum = iUPPER_LIMIT;
 for(i = 0; i < imax; i++)
   if (iarray[i] < icurrent_minimum)
     icurrent_minimum = iarray[i];
 return(icurrent_minimum);
}
Passing Arrays to C++ Functions
The following C++ program format is very similar to the C programs examined so far. The program demonstrates how to declare and pass an array argument.
//
//  fncary.cpp
//  A C++ program demonstrating how to use arrays with
//  functions
//  Copyright (c) Chris H. Pappas and William H. Murray, 1998
//

#include <iostream.h>

#define iSIZE 5
void vadd_1(int iarray[]);

main( )
{
 int iarray[iSIZE]={0,1,2,3,4};
 int i;

 cout << “iarray before calling add_1:\n\n”;
 for(i=0; i < iSIZE; i++)
   cout << “  ” << iarray[i];

 vadd_1(iarray);

 cout << “\n\niarray after calling vadd_1:\n\n”;
 for(i=0; i < iSIZE; i++)
   cout << “  ” << iarray[i];

 return(0);
}

void vadd_1(int iarray[])
{
 int i;

 for(i=0; i < iSIZE; i++)
   iarray[i]++;
}
The output from the program looks like this:
iarray before calling vadd_1:

 0  1  2  3  4

iarray after calling vadd_1:

 1  2  3  4  5
Here is a question you should be able to answer. What do the values in the output tell you about the array argument? Is the array passed call-by-value or call-by-reference? The function vadd_1( ) simply adds 1 to each array element. Since this incremented change is reflected back in main( ) iarray, it would appear that the parameter was passed call-by-reference. Previous discussions about what an array name really is indicate that this is true. Remember, array names are addresses to the first array cell.
The following C++ program incorporates many of the array features discussed so far, including multidimensional array initialization, referencing, and arguments:
//
//  2daray.cpp
//  A C++ program that demonstrates how to define, pass,
//  and walk through the different dimensions of an array
//  Copyright (c) Chris H. Pappas and William H. Murray, 1998
//

#include <iostream.h>

void vdisplay_results(char carray[][3][4]);
char cglobal_cube[5][4][5]= {
                {
                  {‘P’,’L’,’A’,’N’,’E’},
                  {‘Z’,’E’,’R’,’O’,’ ‘},
                  {‘ ‘,’ ‘,’ ‘,’ ‘,’ ‘},
                  {‘R’,’O’,’W’,’ ‘,’3’},
                },
                {
                  {‘P’,’L’,’A’,’N’,’E’},
                  {‘O’,’N’,’E’,’ ‘,’ ‘},
                  {‘R’,’O’,’W’,’ ‘,’2’}
                },
                {
                  {‘P’,’L’,’A’,’N’,’E’},
                  {‘T’,’W’,’0’,’ ‘,’ ‘}
                },
                {
                  {‘P’,’L’,’A’,’N’,’E’},
                  {‘T’,’H’,’R’,’E’,’E’},
                  {‘R’,’O’,’W’,’ ‘,’2’},
                  {‘R’,’O’,’W’,’ ‘,’3’}
                },
                {
                  {‘P’,’L’,’A’,’N’,’E’},
                  {‘F’,’O’,’U’,’R’,’ ‘},
                  {‘r’,’o’,’w’,’ ‘,’2’},
                  {‘a’,’b’,’c’,’d’,’e’}
                }
};

int imatrix[4][3]={ {1},{2},{3},{4} };
main( )
{
 int irow_index, icolumn_index;
 char clocal_cube[2][3][4];

 cout << “sizeof clocal_cube         = ”<< sizeof(clocal_cube)
                                        << “\n”;
 cout << “sizeof clocal_cube[0]      = ”<< sizeof(clocal_cube[0])
                                        << “\n”;
 cout << “sizeof clocal_cube[0][0]   = ”<<
          sizeof(clocal_cube[0][0])     << “\n”;
 cout << “sizeof clocal_cube[0][0][0]= ”<<
          sizeof(clocal_cube[0][0][0])  << “\n”;

 vdisplay_results(clocal_cube);

 cout << “cglobal_cube[0][1][2] is     = ”
      << cglobal_cube[0][1][2] << “\n”;
 cout << “cglobal_cube[1][0][2] is     = ”
      << cglobal_cube[1][0][2] << “\n”;

 cout << “\nprint part of the cglobal_cube’s plane 0\n”;
 for(irow_index=0; irow_index < 4; irow_index++) {
   for(icolumn_index=0; icolumn_index < 5; icolumn_index++)
     cout << cglobal_cube[0][irow_index][icolumn_index];
   cout << “\n”;
 }

 cout << “\nprint part of the cglobal_cube’s plane 4\n”;
 for(irow_index=0; irow_index < 4; irow_index++) {
   for(icolumn_index=0; icolumn_index < 5; icolumn_index++)
     cout << cglobal_cube[4][irow_index][icolumn_index];
   cout << “\n”;
 }

 cout << “\nprint all of imatrix\n”;
 for(irow_index=0; irow_index < 4; irow_index++) {
   for(icolumn_index=0; icolumn_index < 3; icolumn_index++)
     cout << imatrix[irow_index][icolumn_index];
   cout << “\n”;
 }

 return (0);
}
void vdisplay_results(char carray[][3][4])
{
cout << “sizeof carray         =” << sizeof(carray) << “\n”;
cout << “ sizeof  carray[0]      =” << sizeof(carray[0]) << “\n”;
cout << “ sizeof  cglobal_cube =” << sizeof(cglobal_cube) << “\n”;
cout << “ sizeof cglobal_cube[0]=” << sizeof(cglobal_cube[0])
                                  << “\n”;
}
Notice, first, how cglobal_cube is defined and initialized. Braces are used to group the characters together so that they have a form similar to the dimensions of the array. This helps in visualizing the form of the array. The braces are not required in this case since you are not leaving any gaps in the array with the initializing data. If you were initializing only a portion of any dimension, various sets of the inner braces would be required to designate which initializing values should apply to which part of the array. The easiest way to visualize the three-dimensional array is to imagine five layers, each having a two-dimensional, four-row by five-column array (see Figure 9-2).
Figure 9-2: Conceptual view of the array cglobal_cube
The first four lines of the program output show the size of the clocal_cube array, various dimensions, and an individual element. The output illustrates how the total size of the multidimensional array is the product of all the dimensions times the size of the array data type, that is, 2 * 3 * 4 * sizeof(char), or 24.
Observe how the array element clocal_cube[0] is in itself an array that contains a two-dimensional array of [3][4], thereby giving clocal_cube[0] the size of 12. The size of clocal_cube[0][0] is 4, which is the number of elements in the final dimension since each element has a size of 1, as the sizeof(clocal_cube[0][0][0]) shows.
To fully understand multidimensional arrays, it is very important to realize that clocal_cube[0] is both an array name and a pointer constant. Because the program did not subscript the last dimension, the expression does not have the same type as the data type of each fundamental array element. Because clocal_cube[0] does not refer to an individual element, but rather to another array, it does not have the type of char. Since clocal_cube[0] has the type of pointer constant, it is not a legal lvalue and cannot appear to the left of an assignment operator in an assignment expression.
Something very interesting happens when you use an array name in a function argument list, as was done when the function vdisplay_results( ) was invoked with clocal_cube. While inside the function, if you perform a sizeof( ) operation against the formal parameter that represents the array name, you do not correctly compute the actual size of carray. What the function sees is only a copy of the address of the first element in the array. Therefore, the function sizeof( ) will return the size of the address, not the item to which it refers.
The sizeof( ) carray[0] in function vdisplay_results( ) is 12 because it was declared in the function that the formal parameter was an array whose last two dimensions were [3] and [4]. You could not have used any values when you declared the size of these last two dimensions because the function prototype defined them to be [3] and [4]. Without a prototype, the compiler would not be able to detect the difference in the way the array was dimensioned. This would let you redefine the way in which you viewed the array’s organization. The function vdisplay_results( ) also outputs the size of the global cglobal_cube. This points out that while a function may have access to global data directly, it has access only to the address of an array that is passed to a function as an argument.
With regard to the main( ) function, the next two statements demonstrate how to reference specific elements in cglobal_cube when they are executed. cglobal_cube[0][1][2] references the zeroth layer, second row, third column, or “R.” cglobal_cube[1][0][2] references the second layer, row zero, third column, or “A.”
The next block of code in main( ) contains two nested for loops demonstrating that the arrays are stored in plane-row-column order. As already seen, the rightmost subscript (column) of the array varies the fastest when you view the array in a linear fashion. The first for loop pair hardwires the output to the zeroth layer and selects a row, with the inner loop traversing each column in cglobal_cube. The program continues by duplicating the same loop structures but printing only the fifth layer (plane [4]), of the cglobal_cube.
The last for loop pair displays the elements of imatrix in the form of a rectangle, similar to the way many people visualize a two-dimensional array.
The output from the program looks like this:
sizeof clocal_cube          = 24
sizeof clocal_cube[0]       = 12
sizeof clocal_cube[0][0]    = 4
sizeof clocal_cube[0][0][0] = 1
sizeof carray               = 4
sizeof carray[0]            = 12
sizeof cglobal_cube         = 100
sizeof cglobal_cube[0]      = 20
cglobal_cube[0][1][2] is    = R
cglobal_cube[1][0][2] is    = A

print part of the cglobal_cube’s plane 0
PLANE
ZERO

ROW 3

print part of the cglobal_cube’s plane 4
PLANE
FOUR
row 2
abcde

print all of imatrix
100
200
300
400
Does the output catch your attention? Look at the initialization of imatrix. Because each inner set of braces corresponds to one row of the array and enough values were not supplied inside the inner braces, the system padded the remaining elements with zeroes. Remember, C and C++ automatically initialize all undefined static automatic numeric array elements to zero.

Books24x7.com, Inc 2000 –  


Visual C++ 6(c) The Complete Reference
Visual Studio 6: The Complete Reference
ISBN: B00007FYGA
EAN: N/A
Year: 1998
Pages: 207

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net