You can write int values[6], yet still confuse the sixth element with index 6, call every access fast, or use an address formula without checking the element size. Memory addresses advance by element size; insertion and deletion may shift elements; row-major storage lays out rows in sequence. Use Coding & Skills to browse related learning paths as you practise, and test each pattern with pencil and paper.
What an array organises, and why sequential matters
int values[6] = {14, 9, 21, 6, 18, 11};It holds six int elements contiguously. Indices are 0 through 5: values[0] is 14, values[2] is 21, and values[5] is 11. Order tracks positions; addresses track bytes.
Equal sizes enable base-plus-offset indexing. With sizeof(int) == 4, element i has offset 4i bytes. Integer size varies, so use sizeof(int). Its compile-time extent is fixed; it cannot grow. Indexing is constant time; search may inspect every element.
Declaration, initialisation, traversal and updates
int a[4] = {5, 8, 13, 21}; // {5, 8, 13, 21}
int b[4] = {5, 8}; // {5, 8, 0, 0}
int c[4]{}; // four zeros
int d[] = {3, 1, 4}; // inferred extent: 3
int uninitialised[4]; // write before readingfor (std::size_t i = 0; i < 6; ++i)
std::cout << '(' << i << ',' << values[i] << ") ";Output: (0,14) (1,9) (2,21) (3,6) (4,18) (5,11). Use i < 6; i <= 6 reaches invalid values[6]. For values alone: for (int value : values).
Sum trace: 0 -> 14 -> 23 -> 44 -> 50 -> 68 -> 79. Maximum trace: 14 -> 21, ending at index 2. After values[3] = 16, the array is {14, 9, 21, 16, 18, 11} and its sum is 89.
Worked example: every address in a six-element array
Assume &values[0] is 1000 and sizeof(int) == 4. Element i follows i equal elements:
address(values[i]) = base + i * sizeof(int) = 1000 + i * 4
|
| Byte offset | Hypothetical address |
|---|---|---|---|
0 | 14 | 0 | 1000 |
1 | 9 | 4 | 1004 |
2 | 21 | 8 | 1008 |
3 | 6 | 12 | 1012 |
4 | 18 | 16 | 1016 |
5 | 11 | 20 | 1020 |
For values[4], 1000 + 4 * 4 = 1016, holding 18. Here values + 4 equals &values[4], while *(values + 4) reads 18. Pointers in C for GATE teaches this model in C; it also underpins C++ arrays.
![Six-element int array with indices 0 to 5, its values, and byte addresses 1000 to 1020, showing values[4] at address 1016.](https://cdn.knowledgegate.ai/blog-assets/blog_asset_1784573196568_1qwomp.jpg)
Insertion and deletion with fixed capacity
int values[8] = {14, 9, 21, 6, 18, 11};
std::size_t n = 6;Capacity is eight; logical size is six. Insertion requires n < 8 and pos in 0..n. To insert 15 at pos = 2, shift right:
for (std::size_t i = n; i > pos; --i)
values[i] = values[i - 1];
values[pos] = 15;
++n;Copy 5 -> 6 (11), 4 -> 5 (18), 3 -> 4 (6), and 2 -> 3 (21). Result: {14, 9, 15, 21, 6, 18, 11}, with n = 7.
Delete index 4, removing 6. Shift 5 -> 4 (18) and 6 -> 5 (11), then decrement n. Result: {14, 9, 15, 21, 18, 11}; ignore the stale outside value. pos = n appends without shifts; deletion at pos >= n is invalid. Raw arrays check neither. Middle insertion or deletion may move a suffix; indexing does not.
Two-dimensional arrays and row-major addresses
int grid[2][3] = {{4, 7, 1}, {9, 2, 6}};Rows are 0..1; columns are 0..2. Nested loops using outer r < 2 and inner c < 3 print:
4 7 1
9 2 6Assume &grid[0][0] = 2000 and sizeof(int) == 4. Row-major storage places each three-integer row in sequence:
address(grid[r][c]) = 2000 + ((r * 3) + c) * 4
For grid[1][2]: linear index 1 * 3 + 2 = 5, offset 20, address 2020, value 6. For grid[1][0]: linear index 3, address 2012, value 9. Multiplying by the column count skips a complete row.
A compatible parameter keeps the later dimension: void print(const int grid[][3], std::size_t rows).
![A 2-by-3 grid flattened in row-major order to addresses 2000 to 2020, with grid[1][2] at address 2020 holding value 6.](https://cdn.knowledgegate.ai/blog-assets/blog_asset_1784573197875_8l66k4.jpg)
Arrays at function boundaries, then safer abstractions
In void print(const int values[], std::size_t n), values becomes a pointer. sizeof(values) cannot recover six elements, so pass 6 and use i < n. Functions in C refreshes parameters; modern C++ offers safer abstractions.
int raw[6] = {14, 9, 21, 6, 18, 11};
std::array<int, 6> fixed{14, 9, 21, 6, 18, 11};
std::vector<int> dynamic{14, 9, 21, 6, 18, 11};
dynamic.push_back(25); // now seven logical elementsUse std::array for fixed compile-time size, std::vector for runtime resizing, and raw arrays for low-level interfaces, exercises, or existing APIs. On the containers, .at(4) checks bounds; operator[] does not.
Common array mistakes and precise repairs
Mistake | What goes wrong | Repair |
|---|---|---|
Loop with | Touches invalid index | Use |
Read automatic | Reads elements before valid values are written | Initialise or assign first |
Assume every | Address calculation may be wrong | Use |
Use | The array has decayed to a pointer | Pass size or use a sized abstraction |
Insert when | No free slot exists | Check capacity first |
Shift left-to-right during insertion | Unread values get overwritten | Shift right from the end |
Confuse rows with columns in the 2D formula | Produces the wrong linear index | Multiply row by column count |
For std::cout << values[6], index 6 is outside the original array and behaviour is undefined. No output or error is guaranteed.
Record capacity and logical size separately, mark 0..n-1, check bounds, use element size in address calculations, shift safely, and test the first, middle, and last valid index.
Checkable array practice
Use the exercises below to check traces, off-by-one access, address calculation, row-major flattening, and shift counts independently.
Under the earlier address assumptions,
&values[5] = 1000 + 5 * 4 = 1020; the value is11.After
values[3] = 16, the sum is14 + 9 + 21 + 16 + 18 + 11 = 89.To print the original array backwards without unsigned-index trouble, use
for (std::size_t i = 6; i > 0; --i) std::cout << values[i - 1] << ' ';. The output is11 18 6 21 9 14.For
grid[1][1], the linear index is1 * 3 + 1 = 4; its address is2000 + 4 * 4 = 2016, and its value is2.
The short version
Arrays keep same-type elements contiguously at indices 0..n-1. Address calculations need a base, dimensions, and element size. Insertion or deletion may shift elements; direct indexing does not. Row-major storage flattens rows in order.
For a structured next step, continue with the C++ Programming course. For broader placement-oriented coding practice, use the Coding for Placements course.




