Basics & Setup

Variables, Data Types, and Operators

DIFFICULTY: Beginner READ TIME: 15 mins

Welcome back! Today we are going to talk about the absolute core building blocks of any C++ program: Variables, Data Types, and Operators.

Without these three, your code wouldn’t be able to store data, make decisions, or calculate anything. Think of it this way:

  • Variables: Labeled containers where you store your data.
  • Data Types: The label on the container telling C++ what kind of data is inside (whole numbers, text, decimals).
  • Operators: The operations you perform on those containers (like adding them together, comparing them, etc.).

A Quick Real-World Analogy

Think about the calculator app on your phone:

  1. When you type in 5 and 10, the calculator stores those numbers in its memory (inside variables).
  2. The calculator knows these are whole numbers, not words (that’s the data type).
  3. When you press the + button, it uses an addition operator to calculate 15.

Let’s dive into how this works in C++!


Understanding Variables

What are Variables?

In C++, a variable is a named portion of the computer’s memory. When you declare a variable, you tell the computer to reserve a small slot of RAM for your program, and you give that slot a name (an identifier) so you can retrieve it later.

Rules for Declaring Variables

C++ is pretty strict about variable names. When naming your variables, keep these rules in mind:

  • Variable names must start with a letter or an underscore _ (e.g., age, _score).
  • They can contain letters, numbers, and underscores, but no spaces or special characters (@, #, $, etc.).
  • Names are case-sensitive (e.g., Age, AGE, and age are three completely different variables).
  • You cannot use C++ reserved keywords (like int, double, or return).

Syntax for Declaring Variables

To create a variable, you must tell the compiler what type of data it holds, give it a name, and optionally assign it an initial value:

data_type variable_name = value;

Let’s look at a concrete example:

int age = 25;
  • int (Data Type): Tells C++ that this variable holds a whole number integer.
  • age (Variable Name): The name we use to refer to this RAM storage slot.
  • 25 (Value): The actual data we want to store.

Declaring Multiple Variables at Once

If you need to declare several variables of the exact same type, you don’t have to write a new line for each. You can group them on a single line separated by commas:

#include <iostream>

int main() {
    int a = 10, b = 20, c = 30;
    std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
    return 0;
}

Output:

a: 10, b: 20, c: 30

Scope of Variables

The scope of a variable determines where in your code that variable can be accessed. C++ has two main types of scopes:

1. Local Variables

A variable declared inside a function or a block of code (enclosed in curly braces { }) is a local variable. It is born when the block starts, and dies when the block ends. Nothing outside those curly braces can see or use it.

2. Global Variables

A variable declared outside of all functions (usually at the very top of your file) is a global variable. It is alive for the entire lifespan of your program and can be read or modified by any function.

Variable Shadowing & The Scope Resolution Operator (::)

If you have a global variable and a local variable with the exact same name, the local variable wins inside its function. This is called variable shadowing.

If you want to force C++ to look at the global variable instead of the local one, you prefix the variable name with the scope resolution operator ::.

Let’s look at this shadowing in action:

#include <iostream>

int x = 50; // Global variable x

int main() {
    int x = 10; // Local variable x (shadows the global x)
    
    std::cout << "Local x: " << x << std::endl;
    std::cout << "Global x: " << ::x << std::endl; // Access global with ::
    
    return 0;
}

Output:

Local x: 10
Global x: 50

Data Types in C++

When you store a value, the compiler needs to know its data type so it can decide:

  1. How to interpret the bits in memory (e.g. text vs. floating-point math).
  2. How many bytes of RAM to allocate.

1. Integer Types (Whole Numbers)

For counting and whole values, C++ provides int. By default, an int occupies 4 bytes of memory. You can use modifiers to change the size and range of integers:

Type NameSize in RAMValue Range
short (or short int)2 Bytes (16 bits)-32,768 to 32,767
int4 Bytes (32 bits)-2 Billion to 2 Billion
long (or long int)4 Bytes (32 bits)Same as int (minimum 32-bit)
long long (or long long int)8 Bytes (64 bits)-9 Quintillion to 9 Quintillion
unsigned int4 Bytes (32 bits)0 to 4.29 Billion (Positive numbers only)

Example:

#include <iostream>

int main() {
    short smallNum = 10;
    int regularNum = 1000;
    long long hugeNum = 100000LL; // LL suffix forces compiler to read as long long
    
    std::cout << "smallNum: " << smallNum << "\nregularNum: " << regularNum << "\nhugeNum: " << hugeNum << std::endl;
    return 0;
}

Output:

smallNum: 10
regularNum: 1000
hugeNum: 100000

2. Floating-Point Types (Decimals)

For storing values with decimal points, use floating-point types. C++ has three options depending on how much precision you need:

TypeSize in RAMPrecision
float4 Bytes~7 decimal digits
double8 Bytes~15 decimal digits (Default choice in C++)
long double8 or 16 BytesExtended precision

Example:

#include <iostream>

int main() {
    float piFloat = 3.14f; // 'f' suffix specifies float literal
    double piDouble = 3.1415926535;
    
    std::cout << "float: " << piFloat << "\ndouble: " << piDouble << std::endl;
    return 0;
}

Output:

float: 3.14
double: 3.14159

3. Character Type (Letters & Symbols)

For single characters, we use char. A char occupies 1 byte of memory and is always wrapped in single quotes ' '. Under the hood, C++ stores characters as ASCII integer values.

#include <iostream>

int main() {
    char grade = 'A';
    std::cout << "Grade: " << grade << std::endl;
    return 0;
}

Output:

Grade: A

4. Boolean Type (True/False)

Booleans store logical states: true (renders as 1 in the terminal) or false (renders as 0). It uses the bool keyword and takes 1 byte of memory.

#include <iostream>

int main() {
    bool isCPlusPlusCool = true;
    bool isBoring = false;
    
    std::cout << "isCPlusPlusCool: " << isCPlusPlusCool << "\nisBoring: " << isBoring << std::endl;
    return 0;
}

Output:

isCPlusPlusCool: 1
isBoring: 0

Constants and Literals

Constants

If you want to prevent a variable’s value from being changed after initialization, prefix its declaration with the const keyword. This makes the variable immutable:

const double PI = 3.14159;

Trying to assign a new value to PI later in your code will trigger a compile-time compiler error.

Literals

Literals are hardcoded values written directly into your source code. Here are some examples:

#include <iostream>

int main() {
    int decVal = 26;       // Decimal literal
    int hexVal = 0x1A;     // Hexadecimal literal (starts with 0x)
    int binVal = 0b11010;  // Binary literal (starts with 0b)
    
    std::cout << "decVal: " << decVal << "\nhexVal: " << hexVal << "\nbinVal: " << binVal << std::endl;
    return 0;
}

Output:

decVal: 26
hexVal: 26
binVal: 26

Type Conversion in C++

Sometimes you need to convert a value from one data type to another. C++ supports two kinds of conversions:

1. Implicit Conversion (Automatic)

The compiler does this automatically when you assign a value of a smaller type to a larger type (promotions). It is safe and does not lose data.

int myInt = 10;
double myDouble = myInt; // Safe promotion: int to double

The standard implicit promotion scale ranges from smaller/restricted types to larger types:

graph LR
    bool --> char --> short[short int] --> int --> unsigned_int[unsigned int] --> long --> long_long[long long] --> float --> double --> long_double[long double]
    
    style bool fill:#e5eeff,stroke:#0058be,stroke-width:1px
    style long_double fill:#d4e3ff,stroke:#0060ac,stroke-width:2px

2. Explicit Conversion (Type Casting)

When you convert a larger data type to a smaller type (e.g. converting double to int), you risk losing decimal information. The compiler will warning you, so you must explicitly instruct it to cast the values.

There are two primary ways to write explicit casts:

#include <iostream>

int main() {
    double decimal = 5.75;
    int whole = static_cast<int>(decimal); // Truncates .75
    
    std::cout << "whole: " << whole << std::endl;
    return 0;
}

C-Style Cast (Legacy)

double decimal = 5.75;
int whole = (int)decimal; // Deprecated but widely seen

Output:

whole: 5

Working with Operators in C++

Operators are mathematical or logical symbols that process variables. We can classify C++ operators into 5 main categories:

1. Arithmetic Operators

Used for standard mathematical equations:

OperatorOperationExample
+Additiona + b
-Subtractiona - b
*Multiplicationa * b
/Divisiona / b
%Modulo (Remainder)a % b
++Increment++a (Adds 1 to a)
--Decrement--a (Subtracts 1 from a)

2. Logical Operators

Used to evaluate truth values between boolean expressions:

OperatorOperationMeaning
&&Logical ANDReturns true if both conditions are true (a && b)
||Logical ORReturns true if at least one condition is true (a || b)
!Logical NOTInverts the truth value (!a)

3. Assignment Operators

Used to store values in variables, including shorthand operations:

OperatorExampleEquivalent to
=a = 5a = 5
+=a += 2a = a + 2
-=a -= 2a = a - 2
*=a *= 2a = a * 2
/=a /= 2a = a / 2
%=a %= 2a = a % 2

4. Comparison Operators

Used to compare two values, returning a boolean (true/false):

OperatorMeaningExample
==Equal toa == b
!=Not equal toa != b
>Greater thana > b
<Less thana < b
>=Greater than or equal toa >= b
<=Less than or equal toa <= b

5. Bitwise Operators

Used for low-level byte manipulation on binary bits:

OperatorOperationExample (Using 5 [0101] and 3 [0011])
&Bitwise AND0101 & 0011 -> 0001 (1 in decimal)
|Bitwise OR0101 | 0011 -> 0111 (7 in decimal)
^Bitwise XOR0101 ^ 0011 -> 0110 (6 in decimal)
~Bitwise NOT~0101 -> 1010
<<Left Shift0101 << 1 -> 1010 (Shifts bits left by 1)
>>Right Shift0101 >> 1 -> 0010 (Shifts bits right by 1)

Bitwise AND (&) Truth Table

ABA & B
111
100
010
000

Bitwise OR (|) Truth Table

ABA | B
111
101
011
000

Operator Precedence

When writing equations with multiple operators, C++ uses precedence rules to decide what gets calculated first. Unary operations and multiplication/division have higher priority than addition/subtraction or assignments.

[Lowest Precedence] =====================================================> [Highest Precedence]
Assignment (=)  -->  Logical OR (||)  -->  Logical AND (&&)  -->  Arithmetic Add (+,-)  -->  Arithmetic Mul (*,/)  -->  Unary (++,--)

Frequently Asked Questions

What is variable shadowing?

It happens when you declare a local variable inside a function with the exact same name as a global variable. The local variable temporarily hides the global variable, meaning changes inside the function only affect the local one.

What happens if I write unsigned int and assign it a negative number?

Assigning a negative value to an unsigned integer type causes integer overflow wrap-around. For example, assigning -1 to an unsigned int will actually store 4294967295 in memory (the maximum possible unsigned value).

What is the binary arithmetic behind 0101 | 0011?

Bitwise OR checks each bit column. If either bit is 1, the output is 1:

  0 1 0 1   (decimal 5)
| 0 0 1 1   (decimal 3)
─────────
  0 1 1 1   (decimal 7)

So the output is 0111 (which is 7 in decimal).

quiz Test Your Understanding

Which keyword makes a variable constant (unchangeable) in C++?