Search

6.2 — Arrays (Part II)

This lesson continues the discussion of arrays that began in lesson 6.1 -- Arrays (part I)

Initializing fixed arrays

Array elements are treated just like normal variables, and as such, they are not initialized when created.

One way to initialize an array is to do it element by element:

However, this is a pain, especially as the array gets larger.

Fortunately, C++ provides a more convenient way to initialize entire arrays via use of an initializer list. The following example is equivalent to the one above:

If there are more initializers in the list than the array can hold, the compiler will generate an error.

However, if there are less initializers in the list than the array can hold, the remaining elements are initialized to 0. The following example shows this in action:

This prints:

7
4
5
0
0

Consequently, to initialize all the elements of an array to 0, you can do this:

In C++11, the uniform initialization syntax can be used instead:

Omitted length

If you are initializing a fixed array of elements using an initializer list, the compiler can figure out the length of the array for you, and you can omit explicitly declaring the length of the array.

The following two lines are equivalent:

This not only saves typing, it also means you don’t have to update the array length if you add or remove elements later.

Arrays and enums

One of the big documentation problems with arrays is that integer indices do not provide any information to the programmer about the meaning of the index. Consider a class of 5 students:

Who is represented by testScores[2]? It’s not clear.

This can be solved by setting up an enumeration where one enumerator maps to each of the possible array indices:

In this way, it’s much clearer what each of the array elements represents. Note that an extra enumerator named MAX_STUDENTS has been added. This enumerator is used during the array declaration to ensure the array has the proper length (as the array length should be one greater than the largest index). This is useful both for documentation purposes, and because the array will automatically be resized if another enumerator is added:

Note that this “trick” only works if you do not change the enumerator values manually!

Arrays and enum classes

Enum classes don’t have an implicit conversion to integer, so if you try the following:

You’ll get a compiler error. This can be addressed by using a static_cast to convert the enumerator to an integer:

However, doing this is somewhat of a pain, so it might be better to use a standard enum inside of a namespace:

Passing arrays to functions

Although passing an array to a function at first glance looks just like passing a normal variable, underneath the hood, C++ treats arrays differently.

When a normal variable is passed by value, C++ copies the value of the argument into the function parameter. Because the parameter is a copy, changing the value of the parameter does not change the value of the original argument.

However, because copying large arrays can be very expensive, C++ does not copy an array when an array is passed into a function. Instead, the actual array is passed. This has the side effect of allowing functions to directly change the value of array elements!

The following example illustrates this concept:

before passValue: 1
after passValue: 1
before passArray: 2 3 5 7 11
after passArray: 11 7 5 3 2

In the above example, value is not changed in main() because the parameter value in function passValue() was a copy of variable value in function main(), not the actual variable. However, because the parameter array in function passArray() is the actual array, passArray() is able to directly change the value of the elements!

Why this happens is related to the way arrays are implemented in C++, a topic we’ll revisit once we’ve covered pointers. For now, you can consider this as a quirk of the language.

As a side note, if you want to ensure a function does not modify the array elements passed into it, you can make the array const:

sizeof and arrays

The sizeof operator can be used on arrays, and it will return the total size of the array (array length multiplied by element size). Note that due to the way C++ passes arrays to functions, this will _not_ work properly for arrays that have been passed to functions!

On a machine with 4 byte integers and 4 byte pointers, this printed:

32
4

(You may get a slightly different result if the size of your types are different).

For this reason, be careful about using sizeof() on arrays!

Determining the length of a fixed array

One neat trick: we can determine the length of a fixed array by dividing the size of the entire array by the size of an array element:

This prints:

The array has 8 elements

How does this work? First, note that the size of the entire array is equal to the array’s length multiplied by the size of an element. Put more compactly: array size = array length * element size.

Using algebra, we can rearrange this equation: array length = array size / element size. sizeof(array) is the array size, and sizeof(array[0]) is the element size, so our equation becomes array length = sizeof(array) / sizeof(array[0]). We typically use array element 0 for the array element, since it’s the only element guaranteed to exist no matter what the array length is.

Note that this will only work if the array is a fixed-length array, and you’re doing this trick in the same function that array is declared in (we’ll talk more about why this restriction exists in a future lesson in this chapter).

In common usage, the terms “array size” and “array length” are both most often used to refer to the array’s length (the size of the array isn’t useful in most cases, outside of the trick we’ve shown you above). In these tutorials, we’ll try to use the term “length” when we’re talking about the number of elements in the array, and “size” when we’re referring to how large something is in bytes.

Indexing an array out of range

Remember that an array of length N has array elements 0 through N-1. So what happens if you try to access an array with a subscript outside of that range?

Consider the following program:

In this program, our array is of length 5, but we’re trying to write a test score into the 6th element (index 5).

C++ does not do any checking to make sure that your indices are valid for the length of your array. So in the above example, the value of 13 will be inserted into memory where the 6th element would have been had it existed. When this happens, you will get undefined behavior -- For example, this could overwrite the value of another variable, or cause your program to crash.

Although it happens less often, C++ will also let you use a negative index, with similarly undesirable results.

Rule: When using arrays, ensure that your indices are valid for the range of your array!.

Quiz

1) Declare an array to hold the high temperature (to the nearest tenth of a degree) for each day of a year (assume 365 days in a year). Initialize the array with a value of 0.0 for each day.

2) Set up an enum with the names of the following animals: chicken, dog, cat, elephant, duck, and snake. Put the enum in a namespace. Define an array with an element for each of these animals, and use an initializer list to initialize each element to hold the number of legs that animal has.

Write a main function that prints the number of legs an elephant has, using the enumerator.

Quiz answers

1) Show Solution

2) Show Solution

6.3 -- Arrays and loops
Index
6.1 -- Arrays (Part I)

155 comments to 6.2 — Arrays (Part II)

  • Oskar Ramirez

    Hi Alex.  I’m new to programming so I want to start off by saying thank you for being so thorough and so awesome.  I hope to make you proud one day.  In the mean time, can you take a look at my code?  I was able to work it into a manner similar to your solution, but in this example I attempted to call in the input from another function.  Unfortunately it only prints the array when I use break, or works randomly with continue, while looping forever.  Please tell me what i’m wrong.  Any help would be appreciated.
    [int enterNumber(int guess)
    {
    while (1)
    {
    std::cout << "Enter number between 1 and 9 " <> x;

    if (std::cin.fail()) // has a previous extraction failed?
    {
    // yep, so let’s handle the failure
    std::cin.clear(); // put us back in ‘normal’ operation mode
    std::cin.ignore(32767, ‘n’); // and remove the bad input
    }
    else if (x > 9)
    {
    std::cin.clear();
    std::cin.ignore(32767, ‘n’);
    std::cout << "Your number is too high dude" << std::endl;
    }
    else if (x < 1)
    {
    std::cin.clear();
    std::cin.ignore(32767, ‘n’);
    std::cout << "You're wasting my time n";
    }

    else
    {
    std::cin.ignore(32767, 'n');
    std::cout << "4, 6, 7, 3, 8, 2, 1, 9, 5 " << std::endl;
    return x;
    }
    }

    }

    int main()
    {
    int array[] = { 4, 6, 7, 3, 8, 2, 1, 9, 5 };
    const int arrayLength = sizeof(array) / sizeof(array[0]);

    for (int index = 0; index < arrayLength; ++index)
    {
    int x = enterNumber(index);
    if (x == array[index])

    std::cout << "You entered element " << x << " with index " << index << std::endl;
    break;
    }

    return 0;
    }]

  • James carron

    You said that "Note that this will only work if the array is a fixed-length array" but you used   int array[] = { 1, 1, 2, 3, 5, 8, 13, 21 };, the array doesn’t have a specified length?

  • WOW. this is a very complete explanation.

    Hey alex, you’re awesome. thanks for making great tutorial.

  • Wunna

    Some other questions,

    In the above code you wrote. Would the function make the array constant afterward?(I mean in main() after calling this function)
    And are the array parameters the copy like the function parameters?

    • Alex

      > Would the function make the array constant afterward?(I mean in main() after calling this function)

      No, the constness of the parameter only affects array access through that parameter. The actual array is unaffected.

      > And are the array parameters the copy like the function parameters?

      I don’t understand what you’re asking here.

    • Wunna

      I mean would they just implicitly convert any enum or variable being put as parameters into integer?
      I mean for example prime[++x] would cause the actual x to be incremented?

  • Wunna

    I have a little question with this code

    There, why would you bother putting enum into a namespace.
    It makes no sense to me and just making it more of work to be done.
    As I learned from you that enum classes wouldn’t implicitly convert into integer so they should be preferred but putting enum into namespace doesn’t give the power of enum classes instead having to put namespace’s name before enum every time we want to call. Even if it does,it’d still be the same with enum classes and will have to static_cast them which is a pain,right?
    Please explain me why, if you have a good reason.
    Thanks a lot,my teacher.

    • Alex

      It’s not strictly necessary to put the enum into the namespace, it just helps keep your global namespace clean. For example, without the namespace, if you defined another enum in the same scope that used the same enumerator in a different context, you’d get a naming conflict. For example:

      STAN will cause a naming conflict because both StudentNames and ChildrenNames are trying to define it in the same place.

      Using an enum in a namespace helps provide the naming cleanliness, but doesn’t restrict implicit conversion to integer like an enum class does. In some cases, preventing that implicit conversion is desirable. Here, it’s just a pain.

  • Jasper

    Hi Alex, I’d like to create a program that loops through an array of names and grades, and prints something like: "Stan has the highest score: 87", Kenny has the lowest score: 57". I think I need an array that holds both strings and integers but I can’t find the correct method. This code I have doesn’t work:

    • Alex

      At this point in the tutorial series, I’d use a struct instead of a class. Try this:

      • Jasper

        Thanks! My program works now. Here is the code:

  • Angmar

    Hi,  is there any sugar for creating long arrays liike {0 .. 6} instead of writing {0, 1, 2, 3, 4, 5}

    • Alex

      Nope. If you’re okay with assigning values rather than initializing values, you could write a loop to assign values to the array elements rather than list them all out explicitly.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter