Introduction to Arrays
Chapter 8
Categories of Data Types
- Scalar (simple) types: Store a single logical value
int,double,char,bool,enum, etc.
- Homogeneous collections: Multiple values of the same type
- arrays (which we are learning about here)
- Heterogeneous collections (structured types): Group related values of different types
- struct (more on this category later in the semester)
Arrays
An array is a collection of a fixed number of elements (values), all of the same data type. A one-dimensional array has elements that are arranged in a list form.
Array Declaration
The syntax for declaring a one-dimensional array with
SIZEelements:cppdataType arrayName[SIZE];where
SIZEis any constant expression that evaluates to a positive integer.Here is an example declaration using a constant variable for the size.
cpp// Creating an array of 24 doubles const int NUM_OF_STUDENTS = 24; double testScores[NUM_OF_STUDENTS];We can create a new array with 8 elements:
cppint list[8];The array declared above has 8 consecutive locations in memory, each of which can store an integer value. Because nothing has been stored in the array yet, the initial values are unknown (could be anything). The size of the array must be constant. The size of an array must be known at compile time.
WARNING
Make sure that all declared arrays have constant sizes that are known at compile time. For example, you cannot get the size from the user using cin and then declare the array of that size. In CSCI 315, you will learn an alternative method of declaring arrays with sizes that are unknown at compile time, but that is beyond the scope of this course.
Accessing Array elements
Just like with strings, we use the array subscript operator [] to access individual elements of the array.
Here is how to access a single array element, where
indexExpis an expression with a non-negative integer value (called the index).cpparrayName[indexExp];The value of the index is the position of the item in the array.
The first element of an array is at index
0(we start0, not1)!- Therefore, what is the last index in an array relative to its length?
We can store a value in this array:
cpplist[4] = 100; // store 100 in the 5th element of the array100is now stored in memory at index 4 of the array named list.We can also access values from the array:
cpplist[2] = 10; list[6] = 35; list[4] = list[2] + list[6];Setting and accessing array elements
Processing One-Dimensional Arrays
Examples of basic operations to perform on a one-dimensional array include:
- Initializing
- Inputting data
- Outputting data stored in an array
- Finding the largest and/or smallest element
Each operation requires the ability to step through elements of the array. This is easily accomplished using a loop.
Given the declarations:
cppconst int LIST_SIZE = 100; int list[LIST_SIZE]; //array of size 100Use a
forloop to access array elements:cppfor (int iter = 0; iter < LIST_SIZE; iter++) cin >> list[iter];
Array Index Out of Bounds Error
The index of an array is in bounds if the index is >= 0 and < ARRAY_SIZE.
- In C++, there is no guard against indices that are out of bounds.
- If you index an array outside of its bounds, the program has undefined behavior. It might appear to work, produce unexpected results, or stop with a runtime error. C++ does not guarantee what will happen.
Array Initialization during Declaration
An array can be initialized when it is declared by listing the values inside curly braces. The array size is determined by the number of initial values in the braces.
Examples:
To declare an array with 5 elements and initialize them:
cppdouble sales[] { 12.25, 32.40, 16.90, 23, 46.84 };An array can also be partially initialized during declaration:
cppdouble sales[10] {};Declares an array of 10 elements and initializes all of them to zero.
To declare a 10-element array and initialize
sales[0]to8,sales[1]to5, andsales[2]to12:cppdouble sales[10] { 8.0, 5.0, 12.0 };All other elements are initialized to
0.
Aggregate Operations cannot be performed on Arrays in C++
Aggregate operation: any operation that manipulates the entire array as a single unit.
Most aggregate operations are NOT possible with arrays. For example:
const int LIST_SIZE = 5;
int myList[LIST_SIZE] { 1, 5, 3, 7, 16 };
int yourList[LIST_SIZE];
yourList = myList; // error: invalid array assignmentSolution: use a loop.
// Traditional for loop
for (int index = 0; index < LIST_SIZE; ++index)
yourList[index] = myList[index];Auto Variable Types
Remember, C++11 allows the auto declaration of variables.
Data type does not need to be specified when initializing a variable at declaration.
cppauto num1 = 15; // num1 is an int because 15 is an int. auto num2 = 15.0; // num2 is a double auto num3 = 'A'; // num3 is a char auto num4 = num1; // num4 is an intThe
autokeyword is a placeholder for a type, but it is not itself a type. The compiler determines the type based on the value it receives.There is no accidental conversion between types (implicit casting), so your code is not only more flexible but possibly more efficient.
Range-Based For Loops
We have already used range-based for loops with strings. They may also be used with arrays.
Example:
double list[] { 45.3, 77.8, 103.9, 84.2, 88.5, 109.6, 99.5, 101.2, 31.8, 99.2 };
auto sum = 0.0; // a double
// Calculate the sum of all the elements in the list array.
for (auto num : list) // For each num in list
sum = sum + num;In the first part of this for loop, the variable, num, holds a copy of an element from the array (list) that is the second part. Range-based loops are very clean because you do not need to index the values in the array. However, you are limited to traversing the entire array from beginning to end.
WARNING
Range-based for loops work when the compiler can determine the beginning and end of the range. A raw array parameter does not retain the array's length: it is adjusted to a pointer, so a range-based loop cannot be used directly on it. You can use a separate length parameter with an indexed loop, or use a span (introduced later in this note).
Arrays as Parameters to Functions
Array arguments are not copied when passed to a function. In a parameter list, an array parameter is adjusted to a pointer to its first element. This allows the function to modify the original array.
- Do not use the
&symbol when declaring an array parameter in this form.
- Do not use the
The length of the array should be omitted from the square brackets. If provided, it is ignored by the compiler. If the function needs to know the length of the array, it must be passed as an additional parameter.
Example:
cppvoid funcArrayAsParam(int arrayOne[], double arrayTwo[], int length);To prevent a function from changing the array elements, use
constin the declaration of the parameter.Example:
cppvoid exampleFunc(const int VALS[], int size);
C++ does not allow functions to return an array. You can get around this limitation using something known as pointers, but that topic will be discussed in a later course.
TIP
Important: If an array parameter is not to be modified inside the function, make it a const array parameter.
Base Address of an Array and Array in Computer Memory
The base address of an array: address (memory location) of the first array element
Give a one-dimensional array named
list, its base address is the address oflist[0].When an array is passed as a parameter, the base address of the actual array is passed to the formal parameter.
You can view the Base address for the array like this:
cppint array[5]; // Declare array with 5 elements cout << array; // Display the array’s base address (no square brackets) // The address of the first element matches the array's base address. cout << &array[0];The base address is commonly displayed in hexadecimal notation (for example,
0x1234CC00). Hexadecimal is the base-16 numbering system and has sixteen distinct symbols for each digit:0–9andA–F. Each hexadecimal digit represents four binary digits (bits).
| Base 2 | 0 | 1 | 10 | 11 | 100 | 101 | 110 | 111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 | 10000 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Base 10 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| Base 16 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | 10 |
Common Errors with Arrays
- Arrays in C++ (and almost all programming languages) are zero-indexed. That means that the first index is zero, not one. The last index is the length minus one. It is easy to have an off-by-one error if you forget this fact.
- Array index out of bounds: do not access an index outside the range
0throughlength - 1. Doing so produces undefined behavior, not a guaranteed error message. - Array arguments are not copied when passed to a function, so changes to the elements persist after the function call. Use
constto prevent a function from modifying the elements. - Can’t set one array equal to another with just the equal operator. Use a loop instead.
- A function cannot return a built-in array by value. Arrays are not copied when passed to functions, so a function can usually fill an array supplied by its caller instead.
The span Container for Arrays
In C++20 (the C++ standard released in 2020), a helpful view called span was added to associate an array with its length/size. An array is an object that contains its elements, but when an array is passed to a function using a raw array parameter, it is adjusted to a pointer to its first element. That pointer does not keep track of how many elements are in the array. As a result, we often need to pass the array size to a function parameter as an additional parameter. For example,
void display (const double NUMBERS[], int length)
{
cout << "Length: " << length << '\n'; // display the array length
for (int index = 0; index < length; ++index)
{
cout << NUMBERS[index] << '\n';
}
}The span container allows us to connect the array with its size. For example,
/*
* Demonstration of using span to connect an array with its size.
* To compile with the C++20 standard, add the following command line argument
* -std=c++20
* (Replace -std=c++20 with -std=c++2a in GCC 9 or earlier.)
*/
#include <iostream>
#include <span> // To use this new span container
using namespace std;
/**
* Displays the length and values in an array of doubles.
* The numbers parameter is a constant span for an array of doubles.
* Like static_cast, the type goes within the <>. If you change
* <double> to <int>, then it will accept an array of integers.
*/
void display (const span<double> numbers);
int main()
{
// Create an example array of length 10.
const int LENGTH = 10;
double array[LENGTH] { 1.1, 2.1, 3.1, 4, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1 };
// Display the array using an implicit cast to a span container.
display(array);
return 0;
}
void display (const span<double> numbers)
{
// Display the array length
cout << "Length: " << numbers.size() << '\n';
// Display each number. This range-based for loop would not work with a
// traditional array parameter.
for (auto num : numbers)
{
cout << num << '\n';
}
}