Skip to main content
C · lesson 1 of 25
C beginner Lesson 1 of 25

Introduction to C Programming

What C is, where it runs today, and your first compiled program, with real gcc output showing sizeof, memory addresses and exit codes.

By SkillByExample · Updated

What Is C?

C is a general-purpose, procedural programming language developed at Bell Labs in the early 1970s. It gives programmers direct access to memory through pointers, compiles to efficient native machine code, and runs on virtually every platform that exists — from microcontrollers with 2 KB of RAM to supercomputers.

Unlike higher-level languages, C doesn’t hide what the computer is doing. When you write a C program, you manage memory yourself, you deal with pointers directly, and you stay close to the hardware. This is both C’s challenge and its superpower: the price of control is responsibility, and the reward is performance and portability that no managed language can match.

A Brief History

Dennis Ritchie created C between 1969 and 1973 at Bell Telephone Laboratories while working on the Unix operating system. The language evolved from an earlier language called B, which itself came from BCPL. The tight link between C and Unix meant that as Unix spread, so did C — and today the two are inseparable.

The first major standardization happened in 1989 when ANSI published the C89 standard (also called ANSI C). The ISO followed in 1990 (C90). Since then, the language has seen several revisions:

  • C99 — added variable-length arrays, // comments, stdint.h, and inline functions
  • C11 — added _Atomic, _Generic, anonymous structs/unions, and improved Unicode support
  • C17 — mostly bug fixes and clarifications to C11
  • C23 — the latest standard, adding nullptr, constexpr, binary literals, and more

Most production code today targets C99 or C11, and most compilers fully support both.

Where C Is Used

C is not a niche language. It shows up in some of the most critical software ever written, precisely because it offers the control and performance that high-stakes systems demand.

Operating Systems The Linux kernel is written almost entirely in C. So is the core of macOS (XNU kernel), Windows, and FreeBSD. When you boot your computer, the first real code that runs is C.

Embedded Systems Microcontrollers in cars, medical devices, industrial equipment, and consumer electronics run firmware written in C. When memory is measured in kilobytes and there is no operating system, C is often the only practical choice.

Databases SQLite, PostgreSQL, MySQL, and Redis are all written in C. Database engines need predictable performance and fine-grained memory control — exactly what C provides.

Networking Network stacks, routers, and protocol implementations are typically C. The TCP/IP stack in Linux, the OpenSSL library, and tools like nginx are all C.

Compilers and Interpreters The CPython interpreter (which runs your Python code) is written in C. The original C compiler was written in C. Many languages bootstrap themselves through C.

Game Engines and Graphics OpenGL, Vulkan drivers, and the lower layers of game engines often use C for performance-critical paths.

Your First C Program

Every C journey starts with the same program. Here it is, with everything explained:

#include <stdio.h>   /* Include the standard I/O library for printf */

int main(void) {     /* Every C program starts executing from main() */
    printf("Hello, World!\n");  /* \n is the newline character */
    return 0;        /* Returning 0 tells the OS the program succeeded */
}

Save it as hello.c, then compile and run it with GCC:

$ gcc -Wall -Wextra -std=c17 -o hello hello.c
$ ./hello
Hello, World!

Two separate steps happened here, and that split is the first thing C makes you notice. gcc translated the source into a native executable called hello. Running ./hello then executed that file directly, with no interpreter involved. The flags matter:

  • -Wall enables most warnings
  • -Wextra enables additional warnings
  • -std=c17 targets the C17 standard (C11 plus bug fixes)
  • -o hello names the output executable (without it, GCC writes a.out)

Every output block in this C track comes from GCC 14 on 64-bit Linux. Other compilers and platforms may differ where the standard leaves room, and the lessons point those places out.

What C Lets You See

C shows you things other languages keep hidden: how big a value is, where it lives in memory, and the exit status your program hands back to the shell.

#include <stdio.h>

int main(void) {
    int x = 5;
    printf("x = %d\n", x);
    printf("sizeof x = %zu bytes\n", sizeof x);
    printf("x lives at %p\n", (void *)&x);
    return 3;   /* any non-zero value signals failure to the shell */
}
$ gcc -Wall -Wextra -std=c17 -o where where.c
$ ./where
x = 5
sizeof x = 4 bytes
x lives at 0x7fff2fa85c8c
$ echo $?
3
$ ./where
x = 5
sizeof x = 4 bytes
x lives at 0x7ffd3cdf75fc

sizeof reports that an int takes 4 bytes on this machine. The C standard only guarantees at least 2, which is why portable code checks with sizeof instead of assuming. The address changes on every run because the operating system randomises where the stack is placed (address space layout randomisation, a security feature). Your addresses will differ from these. echo $? prints the value main returned, which is how shell scripts and CI jobs tell whether a C program succeeded.

Why Learn C?

Understand how computers actually work. When you write int x = 5; in C, you understand exactly where x lives (on the stack), how much space it takes (typically 4 bytes), and what happens when you take its address. Higher-level languages don’t teach you this.

Performance when it counts. C programs routinely outperform programs written in managed or interpreted languages because there is no runtime overhead, no garbage collector pause, and no virtual machine. The compiler translates your code directly to machine instructions.

Portability across platforms. A well-written C program can run on Linux, Windows, macOS, a Raspberry Pi, an Arduino, and a spacecraft’s flight computer with minimal changes. No other language reaches this many targets.

Career value. Systems programming jobs (kernel development, firmware, high-frequency trading, game engines, compilers) either require C or strongly prefer candidates who know it. Understanding C also makes you a better programmer in every other language.

Foundation for other languages. C++, Objective-C, C#, and Java all borrowed syntax and concepts from C. Python, Ruby, and PHP are implemented in C. Learning C is like learning the mother tongue.

C’s Design Philosophy

C trusts the programmer. It will let you shoot yourself in the foot, access memory you don’t own, and overflow buffers — not because it’s badly designed, but because that trust is what makes it powerful. The language assumes you know what you’re doing, and gives you the tools to do it efficiently.

The trade-off is that C requires discipline. You must manage memory carefully, handle errors explicitly, and understand the implications of every operation. The rewards — speed, control, and understanding — are worth the effort.

In the next section, you’ll set up your development environment and write your first real programs.

Practice

  1. Change the Hello World program so it prints two lines, Hello, C! and Learning C one example at a time, using two printf calls.
Solution
#include <stdio.h>

int main(void) {
    printf("Hello, C!\n");
    printf("Learning C one example at a time\n");
    return 0;
}
$ gcc -Wall -Wextra -std=c17 -o p1 p1.c
$ ./p1
Hello, C!
Learning C one example at a time

printf doesn’t add a newline for you. If you leave the \n off the first call, both messages run together on one line.

  1. Print the size of char, int, long, and double on your machine.
Solution
#include <stdio.h>

int main(void) {
    printf("sizeof char   = %zu\n", sizeof(char));
    printf("sizeof int    = %zu\n", sizeof(int));
    printf("sizeof long   = %zu\n", sizeof(long));
    printf("sizeof double = %zu\n", sizeof(double));
    return 0;
}
$ gcc -Wall -Wextra -std=c17 -o p2 p2.c
$ ./p2
sizeof char   = 1
sizeof int    = 4
sizeof long   = 8
sizeof double = 8

long is 8 bytes on 64-bit Linux and macOS but only 4 on 64-bit Windows, so the same source can print different numbers on different platforms. sizeof(char) is the one value the standard fixes at exactly 1.

  1. Delete the semicolon after printf("Hello, World!\n") and compile. Read the error before fixing it.
Solution
#include <stdio.h>

int main(void) {
    printf("Hello, World!\n")
    return 0;
}
$ gcc -Wall -Wextra -std=c17 -o p3 p3.c
p3.c: In function 'main':
p3.c:4:30: error: expected ';' before 'return'
    4 |     printf("Hello, World!\n")
      |                              ^
      |                              ;
    5 |     return 0;
      |     ~~~~~~

GCC points at the end of line 4 and suggests the fix. No executable is produced, so there is nothing to run until the error is fixed.

  1. Make the where program return 0 instead of 3, then check $? again.
Solution

Change return 3; to return 0;, recompile, and run it:

$ gcc -Wall -Wextra -std=c17 -o where where.c
$ ./where
x = 5
sizeof x = 4 bytes
x lives at 0x7fff79ea5abc
$ echo $?
0

The address will differ on every run, but $? is now 0, which the shell treats as success. A command chained with && (such as ./where && echo ok) only runs when the exit status is 0.

Frequently Asked Questions

Is C still relevant today?
Yes. C powers operating systems (Linux, Windows kernel), embedded systems, databases, and networking stacks. It's the lingua franca of systems programming.
How long does it take to learn C?
With consistent practice, you can write functional C programs in 4-6 weeks. Mastery takes months, but the fundamentals are achievable quickly.
Should I learn C before C++?
It's not required, but many find it beneficial. C forces you to understand memory management and low-level concepts that C++ abstracts away.