Harvard University CS50

Arrays, Memory, and Pointers

SA
StudyAI Editorial
Reviewed by StudyAI tutors
· Published Updated

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?

Wooden letters forming the word WHAT set on a textured burlap surface.
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?

A German Shorthaired Pointer walking through a snowy field in winter.
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

Vivid, blurred close-up of colorful code on a screen, representing web development and programming.
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 + 1 moves 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 1 to a char * and expecting it to jump over an int.
  • 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

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. Read the full notes above for the details.

Arrays, Memory, and Pointers is a core topic in CS50: Introduction to Computer Science. Most exam papers test it via a mix of definitions, worked examples, and applied problems. The notes above cover the high-yield sub-topics, common pitfalls, and the kind of questions examiners typically set.

Yes — every note in the StudyAI Campus Hub is free to read in full, right here on this page, with no account needed. If you clone the plan into your own dashboard, the free plan shows a preview of each note there; Basic and above unlock the full notes in your dashboard, along with practice quizzes, flashcards and offline study. You can always come back here to read the complete note for free.
Continue with
Data Structures, Algorithms, and Recursion

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