# Arrays

Arrays are one way to store many values of the same type in one variable. An array can be of any (fixed) size. If an array is of size n, then the elements (values) of the array can be accessed with indices 0 through n-1. The memory “allocated” to an array is contiguous; you can think of each element sitting right next to its siblings somewhere in memory.

## Examples

Here is an example of how we create arrays, and give them their values:

We can change the values of an array in the same way:

The value of the array variable itself (in this case, arr), is actually not an integer value but the memory location where the array starts. We can print this location, but it’s more-or-less meaningless:

Although arr is a pointer, its address cannot be changed.

Note that we cannot ask an array how large it is. Once the array is created, the computer essentially forgets how big it is. The size of the array is something we need to keep track of ourselves. (This is unlike the string function length(), which we can use to determine how big a string is.)

## Assigning values

We can assign the values to an array with a loop if we don’t want to type all the values individually. In this case, the array is created by specifying a size but the values are missing. Inside a for() loop we will set the values:

We can also provide the values with an “initializer list,” like we did previously:

However, note that if your make an array of size n but you do not provide n values between the braces, then the first values will be put in the array but the values that you have not defined will all have a “default” value.

When you initialize an array with an initializer list, you may omit the array size in the declaration; enough space will be allocated for the array to accommodate the values specified. If you provide a size but specify values for fewer elements than the size indicates, the missing elements are default-initialized. The rules for default initialization are complicated; you should not rely on them. — C++ Pocket Reference

## Dynamically-sized arrays

An alternative is to get the values from the user. In the following example, we first ask for the size of the array, then ask for each value.

We have to create a “dynamically-sized” array because we don’t know how big the array is until the program is running. Note, by “dynamically-sized” I mean an array whose size is unknown until it is created; I do not mean an array whose size changes, which is impossible in C++. To create a dynamically-sized array, we have to use the new operator and later the delete[] operator. These operators are discussed more in the memory management notes.

## Passing arrays to functions

When an array is passed to a function, it is not copied (usually, we like this). Rather, only the pointer to the beginning of the array is passed (and copied, actually). Recall that we have to keep track of the array size; the compiler does not do this for us. So, we should also send the size of the array along with its pointer.

## Returning arrays from functions

If an array is created in a function, without using new, it will be deleted when the function is finished. So, you don’t want to return a pointer to the beginning of this array since the array will disappear. Rather, use the new operator to create an array that won’t be automatically deleted, and return a pointer to it.

Note that the function cannot return both the array pointer and the size of the array. So, somehow, your code must already know the size of the array that will be generated, unless you use pointers or references, as described in the function calling notes.

## Some simple array operations

Find the sum of an array:

Find the product of an array:

Print the contents of an array:

Print the contents of an array in a function:

Sum an array of doubles in a function:

Copy one array to another, in reverse, in a function:

Concatenate two arrays (make a new array that contains the contents of two arrays), in a function:

## 2D arrays; and 1D arrays acting as 2D arrays

A 2D array is technically an array of pointers to arrays. First, however, we’ll ignore that and treat 2D arrays as matrices:

But with dynamically-sized arrays, it is made more obvious that 2D arrays are arrays of pointers to arrays:

Image source

With a little bit of arithmetic, we can treat a 1D array as a 2D array:

## Pointer syntax

Let’s use the famous delta-heart equivalency:

Δ[♥] ≡ *(Δ + ♥)


Anytime the compiler sees something of the form Δ[♥], it rewrites it to *(Δ + ♥). So,

replace p[1][3][4]:
- Δ = p[1][3]
- ♥ = 4
⇛ *(p[1][3] + 4)

replace p[1][3]:
- Δ = p[1]
- ♥ = 3
⇛ *(*(p[1] + 3) + 4)

replace p[1]:
- Δ = p
- ♥ = 1;
⇛ *(*(*(p + 1) + 3) + 4)


Thus,

p[1][3][4] ≡ *(*(*(p + 1) + 3) + 4)


Want proof?! Try this with some 1D array: arr[3] vs. 3[arr]. Note that this won’t work with 2D or more-D arrays, because the stars won’t be in the right places.

## Frequency of English letters example

After compiling, use the program like so:

a.out < text1.txt


Example output (The Adventures of Sherlock Holmes):

a: ******************* 8.12%
b: *** 1.49%
c: ***** 2.45%
d: ********** 4.29%
e: ***************************** 12.30%
f: ***** 2.08%
g: **** 1.83%
h: **************** 6.65%
i: ***************** 6.98%
j:  0.11%
k: ** 0.82%
l: ********* 3.96%
m: ****** 2.72%
n: **************** 6.65%
o: ******************* 7.81%
p: *** 1.60%
q:  0.10%
r: ************* 5.71%
s: *************** 6.28%
t: ********************** 9.04%
u: ******* 3.05%
v: ** 1.03%
w: ****** 2.58%
x:  0.13%
y: ***** 2.19%
z:  0.03%