Programming Languages

C

A small, compiled language close to the hardware. Manual memory, pointers, and no safety net — the language operating systems are written in.

Level: intermediate

What is it?

C is a compact, statically typed, compiled language that maps closely onto machine instructions and memory. You manage memory yourself with malloc and free, work directly with pointers and arrays, and get no bounds checking. Unix and Linux, most databases, and many language runtimes are written in C, and its calling conventions are the lingua franca of foreign function interfaces.

Why does it matter?

Reading C shows how the systems in this curriculum actually work: a system call is a C function, a kernel data structure is a struct, and a segmentation fault is a pointer bug you can now explain. It is also where the cost of every operation is visible.

Mental model

A manual-transmission sports car. Nothing is hidden and you can go exactly as fast as you like, but there is no lane-keeping assistant: if you drift, you crash.

How it works

  • Statically typed, compiled to native code through a preprocessor, compiler, assembler, and linker.
  • Memory is yours: malloc/free on the heap, automatic storage on the stack, and no garbage collector.
  • Arrays are contiguous blocks with no length attached; strings are char arrays ending in a null byte.
  • Undefined behavior — out-of-bounds access, signed overflow, use after free — lets the compiler assume it never happens, so bugs can be silent and strange.
  • Header files declare interfaces; the linker joins compiled object files into an executable.
  • The standard library is small; POSIX adds files, processes, threads, and sockets.

Steps

  • Preprocess includes and macros
  • Compile to assembly
  • Assemble to object code
  • Link with libraries
  • Load and run as a process

Code example: Strings are bytes you must terminate

#include <stdio.h>
#include <string.h>

int main(void) {
    char name[16];
    strncpy(name, "kernel", sizeof name - 1);
    name[sizeof name - 1] = '\0';          /* always terminate */
    printf("%s has %zu chars\n", name, strlen(name));
    return 0;
}

Real-world usage

  • Operating system kernels, drivers, and embedded firmware
  • Language runtimes and databases
  • Performance-critical libraries exposed to other languages

Common mistakes

  • Writing past the end of a buffer (the classic security hole).
  • Forgetting to free memory, or freeing it twice.
  • Trusting sizeof on a pointer parameter as if it were the array's size.

Interview questions

What happens between gcc main.c and running ./a.out?

The preprocessor expands includes and macros, the compiler translates C to assembly, the assembler produces object code, the linker combines it with libraries into an executable, and the OS loader maps it into a new process and starts it.

What is undefined behavior?

Code the standard places no requirements on, such as out-of-bounds access or signed overflow. The compiler may assume it never occurs, so the program can crash, corrupt data, or appear to work, differently between builds.

What is the difference between malloc and a local array?

A local array lives in the stack frame and disappears on return. malloc reserves heap memory that lasts until free is called, and it can be returned from a function.

Prerequisites

Related concepts

Continue learning

Browse the full computer science library