Arrays, Memory, and Pointers
From the CS50: Introduction to Computer Science curriculum
TL;DR
Arrays store collections of data of the same type in contiguous memory locations, making them efficient for access. Pointers are variables that store memory addresses, allowing you to directly manipulate data in memory. Understanding how arrays and pointers relate to memory is crucial for efficient C programming.
1. The Mental Model
Think of your computer's memory like a long street with houses, where each house has a unique address. An array is like a block of identical houses right next to each other, all belonging to the same owner. A pointer is like a sticky note with a house's address written on it, telling you exactly where to find that house.
2. The Core Material
When you declare a variable in C, the computer reserves a spot for it in memory. This spot has a unique memory address.
What's an Array?

Photo by Ann H on Pexels
An array is a collection of elements of the same data type, stored sequentially (one after another) in memory. This contiguous storage is key to their efficiency. When you declare an array like int scores[5];, you're telling the computer to set aside space for 5 integers, one after the other. The name scores itself often acts like a pointer to the first element's address.
#include <stdio.h>
int main(void) {
int scores[3]; // Declares an array named 'scores' that can hold 3 integers
scores[0] = 72; // Assigns 72 to the first element (index 0)
scores[1] = 80; // Assigns 80 to the second element (index 1)
scores[2] = 68; // Assigns 68 to the third element (index 2)
printf("Score at index 0: %i\n", scores[0]); // Accessing an element
printf("Score at index 1: %i\n", scores[1]);
printf("Score at index 2: %i\n", scores[2]);
// The name of the array itself can decay to a pointer to its first element
printf("Address of scores[0]: %p\n", &scores[0]);
printf("Value of 'scores' (address of first element): %p\n", scores);
return 0;
}
What's a Pointer?

Photo by gabesdotphotos photographer on Pexels
A pointer is a special type of variable that stores a memory address. Instead of holding a value directly, it holds the location where a value is stored.
*(dereference operator): Used to access the value at the memory address stored in the pointer.&(address-of operator): Used to get the memory address of a variable.
#include <stdio.h>
int main(void) {
int x = 10;
int *ptr = &x; // Declares a pointer 'ptr' and stores the address of 'x' in it
printf("Value of x: %i\n", x);
printf("Address of x: %p\n", &x);
printf("Value stored in ptr (address of x): %p\n", ptr);
printf("Value at the address ptr points to (*ptr): %i\n", *ptr); // Dereferencing the pointer
*ptr = 20; // Changes the value at the address ptr points to (which is 'x')
printf("New value of x: %i\n", x);
return 0;
}
Arrays and Pointers: A Close Relationship

Photo by Markus Spiske on Pexels
In C, an array's name often "decays" into a pointer to its first element. This means you can often use pointer arithmetic to navigate arrays. For example, if arr is an array, arr + 1 points to the second element, arr + 2 to the third, and so on. Dereferencing *(arr + i) is equivalent to arr[i].
#include <stdio.h>
int main(void) {
int numbers[] = {10, 20, 30, 40, 50}; // An array of 5 integers
int *p = numbers; // p now points to the first element (numbers[0])
printf("First element using array index: %i\n", numbers[0]);
printf("First element using pointer dereference: %i\n", *p);
printf("Second element using array index: %i\n", numbers[1]);
printf("Second element using pointer arithmetic: %i\n", *(p + 1)); // Moves pointer 1 'int' size forward
printf("Address of numbers[0]: %p\n", &numbers[0]);
printf("Address of numbers[1]: %p\n", &numbers[1]);
printf("Address of p: %p\n", &p); // Address of the pointer variable itself
printf("Value of p (address it stores): %p\n", p);
return 0;
}
Here's a visual way to think about how they interact in memory:
graph LR
subgraph Memory
A["0x1000 (Address)"] --> B["numbers[0] (Value: 10)"];
B --> C["numbers[1] (Value: 20)"];
C --> D["numbers[2] (Value: 30)"];
D --> E["numbers[3] (Value: 40)"];
E --> F["numbers[4] (Value: 50)"];
end
P["'p' (Pointer Variable)"] --> G["0x1000 (Value stored in p)"];
G -.-> A;
P -- "Has its own address" --> H["0x2000 (Address of 'p')"];
A -- "Array Name 'numbers' (decays to address)" --> A;
3. Worked Example
Let's trace how memory is used when creating a simple array and using a pointer to modify an element.
#include <stdio.h>
int main(void) {
int data[4]; // Declare an array named 'data' of 4 integers
int *current_pos; // Declare a pointer to an integer
data[0] = 5;
data[1] = 10;
data[2] = 15;
data[3] = 20;
printf("Initial data: %i, %i, %i, %i\n", data[0], data[1], data[2], data[3]);
// Output: Initial data: 5, 10, 15, 20
current_pos = &data[1]; // 'current_pos' now points to the second element (data[1])
printf("Address of data[1]: %p\n", &data[1]);
printf("Value in current_pos: %p\n", current_pos);
*current_pos = 100; // Change the value at the address 'current_pos' points to
printf("data[1] after modification: %i\n", data[1]);
// Output: data[1] after modification: 100
current_pos = data; // 'current_pos' now points to the first element (data[0])
printf("Value in current_pos (now pointing to data[0]): %p\n", current_pos);
*(current_pos + 3) = 500; // Use pointer arithmetic to change data[3]
printf("data[3] after pointer arithmetic: %i\n", data[3]);
// Output: data[3] after pointer arithmetic: 500
printf("Final data: %i, %i, %i, %i\n", data[0], data[1], data[2], data[3]);
// Output: Final data: 5, 100, 15, 500
return 0;
}
In this example, you can see how current_pos can be made to point to different parts of the data array, and how dereferencing *current_pos or using pointer arithmetic like *(current_pos + 3) directly affects the values stored in the array's memory locations.
4. Key Takeaways
- Arrays store elements of the same data type in contiguous memory locations.
- Pointers are variables that store memory addresses as their value.
- The
&operator gives you the address of a variable, and the*operator dereferences a pointer to get the value at that address. - An array's name can often be treated as a pointer to its first element.
- You can use pointer arithmetic to move through an array (e.g.,
ptr + 1moves to the next element). - Manipulating data through pointers is a powerful but dangerous aspect of C programming.
Common Mistakes:
- Forgetting to initialize a pointer before dereferencing it, leading to unpredictable behavior (segmentation fault).
- Confusing the pointer itself (the address it holds) with the value it points to (what's at that address).
- Performing incorrect pointer arithmetic, like adding
1to achar *and expecting it to jump over anint. - Accessing array elements out of bounds (e.g.,
array[SIZE]), which can corrupt memory.
5. Now Try It
Write a C program that declares an array of 5 floating-point numbers. Initialize these numbers. Then, declare a float pointer and make it point to the third element of your array. Use this pointer and the dereference operator to double the value of that third element. Finally, print all elements of the array to confirm the change.
Frequently asked about Arrays, Memory, and Pointers
Study this next
Get the full CS50: Introduction to Computer Science curriculum
Clone the complete plan to your dashboard for unlimited AI-generated notes, practice quizzes, and a personalised revision schedule.
Create Free Account