JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

Types, Variables, and Your First Real Program

You already ran 'hello, world' and saw the edit-compile-run loop. Now we slow down and meet C's real raw material: typed boxes called variables. By the end you'll write, compile, and reason about a small program that actually computes something — and know exactly what every line means.

Where we are on the ladder

In the Foundations rung you saw the big picture: a computer is a machine that stores its own instructions in memory, and to run your own program you went round the edit-compile-run loop — type source code, hand it to a compiler, run the executable it produced. You even printed hello, world. That program was a polite greeting, but it didn't compute anything. This rung, Learning C, fixes that: across five guides we'll pick up enough C to write real, small programs.

We start at the bottom, with the raw material every program is built from: data, and the typed boxes that hold it. Later guides add operators and decisions, then functions, then arrays and structs, then a tour of the library. We deliberately stop before pointers — addresses and the things that name them get a whole rung of their own, because they are powerful and genuinely error-prone, and rushing them is how beginners get hurt. For now, everything we write lives in plain, named variables.

A variable is a labelled box with a type

Picture memory the way the Foundations rung described it: one long shelf of numbered cells. A variable is your way of claiming a few of those cells, giving them a name you can say out loud, and promising the compiler what kind of thing will live there. That promise is the type. When you write `int age = 27;`, you are telling C: reserve room for a whole number, call it `age`, and start it at 27. The compiler now knows how many cells to set aside and how to read them back.

Why insist on a type at all? Because the same bit pattern in memory means different things depending on how you read it — that is a deep idea you'll meet again in the Bits & Bytes rung. The type is the lens. `int` reads a clump of cells as a whole number; `double` reads (a different-sized) clump as a number with a fractional part; `char` reads a single cell as a small integer that usually stands for a text character. C's core basic types are exactly this small menu: `char`, `int`, `float`, `double`, plus the `short`/`long` size variants — and `_Bool` (`bool`) and `void`, which we'll meet shortly.

Declaring, defining, and the danger of empty boxes

The line `int age = 27;` actually does two jobs at once, and it's worth pulling them apart. First it declares the name `age` and its type, so the compiler knows the box exists. Then it defines that box — reserves the actual cells — and initializes it, writing 27 into them. C draws a real line between declaration and definition; for a simple local variable they usually happen on the same line, but you'll see them split apart when you meet functions and multiple files.

The most important word in that sentence is initialize. If you write `int age;` and stop, you have a box but you never put anything in it. C does not helpfully zero it for you (a local variable, anyway). Reading `age` now gives you whatever bit pattern was already sitting in those cells — leftover garbage from whatever ran before. This is the classic uninitialized-variable bug, and it is nastier than it sounds: the garbage might happen to be 0 today and 4 million tomorrow, so the bug appears and vanishes seemingly at random. The fix is a discipline, not a trick: give every variable a value the moment you create it.

Names, lifetimes, signed and unsigned

A variable doesn't live forever, and its name isn't visible everywhere. The braces `{ ... }` around a block of code mark a scope: a variable declared inside them is born when control enters and ceases to exist when control leaves. That is its scope and lifetime. This is why you can use `i` as a loop counter in two different places without them colliding — each lives and dies inside its own block. It also means returning the address of a local variable (something pointers tempt you into later) is a trap, because the box is gone by the time anyone looks.

One more choice rides on every integer type: whether it can be negative. A plain `int` is signed — it spends one bit on the sign and so covers, say, about minus two billion to plus two billion. An `unsigned int` of the same size has no negatives, so it reaches twice as high on the positive side. That's the signed/unsigned distinction. Use unsigned for things that genuinely can't be negative (a count, a size, a bit pattern), but stay alert: subtracting past zero in an unsigned type doesn't go negative, it wraps around to a huge number, which is its own well-known surprise.

And whether signed or unsigned, every integer box has a fixed number of cells, so it has a ceiling. Push a value past the top and you hit overflow. For unsigned types the standard defines the wrap precisely; for signed types overflow is undefined behavior, a subtler hazard we'll take seriously in its own rung. The honest summary for now: integers are not the infinite numbers of mathematics — they are finite, and knowing the edges is part of writing C that doesn't lie to you.

Your first real program

Let's put it together. Every C program starts running at a function called `main`, and `main` hands back a small integer when it finishes — that's its exit status, 0 meaning success by long convention. (`main` can also receive command-line arguments through argc and argv, but we don't need those yet.) Here is a program that actually computes: it converts a Celsius temperature to Fahrenheit using the formula F = C * 9 / 5 + 32.

#include <stdio.h>

int main(void) {
    int celsius = 100;
    int fahrenheit = celsius * 9 / 5 + 32;
    printf("%d C is %d F\n", celsius, fahrenheit);
    return 0;
}
celsius-to-fahrenheit: typed boxes, one computation, a printed result, a clean exit.
  1. Save it as main.c, then build it: `gcc -Wall -Wextra main.c -o temp` — the -o names the executable 'temp' instead of the default a.out.
  2. Run it: `$ ./temp` prints '100 C is 212 F'. The `%d` placeholders in printf() are filled, in order, by `celsius` and `fahrenheit`.
  3. Check the exit status: right after, `$ echo $?` shows 0, the value our `return 0;` sent back to the shell to say 'all good'.
  4. Now experiment: change 100 to 0 and rebuild — you should get 32 F. The whole loop, edit to result, is the rhythm of writing C.

Two honest footnotes hide in those seven lines. The `100` and `32` are literal constants — values baked straight into the source. And the arithmetic is integer arithmetic: because `celsius`, 9, and 5 are all `int`, `celsius * 9 / 5` rounds toward zero at every step, so 37 C comes out as 98 F, not 98.6. That isn't a bug in C; it's C being exact about what you asked for. Want the fraction? Make the numbers `double` and print with `%f` — a small change that quietly teaches the lesson the whole rung is built on: in C, the type you choose decides the answer you get.