Arrays

I l @ ve RuBoard

Arrays

Recall that an array is composed of a series of elements of one data type. You use declarations to tell the compiler when you want an array. An array declaration tells the compiler how many elements the array contains and what the type is for these elements. Armed with this information, the compiler can set up the array properly. Array elements can have the same types as ordinary variables . Consider the following example of array declarations:

 /* some array declarations */ int main(void) {    float candy[365];      /* array of 365 floats */    char code[12];         /* array of 12 chars   */    int states[50];        /* array of 50 ints    */    ... } 

The brackets ([]) identify candy and the rest as arrays, and the number enclosed in the brackets indicates the number of elements in the array.

To access elements in an array, you identify an individual element by using its subscript number, also called an index . The numbering starts with 0. Hence, candy[] is the first element of the candy array, and candy[364] is the 365th and last element.

This is rather old hat; let's learn something new.

Initialization and Storage Classes

Arrays are often used to store data needed for a program. For example, a 12-element array can store the number of days in each month. In cases such as these, it's convenient to initialize the array at the beginning of a program, and you can. Let's see how it is done.

You know you can initialize single-valued variables (sometimes called scalar variables) in a declaration with expressions like

 int fix = 1; float flax = PI * 2; 

where, you hope, PI was defined earlier as a macro. Can you do something similar with arrays? The answer is that old favorite: yes and maybe. It's yes for ANSI C and maybe for K&R C. If the array is an external array or a static array, it can be initialized . If it is an automatic array, it can be initialized under ANSI C but not under the older K&R definition of the language. We'll cover these new terms in Chapter 13, "Storage Classes and Program Development," but we'll preview them now.

The terms external, static , and automatic describe different storage classes that C allows. The storage class determines how widely known a data item is to various functions in a program and for how long it is kept in memory. Until now, we have used only automatic variables. Let's look at these three storage classes.

Automatic Variables and Arrays

An automatic variable or array is one defined inside a function (this includes formal arguments). As we've emphasized , a variable defined in a function is private to that function, even if it reuses a name appearing in another function. We haven't mentioned, however, that such a variable exists only for the duration of the function call. When a function finishes and returns to the calling function, the space used to hold its variables is freed.

ANSI C enables you to initialize automatic arrays, as follows :

 int main(void) {   int powers[8] = {1,2,4,6,8,16,32,64}; /* ANSI only */   ... } 

Because the array is defined inside main() , it is an automatic array. It is initialized by using a comma-separated list of values enclosed in braces. You can use spaces between the values and the commas, if you want. The first element ( powers[0] ) is assigned the value 1 , and so on.

K&R C, however, does not allow this syntax to initialize an array. The only way to give values to an automatic array in K&R is to assign values to the elements individually, perhaps by using a loop.

External Variables and Arrays

An external variable or array is one defined outside a function. Here, for example, is how to define an external variable and an external array:

 int report; int sows[5] = {12, 10, 8, 9, 6};  /* ok in ANSI and K&R */ int feed(int n);   /* prototype */ int main(void) {    ... } int feed(int n) {    ... } 

External variables and arrays differ from their automatic cousins in three respects. First, they are known to all functions following them in a file. Therefore, in this example, both main() and feed() can use and modify the int variable report and the array sows . Second, external variables and arrays persist as long as the program runs. Because they are not defined in a particular function, they don't expire when a particular function terminates. Third, external variables and arrays are initialized to zeros by default, so report is initialized to .

Static Variables and Arrays

You can define a static variable or array inside a function by beginning the definition with the keyword static , as shown here:

 int account(int n, int m) {   static int beans[2] = {343, 332}; /* ok in ANSI, K&R */   ... } 

This definition creates an array that, like an automatic array, is local to the function account() . However, like an external array, a static array retains its values between function calls and is initialized to zeros by default.

Storage Classes: Comments

C offers multiple storage classes to meet different programming needs. In Chapter 13, we'll investigate the uses of each type. For most cases, automatic variables and arrays are the best choice. However, because K&R doesn't allow automatic arrays to be initialized, many older programs use external or static arrays instead. The ANSI standard has been around several years now, so this book assumes that automatic arrays can be initialized. (If that doesn't work for you, you can modify the examples by adding the static keyword.) That said, let's learn a bit more about array initialization.

More Array Initialization

Listing 10.1 presents a short program that prints the number of days per month. (Remember, if your compiler doesn't support initialization of automatic arrays, add the keyword static to the declaration.)

Listing 10.1 The day_mon1.c program.
 /* day_mon1.c -- prints the days for each month */ #include <stdio.h> #define MONTHS 12 int main(void) {   int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};   int index;   for (index = 0; index < MONTHS; index++)      printf("Month %d has %d days.\n", index +1,              days[index]);   return 0; } 

The output looks like this:

 Month 1 has 31 days. Month 2 has 28 days. Month 3 has 31 days. Month 4 has 30 days. Month 5 has 31 days. Month 6 has 30 days. Month 7 has 31 days. Month 8 has 31 days. Month 9 has 30 days. Month 10 has 31 days. Month 11 has 30 days. Month 12 has 31 days. 

Not quite a superb program, but it's wrong only one month in every four years. The program intializes days[] with a list of comma-separated values enclosed in braces.

What if you fail to initialize an array? Listing 10.2 shows what happens with the three kinds of arrays (external, static, and automatic) if you fail to initialize them.

Listing 10.2 The no_data.c program.
 /* no_data.c -- uninitialized arrays */ #include <stdio.h> #define SIZE 4 int extar[SIZE];         /* uninitialized external array  */ int main(void) {   static int statar[SIZE];  /* uninitialized static array */   int autar[SIZE];       /* uninitialized automatic array */   int i;   printf("%2s%10s%10s%10s\n",          "i", "extar", "statar", "autar");   for (i = 0; i < SIZE; i++)       printf("%2d%10d%10d%10d\n", i, extar[i],              statar[i], autar[i]);   return 0; } 

Here is the result:

 i     extar    statar     autar  0         0         0         3  1         0         0   6618612  2         0         0   4206088  3         0         0   6618628 

The rule is that external and static arrays are initialized to 0s by default. The automatic array, on the other hand, is like an ordinary automatic variable ”if you don't initialize it, it might have any value. The compiler just uses whatever values were already present at those memory locations.

The number of items in the list should match the size of the array. What if you count wrong? Let's try the last example again, as shown in Listing 10.3, with lists that are two too short.

Listing 10.3 The somedata.c program.
 /* somedata.c -- partially initialized arrays */ #include <stdio.h> #define SIZE 4 int extar[SIZE] = {1956, 1966}; int main(void) {   static int statar[SIZE]= { -50, -90};   int autar[SIZE] = {492, 567};   int i;   printf("%2s%10s%10s%10s\n",          "i", "extar", "statar", "autar");   for (i = 0; i < SIZE; i++)       printf("%2d%10d%10d%10d\n", i, extar[i],              statar[i], autar[i]);   return 0; } 

This time the output looks like this:

 i     extar    statar     autar  0      1956       -50       492  1      1966       -90       567  2         0         0         0  3         0         0         0 

As you can see, the compiler had no problem. When it ran out of values from the list, it initialized the remaining elements to . This initializing to holds for automatic arrays as well as for external and static arrays. That is, if you don't initialize an automatic array at all, its elements, like uninitialized ordinary variables, get garbage values, but if you partially initialize an automatic array, the uninitialized elements are set to .

The compiler is not so forgiving if you have too many list values. This overgenerosity is considered an error. There is no need, however, to subject yourself to the ridicule of your compiler. Instead, you can let the compiler match the array size to the list by omitting the size from the braces (see Listing 10.4).

Listing 10.4 The day_mon2.c program.
 /* day_mon2.c -- letting the compiler count elements */ #include <stdio.h> int main(void) {   int days[] = {31,28,31,30,31,30,31,31,30,31};   int index;   for (index = 0; index < sizeof days / sizeof (int); index++)      printf("Month %d has %d days.\n", index +1,              days[index]);   return 0; } 

There are two main points to note in the program:

  • When you use empty brackets to initialize an array, the compiler counts the number of items in the list and makes the array that large.

  • Notice what we did in the for loop control statement. Lacking faith (justifiably) in our ability to count correctly, we let the computer give us the size of the array. The sizeof operator gives the size, in bytes, of the object or type following it. On our system, each int element occupies 4 bytes, so we divide the total number of bytes by 4 to get the number of elements. Other systems may have a different size int . Therefore, to be general, we divide by sizeof (int) .

Here is the result of running this program:

 Month 1 has 31 days. Month 2 has 28 days. Month 3 has 31 days. Month 4 has 30 days. Month 5 has 31 days. Month 6 has 30 days. Month 7 has 31 days. Month 8 has 31 days. Month 9 has 30 days. Month 10 has 31 days. 

Oops! We put in just ten values, but our method of letting the program find the array size kept us from trying to print past the end of the array. This points out a potential disadvantage of automatic counting: Errors in the number of elements could pass unnoticed.

There is one more short method of initializing arrays. Because it works only for character strings, however, we will save it for the next chapter.

Assigning Array Values

You can assign values to array members by using an array index, or subscript. For example, the following fragment assigns even numbers to an automatic array:

 /* array assignment */ #include <stdio.h> #define SIZE 50 int main(void) {   int counter, evens[SIZE];   for (counter = 0; counter < SIZE; counter++)         evens[counter] = 2 * counter;   ... } 

Note that this assignment is element by element. C doesn't let you assign one array to another as a unit. Nor can you use the list-in-braces form except when initializing.

 /* nonvalid array assignment */ #define SIZE 5 int main(void) {     int oxen[SIZE] = {5,3,2,8};      /* ok here     */     int yaks[SIZE];     yaks = oxen;                     /* not allowed  */     yaks[SIZE] = oxen[SIZE];         /* invalid      */     yaks[SIZE] = {5,3,2,8};          /* doesn't work */ 
I l @ ve RuBoard


C++ Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 314
Authors: Stephen Prata

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