Section 11b

One Dimensional Array Usage, with Bracket Operators


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Setting Up Arrays and Using Them

But Before We Get Started . . .

There are actually two ways to access and execute array operations. You will see the tactics on this page used much more often because the brackets ( "[" and "]" ) are simpler and in most cases, easier to use. However, the second tactic will be presented in the next topic for reasons explained there. Learning both of these will be very helpful to your ability to program in the C language.

Using the Bracket Operators

The fundamental arrays in the C programming language are simple to declare and define. You define the name of the array as you have done with variables before, and then you tell the computer how many cells or locations you want the array to have using the bracket operators. Consider the following examples.

int integerArray[ 10 ];
double doubleArray[ 10 ];
char characterArray[ 50 ];

Now the first thing you already know is that literal numbers should not be used in a program, not even to define arrays. The above should really look like the following.

// in global constant area of class
const int NUM_INTEGERS = 10;
const int NUM_DOUBLES = 10;
const int NUM_CHARACTERS = 50;

// declared at the beginning of a function
int integerArray[ NUM_INTEGERS ];
doubl doubleArray[ NUM_DOUBLES ];
char characterArray[ NUM_CHARACTERS ];

The second thing you should notice is that your compiler may allow you to declare C arrays with variables. Do not count on this because it is not a C language specification. It may work with the compiler you are currently using but it may completely fail in someone else's system. This is the kind of thing you learn as you move around languages.

The result of your above definitions is as follows. In the case of the first example, an array named integerArray is created. Then, just like when you defined variables, a data storage "box", called an element (much like the "bucket" metaphor when you first learned about variables), is created. However, since you have indicated that you want ten of these integer data types, nine more "boxes" are created after the first one. If you define your array with ten in the brackets, you will have ten boxes available in which to store integer data types.

The array of "boxes" that you have created can be represented as shown below.

Example of initialized array

The array is shown with "stuff" in it when it is first created. The technical terminology for the stuff found in variables and arrays when they are first created is garbage, a term you have seen before. Some languages will zero out array values upon declaration. That said, you should never a trust a language to conduct this action. First, you want to get in the habit of conducting your own initialization so you can move over to other languages, and second, sometimes "automatic" things in programming languages just don't work.

This is a good place to note the difference between the terms size or length, and the term capacity. An array may be declared with a capacity of 100 integers or doubles, etc., but until you actually place appropriate data in the array, the size or length is zero. Once you do place data into the array, the size or length is considered to be the number of valid items with which you are working, not the capacity of the array. You must be careful to maintain the distinction between these two quantities. It is not common to be using all of the elements in an array, so your array size or length will almost always be less than your array's capacity. As a note, the word size is commonly used to mean capacity in some programming languages. This is unfortunate since it blurs the difference but there are some things you have to learn to live with.

The following is an initialized array. For the moment, assume that the programmer took some action to implement the initialization, so your array will now look like the example shown below where all the values have been set to zero.

Example of array initialized to all zeroes

Always remember that arrays are not guaranteed to initialize themselves. It is possible later on when you are using classes and Object Oriented Programming (OOP), that they have the capacity to initialize themselves. However, for the safety of your programs, assume until otherwise told that your arrays start with garbage in them.

Whether your array has been initialized or not, once it is defined, you can store data in it. To implement this process, you need two things identified above. First, you need a location in which to place your data. The numerical value of an array location, or element, is called an index. Remember that this is the offset from the pointer you started with when you defined the array.

Secondly, you need the data itself. Since you have declared this particular array as an integer array, you are only allowed to store integers in it. In order to do this, you indicate the following to the computer, as shown here.

integerArray[ 5 ] = 49;

The above action has placed the value 49 in the sixth element of the array. Notice that since you placed it in the element labeled five, which is the offset from the first element, you have actually placed it in the sixth location. Your array of "boxes" would now look like the following.

Array example with sixth element set to 49

To get the value back, you basically invert the process. For example if you had defined an double value called rootValue, you could implement the following process.

double rootValue;

// get square root of array element
// function: sqrt
rootValue = sqrt( integerArray[ 5 ] );

The library math function called sqrt that calculates (you guessed it) the square root of a value is used here. rootValue would be assigned the value seven because it is the square root of the value 49. Each element of the array acts just like an integer, or integer variable all its own. It is just easier to handle quantities of values by providing one name, and then using index locations to get the values back.

Remember that you can make an array of any data type, and hold values of that data type, as needed. The following provides some examples. The constant MAX_VALUES is used to define the number of elements. This is an abstraction because you may not always know what MAX_VALUES is. There is no harm in this because you can work with whatever number of elements are declared. Remember that as you study lists or groups of data, you may study lists of 10, 25, or 1,000 (or more) values.

However, to be a programmer, you must be able to manage a list of any number of items. For this reason, many times the number of items will be abstracted to N or n, as mentioned previously in this reference. Since N/n can represent any number of items, you can learn how to manage lists of any size. We commonly use N as the abstraction for "some number of values", but we always use self-documenting identifiers such as MAX_VALUES to declare our array capacities.

The following is a simple example of using an array of doubles.

// Example of array of doubles
double dArray[ MAX_VALUES ];

dArray[ 4 ] = 4.55;
dArray[ 6 ] = 3.77;
dArray[ 8 ] = dArray[ 4 ] * dArray[ 6 ];

// the ninth element in dArray now holds 17.1535

The following is a simple example of using an array of Booleans.

// Example of Boolean value array

bool bArray[ MAX_VALUES ];
bArray[ 0 ] = true;
bArray[ 1 ] = true;
bArray[ 2 ] = false;

if( bArray[ 1 ] )
{
// output message
// function: printString, printEndline
printString( "The second element of bArray is true" );
printEndline
}

The following is a simple example of using a character array.

// Example of character array
char cArray[ MAX_VALUES ];

cArray[ 0 ] = 'a';
cArray[ 1 ] = 'b';
cArray[ 2 ] = 'c';
cArray[ 3 ] = 'd';
cArray[ 4 ] = 'e';
cArray[ 5 ] = 'f';

// output lunch message
// function: printString, printEndline;
printString "I think I will eat at the " );
printEndline();
printString " " + cArray[ 2 ] );
printEndline();
printString " " + cArray[ 0 ] );
printEndline();
printString " " + cArray[ 5 ] );
printEndline();
printString " " + cArray[ 4 ] );
printEndline();

The result of the above character program segment is shown below.

I think I will eat at the c
a
f
e

Now that you have seen how to declare, assign to, and retrieve from an array, you have one condition left to consider. Array elements can be passed to functions exactly the same way as other variables; passing whole arrays is even easier but will require a little bit of discussion.

Start with passing array elements to a function. Suppose you have a function that adds two numbers together and returns their sum, called addEm, as shown here.

public int addEm( int valOne, int valTwo ) // header

Only the prototype is provided so you can see that it is just like any other function with normal parameters. So, when you need to add two values in an array, it works exactly as you might expect. Consider the following.

// usage
numbers[ 5 ] = 10;
numbers[ 15 ] = 20;

sum_1_2 = addEm( numbers[ 5 ], numbers[ 15 ] );
// sum_1_2 will now hold the value 30

Now for passing an array to a function, there is a little difference. The compiler needs to know that the identifier is an array instead of being a normal variable. You only need to add the two brackets to the end of the data type to indicate this. Consider the following function that adds all the values within the function and returns their sum.

int addEmAllUp( int intArray[], int sizeOfArray ) // header

And now consider how this is used.

// call function with array and its size
// function: addEmAllUp
overallSum = addEmAllUp( ages, size );

Two important points from this example. First, you will almost always pass the size along with the array to any function that will be using the array data. The function that loads the data needs to how many elements to load so the size variable was passed into it, as it was later passed into addEmAllUp. Remember that the size or length of an array is the number of valid items in the array; the size is not the capacity which is how many elements the array could hold. Stay alert.

Secondly, note that ages looks like any other variable, and that is because it is like any other variable. It is just that ages – the pointer – holds the address of the array and it doesn’t need brackets or anything else to make that happen. When you are passing a whole array to a function, you simply pass the name of the array.

Okay, There is This One Issue

Think about this. You have passed a pointer to a set of data into a function. If you recall, when you pass regular data into a function, you are passing by copy. That is, the compiler makes a copy of the data that can be used and manipulated inside the function. No problem.

However, when you pass a pointer into a function, you are passing the address of the data into that function which means any modifications to the data inside the function will be made to the data in the array outside the function. In some cases, this is helpful. However, in the case above, the function was meant to only add up the numbers, not change them. So if a programmer is not paying attention, he might take some action in the function that corrupts the data. This is a problem.

However, the C programming language has a way to protect this data from inadvertent modification. The solution uses another C language keyword called const which means "You can't modify this". Here is the function header from above slightly modified to provide this protection.

int addEmAllUp( const int intArray[], int sizeOfArray ) // header

Using the const keyword will keep programmers out of trouble. As you will discover later on, it will also allow certain kinds of array data to be passed as parameters that might not otherwise have been allowed. Make sure you use the const keyword when an array passed into a function is not meant to be modified.

And Arrays Are Always Local in Scope

It is important to note that creating an array (using brackets) in a given function is the same as creating a variable in the same function. Whether it is main or any other function, when the function ends, the array is no longer available for use. By itself, that should not be unexpected. However, this is a significant difference between arrays initialized with brackets and arrays initialized with pointers. There will be more to discuss on this in the the next topic. Stay Tuned.

Wrapping Up Part 1, Arrays with brackets

Watch this video to see how to declare functions that will use arrays, and then observe how the arrays are used.

In this topic, you have seen arrays declared, you have seen array elements assigned values, you have seen values retrieved from array elements, and you have seen how to call functions with both array elements and whole arrays. The next topics will get into the actual use of arrays for the interesting things they can do. However, before you move on to further use of arrays, the topic after this one will provide you with an alternative way to manage arrays. Check it out.