Charles E. Oyibo
We will recall that a data type is called simple if variables of that type can store only one value at a time. In constrast, in a structured data type each data item is a collection of other data items. Simple data types are the building blocks of structured data types. Arrays, are a structured data type.
An array is a collection of fixed number of components all of the same data type. A one-dimentional array is an array in which the components are arranged in a list form. We will concentrate on one-dimentional arrays for now.
The general form for declaring a one-dimentional array is:
dataType arrayName[intExp];
where intExp is a constant expression that evaluates to a positive integer. Also, intExp specifies the number of components in the array.
For example, the statement:
int num[5];
declares an array num of 5 components. Each component is of the type int. The components are num[0], num[1], num[2], num[3], num[4]. In other words, we have declared 5 variables, all of the type int.
The general form (syntax) used for assessing an array component is:
arrayName[indexExp]
where indexExp, called the index, is any expression whose value is a non-negative integer. The index value specifies the position of the component in the array.
Recall that in C++, [] is called the array subscripting operator. Moreover, note that in C++, the array index starts at 0
Consider:
int list[10]; // Line1 list[5] = 34; // Line2 i = 4; list[i] = 63 // Line 3 list[2 * i - 2] = 58 // Line 4
Line 1 declares an array list of 10 components (list[0], list[1], ... , list[9]); line 2 stores 34 in list[5]; line 3 stores 63 to list[4]; line 4 stores 58 to list[6].
We can also declare arrays thus:
const int arraySize = 10; int list[arraySize];
Observe that arraySize is declared as a constant.
When we declare an array, its size must be known. That is, we may not declare an array as a variable, thus:
int arraySize; //Line 1 cout << "Enter the size of the array: " //Line 2 cin >> arraySize; //Line 3 cout << endl; //Line 4 int list[arraySize] //Line 5
Because when the compiler compiles Line 1, the value of the variable arraySize is unknown. Thus when the compiler compiles Line 5, the size of the array is unknown and the compiler will not know how much memory to allocated for the array.
We will explore how to specify the size of an array during program execution, and then declare an array of that size using pointers. Arrays that are created during program execution are called dynamic arrays. For now though, whenever we declare an array, we must specify its size (i.e. the number of elements is has).
Some of the basic operations performed on a one-dimentional array are:
and if the data is numeric,
Each of these operations require the ability to step through the elements of the array. This is accomplished using a loop.
Consider the following statements:
double sales[10];
int index;
double largestSale, sum, average;
The following lines of code...
for (index = 0; index < 10; index++)
sale[index] = 0.0;
for (index = 0; index < 10; index++)
cin >> sale[index];
for (index = 0; index < 10; index++)
cout << sale[index] << " ";
sum = 0;
for (index = 0; index < 10; index++)
sum = sum + sale[index];
average = sum / 10;
maxIndex = 0; for (index = 1; index < 10; index++) if (sale[maxIndex] < sale[index]) maxIndex = index; largestSale = sale[maxIndex];
Explanation: Initially, we assume that the first element in the list is the largest element and so maxIndex is initialized to 0. We then compare the element pointed to by maxIndex with every subsequent element in the list. Whenever we find an element in the array larger than the element pointed to by maxIndex, we update maxIndex so that it points to the new larger element.
Consider:
double num[10];
A loop such as:
for (i = 0; i <= 10; i++)
num[i] = 0;
can set the index out of bounds. When i becomes 10, the loop test condition i <= 10 evaluates to true and the body of the loop executes, which results in storing 0 in list[10]. Logically, list[10] does not exist.
Formally, the index (say, index) of an array is in bounds if:
Otherwise, the index is out of bounds. If during program execution, the index goes out of bounds, several unexpected things can happen. Since C++ has no in-built safe-guards against out-of-bound indices, it is incumbent on us, the programmers, to ensure that the index value is within range.
The following statement declares an array, sales, of five components and initializes these components.
double sales[5] = {12.25, 32.43, 23, 24.55, 30.6};
Here:
sales[1] = 12.25 sales[2] = 32.43 sales[3] = 23.00 sales[4] = 24.55 sales[5] = 30.60
When initializing arrays while declaring them, it is not necessary
to specify the size of the array. The size is determined by the number of initial
values in the braces. We must, however, still include the (empty) brackets ([])
following the array name. Hence, our statement above could legally take the
form:
double sales[] = {12.25, 32.43, 23, 24.55, 30.6}
The statement
int list[10] = {5};
declares list of be an array of 10 components and initializes the first component to 5 and the rest to 0. The statement:
int list[10] = {8, 5, 12};
declares list to be an array of 10 components, initializes list[0] to 8, list[1] to 5, list[2] to 12, and all the other components to zero. Hence, if all the values are not specified in the initialization statement, the array components for which the values are not specified are initialized to 0.
Note that the statement:
int list[] = {5, 6, 3};
declares list to be an array of 3 components and intilizes list[0] to 5, list[1] to 6, and list[2] to 3. In contrast, the statement:
int list[25] = {4, 7};
declares list to be an array of 25 components, initializing the first two components to 4 and 7 respectively, and the remaining to 0.
C++ does not allow aggregate operation on an array (an aggregate operation on an array being any operation that is, at least, intended to manipulate the entire array as a unit). To, say, copy one array into another, we must copy it component-wise -- that is, one component at a time. We could use the following loop to accomplish this.
for (j = 0; j < 25; j++)
y[j] = x[j];
rather than simply
y = x;
where x and y are both arrays of size 25.
How are arrays passed as parameters to functions?
By reference only: In C++, arrays are passed by reference only.
Moreover, since arrays are passed by reference only, we do not use the symbol & when declaring an array as a formal parameter. Furthermore, when declaring a one-dimentional array as a formal parameter, we omit the size of the array.
Consider:
void functionArrayAsParam(int
listOne[], double listTwo[])
{
...
}
The function functionArrayAsParam has two formal parameters: (1) listOne, a one-dimensional array of the type int (i.e. its components are of the type int); and (2) listTwo, a one-dimentional array of the type double. In this declaration, the size of both arrays are unspecified.
Consider a function of that is intended to initialize all the elements of an int-type array of any size to 0:
void initialize(int
list[], int listsize)
{
int count;
for (count = 0; count
< listSize; count++)
list[count] = 0;
}
The first parameter of the function initialize is an int array of any size. When the function intialize is called, the size of the actual array is passed as the second parameter of the function intialize.
Even though an array is always passed by reference, we can still prevent the function from changing the actual parameter(s). We do so by using the reserved word const in the declaration of the formal paramter, as in:
void example(int
x[], const int y[],
int sizeX, int sizeY)
{
...
}
Here the function example can modify array x, but not array y. Any attempt to change y will result in a compile-time error.
It is a good programming practice to declare an array to be a constant as a formal parameter if we do not want the function to modify the array.
... examples that show how to write functions for array processing and declare an array as a formal parameter...
The base address of an array is the address (i.e. memory location) of the first array component. E.g. if list is a one-dimentional array, then the base address of list is the address of the component list[0].
When we pass an array as a parameter, the base address of the actual array is passed to the formal parameter.
Question: Why do we pass arrays as reference parameters rather than as value parameters.
Answer: If we were to pass arrays as value parameters, the array would have to be copied from the actual parameters in the function call to the formal parameters in the function definition. Not only does this have the potential for taking a considerable amount of computer time, memory also has to be allocated to hold essentially redudant data. This would evidently make for a very slow and inefficient program. To be more efficient, we pass arrays as reference parameters, so that only the base address of the array is passed to the function.
C++ does not allow functions to return a value of the type array.
...
...
...
Character arrays are of special interest and we process them differently than other arrays. C++ provide a number of (predefined) functions that we can use with character arrays.
A character array is an array whose components are of the type char.
... Subtopics:
Two (or more) arrays are called parallel if their corresponding components hold related information.
We may, for example, be interested in keeping track of students' course grades, together with their ID numbers. To do this, we could declare two arrays: studentId of the type int and courseGrade of the type char (let's assume there are 50 students in our class):
int studentId[50];
char courseGrade[50];
Suppose that the input file is opened using the ifstream variable infile. We make the following considerations:
We implement the following loop, then, to read the data into the parallel arrays studentId and courseGrade.
int noOfStudents = 0;
infile >> studentID[noOfStudents] >> courseGrade[noOfStudents];
while (infile && noOfStudents < 50)
{
noOfStudents++
infile >> studentID[noOfStudents]
>> courseGrade[noOfStudents];
}
Again, the two conditions in the while loop ensure that (1) the program does not attempt to read past the end of file, and (2) we do not attempt to write past the end of the array.
We have thus far dealt with data presented as lists (one-dimentional arrays). Data presented in table form can be manipulated in C++ using two-dimentional arrays.
A two-dimentional array is, formally, a collection of a fixed number of components arranged in rows and columns (that is, in two dimentions), wherein all components are of the same type.
The syntax for declaring a two-dimentional array is:
dataType arrayName[intExp1][intExp2];
where intExp1 and intExp2 are constant expressions yielding positive integer values. The two expressions intExp1 and intExp2 specify the number of rows and the number of columns, respectively, in the array. The statement
double sales[10][5];
declares a two-dimentional array sales of 10 rows and 5 columns, where every component is of the type double. As in the case of one-dimentional arrays, the rows are numberd 0...9 and the columns are numbered 0...4.
To access the components of a two-dimentional array, we need a pair of indices: one for the row position and one for the column position. The syntax:
arrayName[indexExp1][indexExp2]
where indexExp1 and indexExp2 are expressions yielding non-negative integer values. indexExp1 specifies the row position; indexExp2 specifies the column position.
Suppose that: int i = 5; and int j = 3;
Then the statements: sales[5][3] = 25.75; and sales[i][j] = 25.75; both do the same thing: store 25.75 into row number 5 and colum number 3 (i.e. the 6th row and 4th column) of the array sales.
Consider the following statement:
int board[4][3] = {{2, 3, 1}, {15, 25, 13}, {20, 4, 7}, {11, 18, 14}};
This statement declares board to be a two-dimentional array of 4 rows and 3 columns. The components in the first row are 2, 3, and 1; the components of the second row are 15, 25, and 13; the components of the third row are 20, 4, and 7; and the components of the fourth row are 11, 18, and 14, respectively.
To initialize a two-dimentional array when it is declared:
We can also use the enumeration type for array indices. Consider the following statements:
const int
numberOfRows = 6;
const int numberOfColumns
= 5;
enum carType {GM, Ford, Toyota, BMW, Nissan, Volvo};
enum color {Red, Brown, Black, White, Gray};
int inStock[numberOfRows][numberOfColumns];
These statements define the carType and colorType enumeration types, and define inStock as a two-dimentional array of 6 rows and 5 columns. Suppose that each row in inStock corresponds to a car type, and each column corresponds to a color. Suppose, further, that each entry in inStock represents the number of cars of a particular type and color.
inStock| [Red] | [Brown] | [Black] | [White] | [Gray] | |
| [GM] | |||||
| [Ford] | |||||
| [Toyota] | |||||
| [BMW] | |||||
| [Nissan] | |||||
| [Volvo] |
The statement:
inStock[1][3] = 15;
is equivalent to
inStock[Ford][White] = 15;
Observe that the second statement easily conveys the message--that is, set the number of White Ford cars to 15. This illustrates that enumeration types can be used effectively to make the program readable and easy to manage.
A two-dimentional array can be processed in three ways:
Consider the following declarations:
const int noOfRows = 7;
const int noOfCols = 6;
int matrix[noOfRows][noOfCols];
int row;
int col;
int sum;
int largest;
int temp;
The following for loop initializes initialize row number 4 (that is, the 5th row) to 0:
row = 4;
for (col = 0; col < noOfCols; col++)
matrix[row][col] = 0;
If we want to initialize the entire matrix to 0, we could say:
for (row = 0; row < noOfRows;
row++)
for (col = 0; col <
noOfCols; col++)
matrix[row][col] = 0;
The following nested for loop prints the components of matrix, one row per line:
for (row = 0; row < noOfRows;
row++)
{
for (col = 0; col <
noOfCols; col++)
cout << setw(5) <<
matrix[row][col] << " ";
cout << endl;
}
The following for loop inputs the data in row number 4 (i.e. the 5th row) of matrix:
row = 4;
for (col = 0; col < noOfCols; col++)
cin >> matrix[row][col];
As before, by nesting the "col" loop inside the "row" loop, we could input data into each component of matrix:
for (row = 0; row < noOfRows;
row++)
for (col = 0; col <
noOfCols; col++)
cin >> matrix[row][col];
The following for loop finds the sum of row number 4 of matrix; that is, it adds the components of the 5th row:
sum = 0;
row = 4;
for (col = 0; col < noOfCols; col++)
sum = sum + matrix[row][col];
Again, by putting the row number in the loop, we can find the sum of each row separately:
//Sum of each individual row
for (row = 0; row < noOfRows; row++)
{
sum = 0;
for (col = 0; col <
noOfCols; col++)
sum = sum + matrix[row][col];
cout << "Sum of row " << row +
1 << " = " << sum << endl;
}
As in the case of sum by row, the following for loops finds the sum of each individual columnL
//Sum of each individual column
for (col = 0; col < noOfCols; col++)
{
sum = 0;
for
(row = 0; row < noOfRows; row++)
sum = sum + matrix[row][col];
cout << "Sum of column" << col
+ 1 << " = " << sum << endl;
}
The following for loop determines the largest element in row number 4:
row = 4;
largest = matrix[row][0]; //we assume that the
first element of the row is the largest
for (col = 0; col < noOfCols; col++)
if (largest < matrix[row][col])
largest = matrix[row][col];
The following C++ code determines the largest element in each row and each column:
//largest element in each
row
for (row = 0; row < noOfRows; row++)
{
largest = matrix[row][0]; //we
assume that the first element of the row is the largest
for (col = 0; col
< noOfCols; col++)
if
(largest < matrix[row][col])
largest
= matrix[row][col];
cout << "The largest element in row "
row + 1 << " = " << largest << endl;
}
//largest element in each
column
for (col = 0; col < noOfCols; col++)
{
largest = matrix[row][0]; //we
assume that the first element of the column is the largest
for (row = 0; row
< noOfRows; row++)
if
(largest < matrix[row][col])
largest
= matrix[row][col];
cout << "The largest element in row "
row + 1 << " = " << largest << endl;
}
Suppose that matrix is a square array (i.e. noOfRows and noOfCols are the equal). Then matrix has a main diagonal and an opposite diagonal. Let's suppose that we want to reverse both the diagonals of matrix, and that we have:
const int noOfRows = 7;
const int noOfCols = 6;
To reverse the main diagonal, we want to:
And to reverse the opposite diagonal, we want to:
| [0] | [1] | [2] | [3] | |
| [0] | [0][0] | [0][3] | ||
| [1] | [1][1] | [1][2] | ||
| [2] | [2][1] | [2][2] | ||
| [3] | [3][0] | [3][3] |
The following for loop reverses the diagonals:
// reverse the main diagonal
for (row = 0; row < noOfRows / 2; row++)
{
temp = matrix[row][row];
matrix[row][row] = matrix[noOfRows
- 1 - row][noOfRows - 1 - row];
matrix[noOfRows - 1 - row][noOfRows
- 1 - row] = temp;
}
// reverse the opposite diagonal
for (row = 0; row < noOfRows / 2; row++)
{
temp = matrix[row][noOfRows
- 1 - row];
matrix[row][noOfRows -
1 - row] = matrix[noOfRows - 1- row][row];
matrix[noOfRows - 1 - row][row]
= temp;
}
The preceding C++ code to reverse the diagnonals of a square, two-dimentional array works for an array of any size.
Two-dimentional arrays are passed as reference parameters to functions, with the base address (the address of the first component of actual parameter) being passed to the formal parameter.
When sorting a two-dimentional array in the computer's memory, C++ uses the row order form. That is, the first row is sorted first, followed by the second row, and so on.
Recall that when declaring a one-dimentional array as a formal parameter, we usually omit the size of the array. Because C++ sorts two-dimentional arrays in row order form, the compiler must know where one row ends and where the next row begins in order to computer the address of a component correctly. Thus, when declaring two-dimentional arrays as a formal parameter, we can omit the size of the first dimention, but not the second; that is, we must specify the number of columns.
Suppose we have:
const int noOfRows = 6;
const int noOfCols = 5;
Consider the following definition of the function printMatrix:
void printMatrix(int[][noOfCols], int noOfRows)
{
int row, col;
for (row = 0; row < noOfRows;
row++)
{
for
(col = 0; col < noOfCols; col++)
cout
<< setw(5) << matrix[row][col] << " ";
cout
<< endl;
}
}
This function takes as a parameter a two-dimentional array of an unspecified number of rows, and 5 columns, and outputs the content of the two-dimentional array. During the function call, the number of the actual paramters must match the number of the columns of the formal paramter.
Suppose we need to perform an operation, such as alphabetizing a list of names. Because every name is a string, a convenient way to stire the list of names is to use an array. Strings in C++ can be manipulated using either the data type string or character arrays (c-strings).
Suppose that the list consists of a maximum of 100 names. We can declare an array of 100 components of the type string as follows:
string list[100];
Basic operations like assignment, comparison, and input/output can be performed on values of the string type.
Suppose that the largest string in our list is 15 characters long and out list has 100 strings. We can declare a two-dimentional array of characters of 100 rows and 16 columns as follows:
char list[100][16];
So that list[j] for each j, 0 <= j <= 99, is a string of at most 15 characters in lenght.
We set the columns to be 16 because, as we will recall, the \0 character marks the end of a string.
Suppose we want to read and store data in our array list and that there is one entry per line, the following loop accomplishes this task:
for (j = 0; j < 100; j++)
cin.get(list[j], 16);
The following outputs the string in each row:
for (j = 0; j < 100; j++)
cout << list[j]
<< endl;
If we know the size of the tables with which the program will be working, then we can use typedef to first define a two-dimensional array data type and then declare variables of that type. For example, consider:
const int numOfRows = 20;
const int numOfCols = 10;
typedef int tableType[noOfRows][noOfCols];
The previous statement defines a two-dimensional array data type tableType. Now we can declare variables of this type. So:
tableType matrix;
declares a two-dimentional array matrix of 20 rows and 10 columns.
...
Recall that a 1-dimensional array is an array in which the elements are arranged in a list form and that a 2-dimensional array is one in which the elements are arranged in a table form...
A general definition of an array is in order here:
An array is a collection of a fixed number of elements (called components) arranged in n dimentions (n >= 1), called an n-dimentional array.
The general syntax for declaring an n-dimensional array is:
dataType arrayName[intExp1][intExp2] ... [intExpn];
where intExp1, intExp2, and intExpn are constant expressions yielding positive integer values.
The syntax to access the components of an n-dimentional array is:
arrayName[indexExp1][indexExp2] ... [indExpn]
where intExp1, intExp2, and intExpn are expressions yielding non-negative integer values. intExpi gives the position of the array in the ith dimension.
...
Page Last Updated: Saturday February 12, 2005 10:21 AM