[C Series 8] Building Pointer Intuition

한국어 버전

After handling arrays and strings in part 7, it is time to see where those values live in memory. Pointers are "variables that hold addresses." They feel tricky at first, but if you print addresses and follow the values they point to, the idea becomes manageable.

New Terms in This Chapter

  1. Pointer: A variable that stores the memory address of another value
  2. Address-of Operator: The & placed before a variable to obtain its address
  3. Dereference: Using * before a pointer to read or write the value stored at that address
  4. Null Pointer: A pointer that does not point to any valid address, usually NULL or 0
  5. Pointer Type: Information about what kind of value a pointer references (int *, char *, etc.)

Key Ideas

Study Notes

  • Time: around 70 minutes
  • Prep: comfort with array lengths and function calls
  • Goal: print addresses, dereference pointers, and use pointer parameters safely

Pointers require a clear separation between "address" and "value." With int a = 10;, the variable a holds the value 10, while &a represents the address where that 10 lives. A pointer variable stores that address. A simple way to picture it is this: &a asks "where is the box?" and *ptr asks "what is inside the box at that address?"

To reduce confusion, read the following trio of lines together:

  • int *ptr; — declare a pointer that will store an int address
  • ptr = &number; — store the address of number inside the pointer
  • *ptr — read or write the actual value at that address

Follow Along with Code

Printing a Variable's Address

#include <stdio.h>

int main(void) {
    int score = 90;

    printf("score value = %d\n", score);
    printf("score address = %p\n", (void *)&score);
    return 0;
}

%p prints addresses in hexadecimal. We cast &score to (void *) because %p expects a void * argument.

Declaring and Dereferencing a Pointer

#include <stdio.h>

int main(void) {
    int number = 42;
    int *ptr = &number;

    printf("Value via ptr = %d\n", *ptr);

    *ptr = 100;
    printf("number = %d\n", number);
    return 0;
}

int *ptr means "a pointer to an int." Using *ptr lets you read or update the underlying value. Changing the value through the pointer also changes the original variable.

Pointers as Function Arguments

#include <stdio.h>

void set_to_zero(int *value) {
    if (value != NULL) {
        *value = 0;
    }
}

int main(void) {
    int counter = 5;
    set_to_zero(&counter);
    printf("counter = %d\n", counter);
    return 0;
}

set_to_zero receives an address and edits the value stored there. Pointers let functions modify external variables, but you should guard against invalid addresses by checking for NULL first.

Using a Null Pointer

#include <stdio.h>

int main(void) {
    int *ptr = NULL;

    if (ptr == NULL) {
        printf("No valid address yet.\n");
    }

    return 0;
}

If you cannot assign a real address immediately, initialize the pointer with NULL. That way you can easily check whether it is safe to dereference later. NULL means "points to nothing," so dereferencing it is always a bug. In practice that often leads to a crash because the program is trying to read or write through an address that is not valid to use.

Arrays Meet Pointers for the First Time

#include <stdio.h>

int main(void) {
    int scores[3] = {10, 20, 30};
    int *p = scores; // same as &scores[0]

    printf("First value = %d\n", *p);
    printf("Second value = %d\n", *(p + 1));
    return 0;
}

An array name usually behaves like the address of its first element. We will save detailed pointer arithmetic for later, but remember that *(p + 1) reads the same element as scores[1]. The + 1 here means "move to the next int element," not "move by one byte."

Practical Example: Validating User Input

#include <stdio.h>

int read_positive(int *out_value) {
    int temp;

    if (scanf("%d", &temp) != 1) {
        return 0;
    }

    if (temp <= 0) {
        return 0;
    }

    *out_value = temp;
    return 1;
}

int main(void) {
    int number;

    printf("Enter a positive number: ");
    if (read_positive(&number)) {
        printf("You entered: %d\n", number);
    } else {
        printf("Only positive numbers are allowed.\n");
    }

    return 0;
}

When a function needs to return multiple results, a pointer parameter is handy. read_positive returns success or failure through the normal return value, and it writes the actual number to the address provided.

Why It Matters

  • Pointers are the abstraction behind arrays, function parameters, dynamic memory, and structures in C.
  • Printing addresses and dereferencing pointers prepares you to diagnose memory-related bugs.
  • Checking for null pointers prevents crashes caused by touching invalid memory.
  • The upcoming topics—array/pointer relationships, dynamic allocation, and structures—all rely on this pointer intuition.

Practice in CodeSandbox

The sandbox below uses CodeSandbox's Universal starter. For C, the key learning loop is still compile and run in the terminal, so recreate the lesson code as a source file and repeat that cycle directly.

Live Practice

C Practice Sandbox

CodeSandbox

Run the starter project in CodeSandbox, compare it with the lesson code, and keep experimenting.

Universal starterCterminal
  1. Fork the starter and create a practice file such as hello.c
  2. Paste in the lesson code and compile it if clang or gcc is available
  3. Edit the code, rebuild it, and compare the new output

For C, the terminal build loop matters more than a browser preview. Compiler availability can vary by environment, so first confirm that clang or gcc is present in the Universal starter.

Practice

  • Follow: Recreate the ptr example and watch how number changes.
  • Extend: Write a swap function that exchanges two integers using pointer parameters.
  • Debug: (Carefully) experiment with dereferencing a null pointer, observe the runtime failure, and explain why it happens.
  • Done When: You can describe &, *, and null pointers, and write functions that accept addresses in order to modify values.

Wrap-Up

We built the foundations for working with pointers and the &/* operators. Next we will explore the precise relationship between arrays and pointers and learn how to use pointer arithmetic safely.

💬 댓글

이 글에 대한 의견을 남겨주세요