Skip to content

Language guide

Learn C

The small language operating systems are written in, and where memory is yours to manage.

C on SkillAIVibe

Runs in your browser

Real C runs inside a sandbox in your own browser — clang via Emscripten 3.1.24 (2026-09-12 build). Nothing you write is sent to a server. Last verified against the sandbox's checks on .

10 exercises in order, each teaching exactly one new idea. Every one runs in this tab, checks your output, and explains what went wrong in plain language.

  1. Hello, Out Loudprintf() puts text on the screen
  2. Name TagA variable is declared with a type, and holds one value under a name
  3. Party PlannerC does arithmetic with + - * / and %, and / between two ints throws away the remainder
  4. Umbrella or Notif/else chooses between two different blocks of code
  5. Countdowna for loop repeats a block a fixed number of times
  6. The Clapping GameAn if inside a for loop is decided again on every pass
  7. The Scoreboarda number between % and the conversion letter gives printf a fixed field width
  8. Packing ListAn array holds several values of one type in order, indexed from zero with []
  9. Rainfall WeekA variable declared before a loop carries its value from one pass to the next
  10. The Cafe TicketAssembling a complete program from parts you already know

C lessons

Longer explanations of each idea, with examples that were executed before they were published. Read one when an exercise's one new idea deserves more than a paragraph.

  1. 1.Your First C Program
  2. 2.Variables and Types in C
  3. 3.Control Flow in C: if, switch and Loops
  4. 4.C Functions: Prototypes, Arguments and Return Values
  5. 5.Arrays and Strings in C
  6. 6.Pointers in C
  7. 7.Dynamic Memory in C: malloc and free
  8. 8.Structs and typedef in C

What C is

C is a small compiled language from the early 1970s that sits very close to the machine: you decide how memory is laid out, when it is allocated and when it is given back. Writing it feels precise and a little unforgiving — there is no garbage collector, no built-in string type and very few safety nets — but a C program is just a set of functions calling each other, and the whole language fits in a short book. Operating system kernels, compilers and the reference interpreters of languages such as Python and Lua are written in it, which is why its ideas turn up everywhere.

Where C is used

Operating systems and kernels
The Linux kernel and the BSD kernels are written in C, and the device drivers that talk directly to hardware are usually C too.
Embedded systems and firmware
The code inside washing machines, car controllers, medical devices and hobby microcontroller boards runs on chips with very little memory, where C's tiny runtime and predictable output are essential.
Language runtimes and interpreters
CPython (the standard Python interpreter), Lua and the C standard library that most other languages call into are C code, so a C programmer can read the layer underneath the language they use every day.
Databases and system tools
SQLite, PostgreSQL and Redis are written in C, as are the classic Unix command-line utilities.
Performance-critical libraries
When a Python or JavaScript library needs to be fast — compression, image decoding, cryptography — the hot part is often a C library with a thin wrapper around it.

Your first C program

Saved as hello.c. You can paste it straight into the playground to see it run.

C
#include <stdio.h>

int main(void) {
    int apples = 3;
    double price = 0.5;

    printf("Hello from C.\n");
    printf("%d apples cost %.2f.\n", apples, apples * price);
    return 0;
}

What it prints

Output
Hello from C.
3 apples cost 1.50.
  1. Line 1 pulls in the standard input/output header, which is where printf is declared. Without it the compiler does not know what printf is.
  2. Line 3 declares main, the function every C program starts in. void in the brackets says it takes no arguments, and the int before it says it hands a whole number back to the operating system when it finishes.
  3. Lines 4 and 5 declare two variables. In C every variable has a fixed type written before its name: int holds whole numbers and double holds decimals. Each statement ends with a semicolon.
  4. Line 7 prints a line of text. The \n at the end is the newline character; C does not add one for you, so without it the next print would continue on the same line.
  5. Line 8 shows how C formats values. %d is a placeholder for an int and %.2f for a double shown to two decimal places; the values after the format string fill the placeholders in order. apples * price mixes an int and a double, so C widens the int and the result is the double 1.5, printed as 1.50.
  6. Line 9 returns 0, the conventional way to say the program finished without error, and line 10 closes main.

Try it in the C playground →

Run C on your own computer

C needs a compiler on your machine; there is no interpreter to type lines into. Every major platform has a free, well-supported one, and the setup is a single install followed by a two-step compile-then-run habit.

  1. Install a compiler

    On Debian or Ubuntu Linux, install the build-essential package, which brings in GCC; other distributions have an equivalent package. On macOS, run xcode-select --install to get Apple's command-line tools, which include Clang and a gcc command that forwards to it. On Windows, the usual routes are a GCC build installed through MSYS2, the C compiler in Microsoft's Visual Studio Build Tools, or a Linux environment under WSL. The commands below assume GCC; Clang accepts the same ones.

    Shell
    sudo apt install build-essential
  2. Check it works

    Open a terminal and ask the compiler for its version. If you installed Clang instead, clang --version does the same job.

    Shell
    gcc --version
  3. Save the file and compile it

    Save the program as hello.c, then compile it from the folder it is in. The compiler writes an executable called hello (hello.exe on Windows). The -Wall and -Wextra flags switch on the warnings that catch most beginner mistakes; use them from day one and treat every warning as something to fix.

    Shell
    gcc -Wall -Wextra hello.c -o hello
  4. Run the executable

    Run the file you just built. In PowerShell or Command Prompt on Windows the command is .\hello instead. Notice the two separate steps: if you change the source, you must compile again before the change shows up.

    Shell
    ./hello
  5. Pick an editor that shows warnings

    C files are plain text, so any editor works. One that runs the compiler and underlines its warnings as you type — VS Code with a C extension, or Visual Studio on Windows — makes the compile-fix-compile loop much faster.

A learning order for C

Stages, not a timetable. Each one exists because the next would not make sense without it, and how long each takes depends on how much you write.

  1. Stage 1. Compiling, printing and variables

    • the compile-then-run cycle
    • printf and format specifiers
    • int, double and char
    • arithmetic and integer division
    • reading compiler errors and warnings

    In C the compiler is your first teacher, so learning to read its messages comes before anything else. Integer division and format specifiers are where the first surprises live.

  2. Stage 2. Control flow and functions

    • if / else and comparisons
    • while and for loops
    • switch
    • writing your own functions
    • function prototypes and header files

    C programs are nothing but functions. The compiler has to see a function's signature before the function is called, which is why prototypes and header files appear so early.

  3. Stage 3. Arrays, strings and pointers

    • arrays and indexing
    • strings as char arrays ending in '\0'
    • pointers, & and *
    • pointer arithmetic
    • passing arrays to functions

    This is the stage that defines C. A pointer is just an address, but almost every serious C bug is a pointer or array mistake, so this deserves more time than any other stage.

  4. Stage 4. Memory and structs

    • the stack versus the heap
    • malloc, calloc and free
    • struct and typedef
    • building a linked list
    • AddressSanitizer (-fsanitize=address)

    Dynamic memory lets a program handle data whose size is not known in advance, and freeing it exactly once is the discipline C demands in return. A sanitizer makes that discipline visible while you learn it.

  5. Stage 5. Files, the preprocessor and multi-file programs

    • fopen, fgets, fprintf and fclose
    • #define and #include
    • splitting a program across .c and .h files
    • a first Makefile
    • the standard library headers worth knowing

    Once a program outgrows one file you need to understand how the pieces are compiled separately and linked together. The preprocessor is a text-substitution step that runs before the compiler, and knowing that explains most of its oddities.

  6. Stage 6. Undefined behaviour and real code

    • what undefined behaviour means
    • integer overflow and signedness
    • buffer overflows and bounds checking
    • compiler flags: -O2, -g and -fsanitize
    • reading someone else's C codebase

    C trusts you completely, which means the compiler may do anything at all when you break its rules. Knowing which rules matter is what turns someone who can write C into someone who can be trusted with it.

Mistakes beginners make in C

Reading a variable before giving it a value
int total; followed by total = total + 5 reads whatever bytes happened to be in that memory. C does not zero local variables, and reading one is undefined behaviour: the program may print rubbish, print 0 today and 4198 tomorrow, or be optimised into something you did not write. Compiling with -Wall makes GCC warn that the variable 'may be used uninitialized'; always initialise on the line you declare.
Walking off the end of an array
int scores[5] has valid positions 0 to 4, so scores[5] is past the end. C performs no bounds check, so you silently read or overwrite neighbouring memory, and the crash, if there is one, happens somewhere else entirely. On Linux and macOS, compiling with -fsanitize=address turns this into an immediate, precise report ('stack-buffer-overflow' or 'heap-buffer-overflow') with the line number.
Forgetting that a string needs its terminator
A C string is a char array that ends with a zero byte, '\0'. char word[5] = "hello" leaves no room for it, so printf and strlen keep reading past the end until they happen to find a zero. Size the array one larger than the text, or let the compiler count for you with char word[] = "hello".
Integer division throwing away the fraction
7 / 2 is 3 in C, not 3.5, because both operands are ints and so the result is an int. Make one side a double — 7.0 / 2, or (double) a / b — when you want the decimal part. There is no warning for this; the compiler considers it exactly what you asked for.
Freeing memory twice, or using it after free
Calling free on the same pointer twice, or reading through a pointer after it has been freed, is undefined behaviour and a long-standing source of security holes. The GNU C library often catches the first case and aborts with 'free(): double free detected in tcache 2'; the second case usually produces no message at all. Set a pointer to NULL straight after freeing it, and let AddressSanitizer check your programs while you learn.

Strengths and trade-offs

Where it is strong

  • Direct control over memory and layout, which is exactly what operating systems, drivers and firmware need.
  • A small language: the core syntax fits in a short reference, and it is the ancestor of the syntax used by C++, Java, C#, JavaScript and Go, so those languages look familiar afterwards.
  • Compilers exist for an enormous range of processors, from desktop chips to tiny microcontrollers, and a C library can be called from nearly every other language.
  • Compiled programs start instantly, use little memory and need no runtime to be installed alongside them.

Where it is not

  • No memory safety: an off-by-one, a dangling pointer or an uninitialised variable is undefined behaviour, and the compiler is allowed to do anything in response. These mistakes are a long-standing source of crashes and security vulnerabilities.
  • No built-in string type, growable list, dictionary or error handling. You write or find a library for each, and you check return values by hand.
  • Slow to write compared with Python, Go or C#: a task that takes one line in those languages often takes a function in C.
  • Dependencies, packaging and cross-platform builds have no single standard tool; each project chooses its own build system, and beginners often spend their first hours on setup rather than code.

Who C is for

C is a good first language for people who want to understand what a computer is actually doing — students in systems or embedded courses, anyone curious about operating systems, and hobbyists working with microcontrollers. It is also a strong second language for programmers who already know something higher level and keep meeting the word 'memory' without knowing what it means. It is a poor choice if your goal is a website, a mobile app, a data analysis or simply getting something working quickly; Python, JavaScript or C# will get you there sooner, and C's lessons will still be waiting when you want them.

Questions about learning C

Should I learn C before C++?
Not necessarily. C++ began as an extension of C and still accepts most C code, so the basic syntax overlaps, but modern C++ is written very differently, with classes, templates and a standard library that does the memory management C makes you do by hand. Learn C if you want the memory-level understanding on its own terms, or if you want to work on kernels, embedded systems or other places where C is the language in use. If your real target is C++, you can start there and pick up the C subset along the way.
Is C still worth learning?
Yes, for specific reasons rather than general ones. The Linux and BSD kernels, most embedded firmware and the interpreters underneath languages such as Python are written in C, and that code is not going away. Even if you never write C for a living, understanding pointers, the stack and the heap makes you better at every other language, because it shows you what they are hiding from you.
Why does my program print rubbish or crash at random?
Almost always because it has undefined behaviour: an uninitialised variable, an array index past the end, a missing string terminator or a pointer to memory that has already been freed. C does not check for any of these, so the symptom shows up far from the cause and can change from one run to the next. Compile with -Wall -Wextra -fsanitize=address,undefined and run again; the sanitizers report the exact line the first time a rule is broken.
What is the difference between gcc and clang?
They are two separate compilers that both implement the C standard. GCC is the GNU project's compiler and the usual default on Linux; Clang is the LLVM project's compiler and is what Apple ships on macOS. For learning they are interchangeable: the same source compiles with both, the flags on this page work on both, and their error messages differ only in wording.

The primary source

When this guide and the official documentation disagree, the documentation is right and we would like to hear about it.

Other languages

All languages and paths · Programming glossary · Your progress