Variables and Basic Types¶
A variable is a named piece of memory that holds a value. When you write int age = 25;, you tell the compiler: "set aside enough memory to hold an integer, call it age, and store 25 in it."
In C++ every variable has a type that is fixed for its entire lifetime. You declare the type up front; you cannot later store a string in a variable declared int. This is what makes C++ a statically typed language.
Built-in types¶
The types you will use day-to-day:
| Type | Holds | Typical size | Example value |
|---|---|---|---|
bool |
true or false | 1 byte | true |
char |
a single character | 1 byte | 'A' |
int |
whole numbers | 4 bytes | 42 |
double |
decimal numbers (floating point) | 8 bytes | 3.14159 |
float |
decimal numbers, less precision | 4 bytes | 3.14f |
Prefer int for whole numbers and double for decimal numbers unless you have a specific reason to do otherwise (float for memory-constrained embedded code, for instance). Sizes are typical for desktop platforms; they can differ on microcontrollers. For a complete reference, see cppreference's entry on Fundamental types.
The standard library adds a few more types you will use constantly in desktop C++. They are not "built in," but on the desktop they are everywhere:
| Type | Holds | Header |
|---|---|---|
std::string |
text; see Strings | <string> |
std::vector |
a resizable list of values | <vector> |
On small microcontrollers these are often unavailable; there you use fixed-size arrays and buffers instead (see Arduino vs. Desktop C++).
Declaring and initialising¶
You can declare a variable and assign to it in one step (recommended) or split it into two:
int quantity = 10; // declare and initialise (preferred)
double price{5.99}; // braces also work, and are stricter about conversions
int count; // declare only; `count` now holds a garbage value
count = 5; // assign later
Always initialise variables when you declare them. Reading from an uninitialised variable is undefined behaviour. The program might print garbage, might crash, might appear to work fine and then break on a different compiler. The compiler will not warn you in every case.
Two extra reasons to initialise eagerly:
- The initial value documents what the variable is for.
int retries = 0;tells the reader somethingint retries;does not. - If you do not have a sensible initial value yet, that is usually a sign the variable should be declared later, closer to where it is actually used.
Brace initialisation¶
You will see two ways to initialise:
Both work. Brace initialisation is stricter: it refuses narrowing conversions that silently lose information.
int a = 3.7; // compiles; silently truncates to 3
int b{3.7}; // compile error: narrowing from double to int
For numeric types it is up to you. For class types (which you will meet in Chapter 4) brace initialisation often does the right thing more reliably.
Type inference with auto¶
Sometimes the type is obvious from the right-hand side and writing it out is just noise:
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Without auto:
std::vector<int>::iterator it = numbers.begin();
// With auto, the compiler figures out the type from numbers.begin():
auto it = numbers.begin();
(You will meet std::vector shortly, in Strings and Vectors; its iterators are Chapter 3 material. Here they just supply a deliberately long type name, so the value of auto is obvious.)
auto lets the compiler deduce the type for you. It is not "dynamic typing"; the type is still fixed and checked at compile time. Use auto when the type is verbose or when the exact type does not matter to the reader; spell it out when the explicit type helps clarity.
Naming variables¶
A name can contain letters, digits, and underscores, and must start with a letter or underscore. Names are case-sensitive: count and Count are different variables.
Two conventions used throughout this book:
- Local variables and function parameters:
lowerCamelCase, likemaxSpeed,sensorIndex. - Constants and macros:
UPPER_SNAKE_CASE, likeMAX_RETRIES.
Pick descriptive names. int x is fine for a loop counter; int maxAllowedTemperature is far better than int t if that is what the variable means.
Constants¶
If a value should never change after it is set, mark it const:
The compiler enforces this, which catches a class of bugs and also documents intent: "this is a value, not a setting."
The same applies to ordinary local variables, not just named constants like maxRetries: if you compute a value and never change it again, make it const. Reaching for const by default — and dropping it only when you genuinely need to reassign — documents that the value is settled and lets the compiler stop you (or a future editor) from overwriting it by accident.
Summary¶
- Every variable has a type, fixed at declaration.
- Always initialise; uninitialised reads are undefined behaviour.
- Prefer
intanddoublefor arithmetic. Useboolfor true/false. Usestd::stringfor text. - Prefer
constfor anything you don't reassign — not just named constants. - Pick descriptive names.
Scope (the region in which a variable exists) was covered in Basic Structure. The short version: variables declared in a block disappear when the block ends.