PY
C

Python to C

10 lessons

Progress0%
1Variables & Types2Functions3Lists → Arrays4Memory Management5String Handling6Structs7Preprocessor8File I/O9Pointers and Manual Memory10Build System: Makefile
All Mirror Courses
PY
C
Pointers and Manual Memory
MirrorLesson 9 of 10
Lesson 9

Pointers and Manual Memory

C pointers hold the memory address of a value; manual heap allocation (malloc/free) replaces Python's automatic garbage collection.

Introduction

In this lesson, you'll learn about pointers and manual memory in C. Coming from Python, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
PY
From Python:

In Python, you're familiar with c pointers hold the memory address of a value; manual heap allocation (malloc/free) replaces python's automatic garbage collection..

C
In C:

C has its own approach to c pointers hold the memory address of a value; manual heap allocation (malloc/free) replaces python's automatic garbage collection., which we'll explore step by step.

The C Way

Let's see how C handles this concept. Here's a typical example:

C
C Example
#include <stdio.h>
#include <stdlib.h>   /* malloc, free */
#include <string.h>   /* memset */

/* Pass pointer to allow function to modify the caller's variables */
void swap(int *a, int *b) {
    int tmp = *a;   /* dereference: read value at address */
    *a = *b;
    *b = tmp;
}

/* Return a heap-allocated array — caller must free() */
int *make_array(int n, int fill) {
    int *arr = malloc(n * sizeof(int));   /* allocate n ints on heap */
    if (!arr) return NULL;                /* malloc can fail! */
    for (int i = 0; i < n; i++) arr[i] = fill;
    return arr;   /* caller owns this memory */
}

int main(void) {
    int x = 3, y = 7;
    printf("before: x=%d y=%d\n", x, y);
    swap(&x, &y);   /* pass address of x and y */
    printf("after:  x=%d y=%d\n", x, y);   /* x=7 y=3 */

    int *data = make_array(100, 0);
    if (!data) { fprintf(stderr, "OOM\n"); return 1; }
    data[42] = 99;
    printf("data[42]=%d\n", data[42]);
    free(data);   /* MUST free — no GC */
    data = NULL;  /* avoid dangling pointer */
    return 0;
}

Comparing to Python

Here's how you might have written similar code in Python:

PY
Python (What you know)
# Python — automatic memory, no explicit pointers
def swap(lst, i, j):
    lst[i], lst[j] = lst[j], lst[i]   # list passed by reference

numbers = [3, 1, 4]
swap(numbers, 0, 2)
print(numbers)   # [4, 1, 3]

# Dynamic allocation is implicit
data = [0] * 100   # GC handles cleanup
data = None         # refcount drops, memory freed automatically
Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

int *p declares a pointer; &x gives the address of x; *p dereferences (reads/writes the pointed-to value)

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

malloc(n * sizeof(T)) allocates n bytes on the heap; returns void* or NULL on failure

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

Every malloc must have a paired free() — no garbage collector, leaks are permanent until process exits

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

Passing &var to a function lets it modify the caller's variable (simulating pass-by-reference)

Mirror Card
PY
From Python:

You may be used to different syntax or behavior.

C
In C:

Python references are automatically reference-counted; C pointers are raw memory addresses with no safety net

Step-by-Step Breakdown

1. Declare and Dereference Pointers

int *p is a pointer to int. Use & to take the address and * to dereference (access the value). Think of * as 'the value at this address'.

PY
Python
x = 42  # Python: x is a name bound to an object
C
C
int x = 42;
int *p = &x;    /* p holds the address of x */
printf("%d\n", *p);  /* dereference: prints 42 */
*p = 99;            /* modifies x through p */
printf("%d\n", x);   /* 99 */

2. Pointer Parameters for Output

C is pass-by-value. To let a function modify a variable, pass its address. The function uses * to write through the pointer.

PY
Python
def swap(lst, i, j):
    lst[i], lst[j] = lst[j], lst[i]
C
C
void swap(int *a, int *b) {
    int tmp = *a; *a = *b; *b = tmp;
}
// call:
swap(&x, &y);  /* pass addresses */

3. Heap Allocation with malloc

malloc allocates memory on the heap; returns void* (cast not required in C). Always check for NULL — malloc fails when out of memory.

PY
Python
data = [0] * n  # Python: heap-allocated, GC'd
C
C
int *data = malloc(n * sizeof(int));
if (!data) { perror("malloc"); exit(1); }
for (int i = 0; i < n; i++) data[i] = 0;
/* ... use data ... */
free(data);
data = NULL;
Common Pitfall
Using memory after free() (use-after-free) or freeing twice (double-free) causes undefined behaviour and security vulnerabilities.

4. Pointer Arithmetic

Adding 1 to a pointer advances it by sizeof(T) bytes — directly accessing the next element in an array.

PY
Python
for item in lst:  # Python iterator
C
C
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;   /* p points to arr[0] */
for (int i = 0; i < 5; i++) {
    printf("%d\n", *(p + i));  /* arr[i] */
}
/* arr[i] and *(arr+i) are identical */
Rule of Thumb
After free(), set the pointer to NULL immediately. Dereferencing NULL crashes visibly; dereferencing a dangling pointer silently corrupts data.

Common Mistakes

When coming from Python, developers often make these mistakes:

  • int *p declares a pointer; &x gives the address of x; *p dereferences (reads/writes the pointed-to value)
  • malloc(n * sizeof(T)) allocates n bytes on the heap; returns void* or NULL on failure
  • Every malloc must have a paired free() — no garbage collector, leaks are permanent until process exits
Common Pitfall
Don't assume C works exactly like Python. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • int *p = &x; — p holds x's address; *p reads/writes the value at that address
  • Pass &var to functions that need to modify the caller's variable
  • malloc allocates heap memory; every malloc needs a free() — no garbage collector
  • Pointer arithmetic: p+1 advances by sizeof(*p) bytes — use for array traversal
  • After free, set pointer to NULL to prevent dangling-pointer bugs
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your Python code in C to practice these concepts.
PreviousNext