C-Style Arrays
Programs often need to deal with collections of values, like a list of student names or a monthly record of how many people volunteered each day.
Arrays are C++’s original way to group values like that. Inherited from the C language almost unchanged, they’re the foundation for the more modern collection types covered in this chapter.
Creating an array
An array is a fixed number of values of the same type, stored one after another. Here’s one to store a group of people’s ages:
int ages[7];This reserves space for exactly seven ints, back to back. The number in the brackets is the array’s size, and once you’ve specified it, it’s locked in. You can’t add an eighth slot later or shrink it to five.
Initializing elements
Declaring the array above gives you seven ints with garbage values, whatever bits happened to be in that spot in memory. Usually you’ll want to initialize the array right away, so each slot in the array is assigned a value:
int ages[7] = {19, 24, 31, 45, 52, 60, 67};If you give fewer values than the size, the rest are set to zero:
int ages[7] = {19, 24}; // {19, 24, 0, 0, 0, 0, 0}And if you leave the size out entirely, the compiler infers the size for you:
int ages[] = {19, 24, 31, 45, 52, 60, 67}; // size is 7, inferredThis last form works well when you’re listing out every value by hand. But if the array size needs to be bigger than the number of values provided (so the rest fill in as zero), you’ll have to specify it explicitly.
Accessing elements by index
Each slot in the array has a position, called an index. To access a value stored at an index, you use square brackets, as shown on lines 6–7:
Indexing starts at zero, not one. So ages[0] is the first element, and ages[6] is the seventh (the last one). It’s useful to think of an index as how far an element is from the start of the array.
You can also assign a value to an indexed slot, as shown on line 6.
Looping through an array
Now that you can index into the array, you can also loop over it:
Since ages has 7 elements, valid indices run from 0 to 6, so the loop uses i < 7 to stop once i reaches 7.
There’s also a second style, the range-based for loop, which provides each element directly instead of using an index to look it up with:
Read line 7 as "for each age in ages." On every pass through the loop, age receives the next element in the array, starting from the first. The loop stops automatically once it runs out of elements. There’s no index variable to manage.
The indexed version is still useful because plenty of tasks need the position too.
Finding the size of an array
Notice how both loops above hardcode 7 as the array’s size. If you added an eighth age to ages, you’d have to remember to go update that 7 too, and it’s easy to miss a spot like that.
You’d think there’d be a built-in way to check an array’s size. There is, but not a direct one. Recall how we used the sizeof operator on types and variables to see how many bytes something takes up. We can apply it to an array too:
sizeof(ages) gives you the total bytes used by the whole array, and sizeof(ages[0]) gives you the bytes used by one element. Divide one by the other and you get the number of elements.
You can now use count in place of a hardcoded 7 anywhere you need the array’s size.
Figuring out an array’s size
Passing arrays to functions
You can also pass a C-style array to a function. Here, it’s passed on line 13 to compute an average:
arr[] in the parameter list on line 3 doesn’t actually carry the size with it. When you pass a C-style array to a function, what actually gets handed over is the memory address of its first element, not the whole block. This is called array decay, and it means the function has no way to know how many elements there are. That’s why you need to pass the array’s size explicitly through a separate parameter, size on line 3.
Out-of-bounds access
Finally, nothing stops you from writing this:
int ages[7] = {19, 24, 31, 45, 52, 60, 67};ages[10] = 15; // compiles fineThere’s no tenth slot in this array, but the compiler lets it through. When the program runs, it writes 15 into the memory located beyond the end of the array, leading to unpredictable outcomes.
The practical takeaway is that an index has to satisfy 0 <= index < size, and it’s on the programmer to keep it that way.
Checkpoint
int inventory[6] = {12, 8};
What ends up stored in inventory after this line runs?
What does this print?
int counts[5];
std::cout << counts[2];You need to print each element of an array alongside its position, like “Item 0: 12”, “Item 1: 8”, and so on. Which loop style is best suited?
int getSize(int arr[]) {
int size = sizeof(arr) / sizeof(arr[0]);
return size;
}
This function is called with an int array. What does it return?