C code visualizer

See what your C code does to memory.

Step through a C program line by line and watch the call stack, the heap and every pointer between them change. Valgrind Memcheck reports each leak and invalid access with its line.

main.cStep 1 of 16
#include <stdio.h>#include <stdlib.h> typedef struct s_attempt{ const char *student; int score;} t_attempt; static int grade(t_attempt *attempt, int bonus){ attempt->score += bonus; return (attempt->score);} int main(void){ t_attempt demo = {"Grady", 40}; int *checks = malloc(2 * sizeof(*checks)); if (checks == NULL) return (1); checks[0] = 1; checks[1] = 1; int final_score = grade(&demo, checks[0] + checks[1]); printf("Grademe says: %s reached %d points. Ship it!\n", demo.student, final_score); free(checks); return (final_score == 42 ? 0 : 1);}

Stack

main()
L17
checksint *?
demot_attempt
.studentconst char *?
.scoreint?
final_scoreint?

Heap

What it draws at every step

Call stack
One frame per call, with its arguments and locals. A frame leaves the stack the moment its function returns.
Heap
Each block from malloc, calloc or realloc, with its size, until free releases it.
Pointers
An arrow from every pointer to what it reaches. A pointer into freed memory or past the end of a block is labelled.
Raw memory
Switch every value between its C value, its address and its bytes.
Memory errors
Valgrind Memcheck runs the same program and reports invalid reads and writes, uninitialized values and leaks, each with its line.

Classic programs to step through

swap.c

Swap through pointers

a and b live in swap's frame and point back at x and y in main.

#include <stdio.h>
void swap(int *a, int *b){    int tmp = *a;
    *a = *b;    *b = tmp;}
int main(void){    int x = 4;    int y = 2;
    swap(&x, &y);    printf("%d %d\n", x, y);    return 0;}

list.c

Linked list

Three nodes appear on the heap, each pointing to the next, then free releases them one by one.

#include <stdio.h>#include <stdlib.h>
struct node {    int value;    struct node *next;};
struct node *push(struct node *head, int value){    struct node *node = malloc(sizeof(*node));
    if (node == NULL)        return head;    node->value = value;    node->next = head;    return node;}
int main(void){    struct node *list = NULL;
    for (int i = 1; i <= 3; i++)        list = push(list, i);    while (list != NULL) {        struct node *next = list->next;
        printf("%d\n", list->value);        free(list);        list = next;    }    return 0;}

reverse.c

Reverse a string

Two indices walk toward each other across the char array, swapping as they go.

#include <stdio.h>#include <string.h>
void reverse(char *str){    size_t left = 0;    size_t right = strlen(str);
    while (right > left + 1) {        right--;        char tmp = str[left];        str[left] = str[right];        str[right] = tmp;        left++;    }}
int main(void){    char word[] = "stack";
    reverse(word);    printf("%s\n", word);    return 0;}

leak.c

A memory leak

The first copy loses its only pointer. Memcheck reports the lost block and the line that allocated it.

#include <stdio.h>#include <stdlib.h>#include <string.h>
char *duplicate(const char *src){    size_t len = strlen(src);    char *copy = malloc(len + 1);
    if (copy == NULL)        return NULL;    memcpy(copy, src, len + 1);    return copy;}
int main(void){    char *name = duplicate("Grady");
    name = duplicate("Ada");    if (name == NULL)        return 1;    printf("%s\n", name);    free(name);    return 0;}

Questions

Is the C visualizer free?
Yes. Running your own code needs a free account, because it runs on our machines. The program on this page steps through without one.
Which compiler runs my code?
GCC, in GNU C17 mode with -Wall -Wextra -Werror. It compiles without optimization, so every line you wrote stays a step you can stop on.
Can my program read input or take arguments?
Yes. Before a run you can give main up to 16 arguments and your program up to 20,000 characters of standard input.
What happens with an infinite loop?
The trace stops at its step limit: 300 steps by default, adjustable from 1 to 1,000.

Step through your own code