Variables
beginnerPart of C++ Basics
Theory
Variables are named memory locations that store data. Every variable in C++ has a type that determines what kind of data it can hold and what operations can be performed on it.
Basic Data Types
C++ provides several fundamental data types:
| Type | Size (typical) | Range | Usage |
|------|---------------|-------|-------|
| int | 4 bytes | -2.1B to 2.1B | Whole numbers |
| float | 4 bytes | ~1.2E-38 to 3.4E+38 | Single-precision decimal |
| double | 8 bytes | ~2.3E-308 to 1.7E+308 | Double-precision decimal |
| char | 1 byte | -128 to 127 or 0-255 | Single character |
| bool | 1 byte | true or false | Boolean logic |
int age = 25;
float price = 19.99f; // f suffix for float
double pi = 3.14159265358979;
char grade = 'A';
bool isActive = true;Modifiers
Type modifiers alter the range of basic types:
short— reduces size (e.g.,short int)long— increases size (e.g.,long long int)signed— allows negative values (default)unsigned— only non-negative values (doubles positive range)
unsigned int count = 100; // 0 to ~4.2B
long long int big = 1000000000000LL;
short int small = 32000;
unsigned char byte = 255; // 0-255Variable Declaration and Initialization
C++ supports several initialization styles:
int a; // Default initialization (undefined value!)
int b = 10; // Copy initialization
int c(20); // Direct initialization
int d{30}; // Brace initialization (preferred in modern C++)
int e = {40}; // Copy brace initializationBrace initialization ({}) is preferred because it prevents narrowing conversions:
int x{5.5}; // Compile error! Narrowing conversion from double to int
int y = 5.5; // Allowed, but y becomes 5 (data loss)The const Qualifier
const makes a variable read-only — its value cannot be changed after initialization:
const double TAX_RATE = 0.08;
const int MAX_USERS = 1000;
// TAX_RATE = 0.10; // Error! Cannot modify const variable#define vs const
#define is a preprocessor directive that creates a text substitution:
#define PI 3.14159
#define MAX(a, b) ((a) > (b) ? (a) : (b))const variables are preferred over #define because:
- They have proper types (type safety)
- They respect scope
- They can be debugged (the debugger knows about them)
- They don't cause unexpected text substitutions
typedef and using
Both create type aliases. using is the modern C++ approach:
// Traditional typedef
typedef unsigned long long uint64;
typedef std::vector<int> IntVector;
// Modern using (C++11)
using uint64 = unsigned long long;
using IntVector = std::vector<int>;
uint64 bigNumber = 123456789ULL;
IntVector numbers;Type Casting
C++ provides several casting operators. Avoid C-style casts in modern C++:
C-style cast (avoid):
int a = 10;
double b = (double) a; // C-stylestatic_cast — safe, compile-time checked:
double result = static_cast<double>(5) / 2; // 2.5
int grade = static_cast<int>(87.9); // 87 (truncates)dynamic_cast — for polymorphic class hierarchies (runtime check)
const_cast — adds/removes const qualifier
reinterpret_cast — low-level bit reinterpretation (use with caution)
Scope
Local scope — variables declared inside a block {}:
void function() {
int x = 10; // local to function
if (x > 0) {
int y = 20; // local to if block
cout << x + y; // OK
}
// cout << y; // Error! y is out of scope
}Global scope — variables declared outside any function:
int globalVar = 100; // global variable
void function() {
cout << globalVar; // accessible
}Namespace scope — variables inside a namespace:
namespace Config {
int maxUsers = 100;
string appName = "MyApp";
}
cout << Config::maxUsers; // Access with ::The auto Keyword (C++11)
auto lets the compiler deduce the type from the initializer:
auto i = 42; // int
auto d = 3.14; // double
auto c = 'A'; // char
auto b = true; // bool
auto result = compute(); // deduced from return type
auto vec = std::vector<int>{1, 2, 3}; // std::vector<int>auto is especially useful with iterators and complex template types:
// Without auto
std::map<std::string, std::vector<int>>::iterator it = myMap.begin();
// With auto
auto it = myMap.begin();Always initialize variables before use. Reading an uninitialized variable leads to undefined behavior — one of the most common bugs in C++.
Practical Examples
Use 'unsigned' for quantities that can never be negative (age, count, size). This doubles the positive range and communicates intent.
Exercises
Variable Declaration Practice
Declare and initialize variables for: a student's name, age, GPA, enrollment status (bool), and grade letter. Use appropriate data types. Print all values.
Expected Output:
Name: Alice\nAge: 20\nGPA: 3.75\nEnrolled: 1\nGrade: ANarrowing Conversion Detection
Use brace initialization to declare variables. Try to assign a double to an int, a long to a short, and a double to a float — each using brace initialization. Observe which compile and which don't. Then write a version that compiles using static_cast.
Expected Output:
a = 3 (truncated)\nb = 100000 (within range, but brace init catches narrowing)\nc = 3.14159 (precision loss)Scope Experiment
Write a program that demonstrates local, global, and block scope. Create a global variable, a function-local variable, and a block-scoped variable inside an if statement. Show which are accessible where.
Expected Output:
A program that demonstrates which variables are accessible in each scope, showing that globalVar is accessible everywhere, mainVar in main, localVar in demoScope, and innerVar only inside the if block.Mini Quiz
Mini Quiz
Mini Project
Mini Project: Student Grade Analyzer
Create a program that stores student data using appropriate data types, performs calculations, and demonstrates type conversions. Use const for constants, auto for type deduction, and proper variable scoping.
Requirements:
Bonus Challenge
Add a feature to calculate the standard deviation of the scores. Use the cmath library's sqrt() function.