Section 4.1. Arrays


4.1. Arrays

An array is a compound type (Section 2.5, p. 58) that consists of a type specifier, an identifier, and a dimension. The type specifier indicates what type the elements stored in the array will have. The dimension specifies how many elements the array will contain.

The type specifier can denote a built-in data or class type. With the exception of references, the element type can also be any compound type. There are no arrays of references.



4.1.1. Defining and Initializing Arrays

The dimension must be a constant expression (Section 2.7, p. 62) whose value is greater than or equal to one. A constant expression is any expression that involves only integral literal constants, enumerators (Section 2.7, p. 62), or const objects of integral type that are themselves initialized from constant expressions. A nonconst variable, or a const variable whose value is not known until run time, cannot be used to specify the dimension of an array.

The dimension is specified inside a [] bracket pair:

           // both buf_size and max_files are const           const unsigned buf_size = 512, max_files = 20;           int staff_size = 27;            // nonconst           const unsigned sz = get_size();  // const value not known until run time           char input_buffer[buf_size];     // ok: const variable           string fileTable[max_files + 1]; // ok: constant expression           double salaries[staff_size];     // error: non const variable           int test_scores[get_size()];     // error: non const expression           int vals[sz];                    // error: size not known until run time 

Although staff_size is initialized with a literal constant, staff_size itself is a nonconst object. Its value can be known only at run time, so it is illegal as an array dimension. Even though size is a const object, its value is not known until get_size is called at run time. Therefore, it may not be used as a dimension. On the other hand, the expression

           max_files + 1 

is a constant expression because max_files is a const variable. The expression can be and is evaluated at compile time to a value of 21.

Explicitly Initializing Array Elements

When we define an array, we can provide a comma-separated list of initializers for its elements. The initializer list must be enclosed in braces:

           const unsigned array_size = 3;           int ia[array_size] = {0, 1, 2}; 

If we do not supply element initializers, then the elements are initialized in the same way that variables are initialized (Section 2.3.4, p. 50).

  • Elements of an array of built-in type defined outside the body of a function are initialized to zero.

  • Elements of an array of built-in type defined inside the body of a function are uninitialized.

  • Regardless of where the array is defined, if it holds elements of a class type, then the elements are initialized by the default constructor for that class if it has one. If the class does not have a default constructor, then the elements must be explicitly initialized.

Unless we explicitly supply element initializers, the elements of a local array of built-in type are uninitialized. Using these elements for any purpose other than to assign a new value is undefined.



An explicitly initialized array need not specify a dimension value. The compiler will infer the array size from the number of elements listed:

           int ia[] = {0, 1, 2}; // an array of dimension 3 

If the dimension size is specified, the number of elements provided must not exceed that size. If the dimension size is greater than the number of listed elements, the initializers are used for the first elements. The remaining elements are initialized to zero if the elements are of built-in type or by running the default constructor if they are of class type:

           const unsigned array_size = 5;           // Equivalent to ia = {0, 1, 2, 0, 0}           // ia[3] and ia[4] default initialized to 0           int ia[array_size] = {0, 1, 2};           // Equivalent to str_arr = {"hi", "bye", "", "", ""}           // str_arr[2] through str_arr[4] default initialized to the empty string           string str_arr[array_size] = {"hi", "bye"}; 

Character Arrays Are Special

A character array can be initialized with either a list of comma-separated character literals enclosed in braces or a string literal. Note, however, that the two forms are not equivalent. Recall that a string literal (Section 2.2, p. 40) contains an additional terminating null character. When we create a character array from a string literal, the null is also inserted into the array:

           char ca1[] = {'C', '+', '+'};                // no null           char ca2[] = {'C', '+', '+', '\0'};         // explicit null           char ca3[] = "C++";     // null terminator added automatically 

The dimension of ca1 is 3; the dimension of ca2 and ca3 is 4. It is important to remember the null-terminator when initializing an array of characters to a literal. For example, the following is a compile-time error:

           const char ch3[6] = "Daniel"; // error: Daniel is 7 elements 

While the literal contains only six explicit characters, the required array size is sevensix to hold the literal and one for the null.

No Array Copy or Assignment

Unlike a vector, it is not possible to initialize an array as a copy of another array. Nor is it legal to assign one array to another:

           int ia[] = {0, 1, 2}; // ok: array of ints           int ia2[](ia);        // error: cannot initialize one array with another           int main()           {               const unsigned array_size = 3;               int ia3[array_size]; // ok: but elements are uninitialized!               ia3 = ia;           //  error: cannot assign one array to another               return 0;           } 

Some compilers allow array assignment as a compiler extension. If you intend to run a given program on more than one compiler, it is usually a good idea to avoid using nonstandard compiler-specific features such as array assignment.



Caution: Arrays Are Fixed Size

Unlike the vector type, there is no push_back or other operation to add elements to the array. Once we define an array, we cannot add elements to it.

If we must add elements to the array, then we must manage the memory ourselves. We have to ask the system for new storage to hold the larger array and copy the existing elements into that new storage. We'll see how to do so in Section 4.3.1 (p. 134).


Exercises Section 4.1.1

Exercise 4.1:

Assuming get_size is a function that takes no arguments and returns an int value, which of the following definitions are illegal? Explain why.

           unsigned buf_size = 1024;           (a) int ia[buf_size];           (b) int ia[get_size()];           (c) int ia[4 * 7 - 14];           (d) char st[11] = "fundamental"; 

Exercise 4.2:

What are the values in the following arrays?

           string sa[10];           int ia[10];           int main() {               string sa2[10];               int    ia2[10];           } 

Exercise 4.3:

Which, if any, of the following definitions are in error?

           (a) int ia[7] = { 0, 1, 1, 2, 3, 5, 8 };           (b) vector<int> ivec = { 0, 1, 1, 2, 3, 5, 8 };           (c) int ia2[ ] = ia1;           (d) int ia3[ ] = ivec; 

Exercise 4.4:

How can you initialize some or all the elements of an array?

Exercise 4.5:

List some of the drawbacks of using an array instead of a vector.


4.1.2. Operations on Arrays

Array elements, like vector elements, may be accessed using the subscript operator (Section 3.3.2, p. 94). Like the elements of a vector, the elements of an array are numbered beginning with 0. For an array of ten elements, the correct index values are 0 through 9, not 1 through 10.

When we subscript a vector, we use vector::size_type as the type for the index. When we subscript an array, the right type to use for the index is size_t (Section 3.5.2, p. 104).

In the following example, a for loop steps through the 10 elements of an array, assigning to each the value of its index:

           int main()           {               const size_t array_size = 10;               int ia[array_size]; // 10 ints, elements are uninitialized               // loop through array, assigning value of its index to each element               for (size_t ix = 0; ix != array_size; ++ix)                     ia[ix] = ix;               return 0;           } 

Using a similar loop, we can copy one array into another:

           int main()           {               const size_t array_size = 7;               int ia1[] = { 0, 1, 2, 3, 4, 5, 6 };               int ia2[array_size]; // local array, elements uninitialized               // copy elements from ia1 into ia2               for (size_t ix = 0; ix != array_size; ++ix)                     ia2[ix] = ia1[ix];               return 0;           } 

Checking Subscript Values

As with both strings and vectors, the programmer must guarantee that the subscript value is in rangethat the array has an element at the index value.

Nothing stops a programmer from stepping across an array boundary except attention to detail and thorough testing of the code. It is not inconceivable for a program to compile and execute and still be fatally wrong.

By far, the most common causes of security problems are so-called "buffer overflow" bugs. These bugs occur when a subscript is not checked and reference is made to an element outside the bounds of an array or other similar data structure.





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

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