Chapter 3

Variables, and the Types They Insist On

Giving values names, and saying what kind of thing they are.

The program in chapter 1 printed the same sentence every time you ran it. That’s fine for a greeting, and useless for almost everything else. Programs get interesting when they can hold on to something.

Giving a value a name

int score = 7;

Three parts, then the semicolon you’ve already been bitten by:

Now the name stands in for the value everywhere you use it:

#include <iostream>

int main() {
    int score = 7;
    std::cout << "Score: " << score << '\n';
}
Score: 7

Look closely at that cout line, because it has both kinds of thing on it. "Score: " is in quotes, so it’s literal text and gets printed exactly. score has no quotes, so it’s a name, and what gets printed is the value behind it.

Why C++ makes you say what kind

Some languages let you write score = 7 and work out the rest themselves. C++ wants to be told first, and the reason is worth understanding rather than just tolerating.

Try lying to it:

int score = "seven";
wrongtype.cpp:4:9: error: cannot initialize a variable of type 'int'
      with an lvalue of type 'const char[6]'
    4 |     int score = "seven";
      |         ^       ~~~~~~~
1 error generated.

Don’t worry about const char[6] — that’s the compiler’s name for a piece of text, and chapter 24 explains why it’s spelled so strangely. What matters is everything that didn’t happen. Your program never ran. Nothing half-worked, nothing behaved oddly at 3am for a user in another country. The mistake was caught while you were sitting right there.

That’s the deal C++ offers: tell me what kind of thing this is, and I’ll check your work before it ever runs.

Exercise 1 · Lie to the compiler

Type that line into a file and compile it. Read the message properly — file, line, column, and the two types it’s complaining about.

Then try double price = "free"; and bool ready = "yes";. Same complaint, new words. You’re getting quick at these now.

The four you need today

Type Holds Example
int Whole numbers, positive or negative int score = 7;
double Numbers with a fractional part double price = 2.5;
bool true or false, and nothing else bool passed = true;
std::string Text std::string name = "Ada";

There are more — C++ has a whole cupboard of number types — but these four cover most of what you’ll write for a long time.

Two practical notes. std::string needs #include <string> at the top, alongside <iostream>. And double is called that for historical reasons involving “double precision”; chapter 6 explains why it occasionally gives you answers that look wrong.

Changing it later

A variable varies. That’s the whole point of the name:

int score = 7;
score = 9;

The first line makes it and gives it a starting value. The second one replaces that value. No int the second time — the type was settled when the variable was created, and it can’t change.

Things that should never change

Some values shouldn’t move once set. A tax rate, a maximum, the number of cards in a deck. Say so:

const double tax_rate = 0.2;

Then try to change it, and the compiler stops you:

constchange.cpp:3:14: error: cannot assign to variable 'tax_rate' with
      const-qualified type 'const double'
    3 |     tax_rate = 0.25;
      |     ~~~~~~~~ ^
constchange.cpp:2:18: note: variable 'tax_rate' declared const here

const is a promise you make to yourself and hand to the compiler for enforcement. It costs one word, and it converts “I’m fairly sure nothing changes this” into something checked. Use it whenever you can.

The value you never set

You’re allowed to make a variable without giving it a value:

int score;
std::cout << score << '\n';

Compile that and the compiler will warn you — -Wall earning its place again:

uninit.cpp:5:18: warning: variable 'score' is uninitialized when used here
      [-Wuninitialized]
    5 |     std::cout << score << '\n';
      |                  ^~~~~

But it’s a warning, not an error, so you still get a program. Run it and it prints something: maybe 0, maybe 32767, maybe a different number tomorrow. C++ doesn’t tidy the space before handing it to you, so you get whatever was lying around.

That’s the whole habit: give every variable a value when you make it. It costs nothing and removes an entire category of baffling bug. Chapter 31 has the proper name for what you’re avoiding, and it’s a good one.

What you’re allowed to call things

Names can use letters, digits and underscores, and can’t start with a digit. No spaces, no hyphens. score, total_price and player2 are fine; total price and 2nd_player are not.

Case matters: score and Score are two different variables, which is an excellent way to confuse yourself at midnight.

Beyond the rules, use names that say what the thing is. total_price beats tp, and it beats x by a mile. You are writing for the version of you that comes back in a month having forgotten everything.

Check yourself

1. What happens when you compile int score = "seven";?

Not quite. That is what an uninitialized variable does. This is different: the compiler can see the mistake, so it refuses.

Yes. The type is the promise, and text is not a whole number. The mistake gets caught while you're sitting there rather than at 3am.

Not quite. C++ does not quietly convert text to a number and pick a fallback. It stops.

2. After const double tax_rate = 0.2; you write tax_rate = 0.25;. What happens?

Not quite. Then const would be a comment rather than a rule. The point is that the compiler enforces it.

Not quite. C++ does not silently discard instructions. If something cannot work, you get told.

Yes. And it also points back at the line where you declared it const, in case you had forgotten.

3. You write int score; and print it without ever setting a value. What do you get?

Not quite. Some languages do that. C++ does not tidy the space first, so what you get is whatever happened to be there.

Yes. A warning rather than an error, so you still get a program — and a number that may differ between runs or machines.

Not quite. It has a value. Nobody chose it, which is worse than a crash, because a crash would at least tell you.

Project

A receipt

Roughly 30 minutes

Write a program that prints a receipt for a single item. It should hold, in properly named variables:

  • the item’s name, as a std::string
  • how many were bought, as an int
  • the price of one, as a double
  • a tax rate, as a const double — it isn’t going to change while the program runs, so say so

Then work out the subtotal, the tax and the total, and print something like:

RECEIPT
-------------------------
Mechanical keyboard
2 x 49.5
Subtotal: 99
Tax:      19.8
Total:    118.8

Rules: every variable gets a value on the line that creates it, and every name says what it holds. No x, no t2.

Stretch: add a second item with its own name, quantity and price, and make the total cover both. You’ll notice you’re copying and pasting three variable declarations and changing the names. Hold that thought — it’s the itch that chapters 9 and 14 scratch.