One of the fundamental approaches to implementing a data structure is to store elements next to each other in memory within a contiguous allocation. In C++, an array (not to be confused with std::array
from the C++ standard library), provides a low-level abstraction over a sequence of objects stored within a larger block of memory. It's customary to work with arrays via pointers, including by using pointer arithmetic to compute addresses of individual elements.
We'll also introduce the notion of time complexity to formally analyze the efficiency of operations on data structures.
It turns out that arrays (and data structures built using them) provide very efficient access to data in a couple different ways:
Sequential Access: Iterating through a sequence of elements from start to end.
Random Access: Accessing an element at a particular index (i.e. position) in the sequence.
1: Time Complexity
As we're asessing the fitness of a data structure for a given task, it's helpful to determine its time complexity, which quantifies how well it performs as the size of the data we're working with scales up. |
2: Introduction to Arrays
2.1
Arrays are a low-level abstraction over a sequence of objects in memory that we can fit into the memory model we've been building up so far…
2.1 Exercise: Introduction to Arrays
Determine whether each of the following statements are true or false. Arrays can be resized if you need more space. The elements in an array are stored contiguously in memory. All elements in a particular array must be the same type. All individual array elements must be the same size in memory. Each array element lives at the same address in memory. Sample solution…Arrays can be resized if you need more space. The elements in an array are stored contiguously in memory. All elements in a particular array must be the same type. All individual array elements must be the same size in memory. Each array element lives at the same address in memory. |
3: Arrays, Pointers, and Pointer Arithmetic
3.1
Because an array is essentially just a sequence of objects (one for each element in the array) that are laid out contiguously in memory, we can leverage pointers (i.e. addresses) to work with arrays. Here's one example, informally: Let's recap the fundamental arithmetic operations with pointers. Assume
Note that in both cases, we don't have to worry about how many bytes are involved - the compiler takes care of that behind the scenes based on the pointer types. We can think about offsets and differences in terms of the sequences of whole objects in memory. Finally, and perhaps one of the biggest takeaways here, indexing in arrays with the
3.1 Exercise: Pointer Arithmetic
Trace this code and draw a memory diagram as you go. Once you're finished, use your diagram to answer the question below. You could also run the lobster simulation to check your work. What values are printed for each of the expressions sent to
Sample solution…
You're welcome to check your solution with this walkthrough video: |
4: Pointer Comparison Operators
4.1
Just like we can do arithmetic with pointers by considering offsets and distances between locations in memory, we can also understand pointer comparisons naturally in terms of addresses. So, basically, It's also worth noting the equality operators
4.1 Exercise: Pointer Comparison
Given an array and some pointers:
Determine whether each of the following expressions evaluates to Sample solution… Why does the last expression yield a guaranteed |
5: Traversal by Pointer
5.1
There are two fundamental ways to approach sequential access of the elements in an array using a loop, which we might also call "traversal" or "iteration" through the array's elements:
Neither traversal by pointer nor traversal by index is fundamentally better or more efficient for arrays. You might hear someone say that traversal by index is slower, but this is generally not true given that modern compilers can optimize both approaches into the same machine code. You should use the one that feels more natural to you or that matches the generally accepted pattern for the code you're writing. In most cases, that's probably traversal by index. However, we're taking a look at traversal by pointer now because:
5.1 Exercise: Traversal By Pointer
Which of the following code snippets correctly implement traversal by pointer? For each, indicate whether it is correct or has a bug. If it has a bug, describe what's wrong. Is it a compile error or a runtime error? How would you fix it?
Surprise! Each of the code snippets above contains at least one mistake. If you didn't find this, double check the ones you marked as correct, or take a look this walkthrough video: |
6: Array Parameters and Functions
6.1
When working with arrays, it's often helpful to write helper functions that process the arrays in some way, perhaps using a loop to iterate through each element and perform some operation. An example of this would be a function that prints out an array… Two big takeaways here:
6.1 Exercise: Pass-by-Pointer
Write a function called You're welcome to check your solution with this walkthrough video: |