How the address of an array element is calculated in C++
The above video demonstrates how the address of each array element is calculated from the base address. It begins with a char array, gradually reveals the address of each element, applies the address calculation formula, and then changes the element type to int and double.
An array stores a fixed number of elements of the same type. These elements are placed next to each other in contiguous memory locations and are numbered from index 0.
Although an array element is normally accessed using its index, every element also has a memory address. The address depends on the base address of the array, the index of the element, and the size of one element.
Starting with a char array
Consider the following array:
char my_array[4] = {'A', 'B', 'C', 'D'};
It contains four elements:
my_array[0] = 'A'my_array[1] = 'B'my_array[2] = 'C'my_array[3] = 'D'
The index is the position of an element within the array. Since array indexing starts at 0, my_array[0] is the first element and my_array[3] is the fourth element.
The address of my_array[0] is used as the base address. In other words, the base address is the starting address of the array’s first element. In the video, this address is assumed to be 0x1000.
The same base address is used for each array shown in the video so that the address differences can be compared easily. Separate arrays in a real program would not necessarily have the same base address.
Calculating the address of an element
For the byte-addressed system shown in the video, the address of an array element can be expressed using the following formula:
address of element = base address + index × sizeof(element type)
For an element at index i, the formula becomes:
address(my_array[i]) = base address + i × sizeof(element type)
The sizeof operator gives the amount of storage occupied by one element. Multiplying the index by this size gives the element’s offset from the base address.
The first element is at index 0. Its offset is therefore zero:
0 × sizeof(element type) = 0
This is why the address of the first element is the base address itself.
In a byte-addressed system, each numeric memory address identifies one byte of memory. Increasing an address from
0x1000 to 0x1001 moves forward by one byte. The numeric addresses in the video use this common memory model.
Addresses in the char array
In C++, sizeof(char) is always 1. The address calculation for the char array is therefore:
address = 0x1000 + index × 1
The addresses of the four elements are:
my_array[0] → 0x1000my_array[1] → 0x1001my_array[2] → 0x1002my_array[3] → 0x1003
For example, the address of the element at index 2 is calculated as follows:
0x1000 + 2 × 1 = 0x1002
Each element occupies one byte, so the next element begins one byte after the previous element. This is the simplest form of the calculation. The effect of sizeof becomes more visible when the element type is changed.
Changing the element type to int
The video next changes the array to:
int my_array[4] = {10, 20, 30, 40};
For this example, sizeof(int) is assumed to be 4. The address calculation now becomes:
address = 0x1000 + index × 4
The element addresses are:
my_array[0] → 0x1000my_array[1] → 0x1004my_array[2] → 0x1008my_array[3] → 0x100C
The address of the element at index 2 is:
0x1000 + 2 × 4 = 0x1008
Each int occupies four bytes in this example. The starting address of each element is therefore four bytes after the starting address of the previous element.
The final element starts at 0x100C. In hexadecimal, C represents decimal 12. This matches the offset calculated for index 3:
3 × 4 = 12 bytes
Changing the element type to double
The same calculation can be applied after changing the element type again:
double my_array[4] = {1.5, 2.5, 3.5, 4.5};
For this example, sizeof(double) is assumed to be 8. The calculation becomes:
address = 0x1000 + index × 8
The addresses are:
my_array[0] → 0x1000my_array[1] → 0x1008my_array[2] → 0x1010my_array[3] → 0x1018
For the element at index 2:
0x1000 + 2 × 8 = 0x1010
Each double occupies eight bytes in this example, so the starting addresses are eight bytes apart.
Comparing the three arrays
The number of bytes between the starting addresses of consecutive elements is sometimes called the element stride. For a built-in array, the stride is sizeof(element type).
The video uses the following element sizes:
char: sizeof(char) = 1int: sizeof(int) = 4double: sizeof(double) = 8
These sizes produce the following addresses:
char: 0x1000, 0x1001, 0x1002, 0x1003int: 0x1000, 0x1004, 0x1008, 0x100Cdouble: 0x1000, 0x1008, 0x1010, 0x1018
The elements remain contiguous in all three arrays. What changes is the amount of memory occupied by each element and, as a result, the distance between their starting addresses.
How pointer arithmetic handles the calculation
The byte-address formula explains the memory layout shown in the video. C++ pointer arithmetic already accounts for the element type, so the multiplication by sizeof is not written manually.
For example:
int* element_address = my_array + 2;
If my_array points to the first element of an int array, adding 2 advances the pointer by two complete int elements. It does not advance the pointer by two bytes.
The following expressions identify the same element:
&my_array[2]my_array + 2
Built-in array subscripting is also defined in terms of pointer arithmetic:
my_array[2]*(my_array + 2)
Both expressions access the element at index 2.
Displaying array element addresses in C++
The following program prints the address of every element in an int array.
Example 1: Displaying the addresses of elements in a built-in array
display_array_element_addresses.cpp
#include <cstddef>#include <iostream>#include <iterator>int main(){ int my_array[4] = {10, 20, 30, 40}; for (std::size_t index = 0; index < std::size(my_array); ++index) { std::cout << "Address of my_array[" << index << "] = " << static_cast<const void*>(&my_array[index]) << '\n'; } return 0;}
The actual addresses will depend on where the array is placed when the program runs. However, the difference between consecutive addresses will be sizeof(int).
std::size, introduced in C++17, obtains the number of elements in the built-in array. It avoids repeating the array bound in the loop condition.
Where this address calculation is used
Understanding the relationship between an index and an element address is useful when working with buffers through pointers. C and C++ library interfaces often receive a pointer to the first element together with the number of elements. Moving through that buffer relies on the same pointer arithmetic used by an array.
The calculation is also useful when debugging an out-of-bounds access. If an address falls before the first element or beyond the end of the array, the index or offset calculation can be checked against the base address and the element size.
In embedded systems, arrays are commonly used for communication buffers, sensor samples, lookup data, and Direct Memory Access (DMA) buffers. Hardware or another software component may provide a starting address, while the program uses offsets or indexes to locate individual entries.
The values used for
int and double in the video are common, but they are not guaranteed for every C++ implementation. Their sizes should be checked using sizeof(int) and sizeof(double) on the target platform.
Conclusion
An array stores its elements contiguously, and the address of an element is determined by its position and the size of its type. For the byte-addressed example used in the video, the calculation is:
base address + index × sizeof(element type)
A char array advances by one byte per element, while the example int and double arrays advance by four and eight bytes. In normal C++ code, pointer arithmetic performs this adjustment automatically. The programmer adds an element count to the pointer, and C++ accounts for the size of the pointed-to type.
Discover more from Tech For Talk
Subscribe to get the latest posts sent to your email.
Leave a Reply