Variables & Constants
Variables let a C++ program hold values that change; constants let it lock a value down. This page walks through declaration, every initialization style, const and constexpr, scope, lifetime, and literals in detail.
Variables and constants are two of the most fundamental building blocks of a C++ program. A variable represents an object whose stored value can generally be changed during its lifetime. A constant represents a value or object that is not intended to be modified through the relevant name or mechanism. Everything else in this topic — declaration syntax, the different initialization styles, const versus constexpr, scope, lifetime, and literals — builds on that basic distinction.
Overview: A First Look
Consider a variable and a constant side by side:
age is a variable — an object of type int that can be reassigned later. maxAge is a constant — also an int, but declared const, so its value cannot be changed after initialization.
Here, age can be modified later in the program, but maxAge cannot be modified through that declaration.
int age = 25;
const int maxAge = 100;1. What Is a Variable?
A variable is a named object used to store a value.
This statement creates an object named age of type int and initializes it with 25.
The value can later be changed:
Assigns a new value, 30, to the existing object age.
int age = 25;age = 30;2. Basic Variable Syntax
The general form of a variable declaration is type variable_name;
Four variables of different types, each declared without an initial value.
A variable can also be initialized when it is declared:
Each variable is declared and given an initial value in the same statement.
The basic structure is type + name + initialization, for example int count = 10;
int age;
double price;
char grade;
bool active;int age = 25;
double price = 99.99;
char grade = 'A';
bool active = true;3. Declaration vs Initialization
Declaration, initialization, and assignment are three different concepts, even though they can look similar.
Declaration — this declares an object named count with type int, without giving it a value.
Initialization — this declares count and initializes it with 10.
Assignment — this changes the value of an already-existing object count.
So: declaration introduces the object; initialization provides its initial value; assignment changes an existing object's value.
int count;int count = 10;count = 20;4. Initialization
C++ provides several forms of initialization.
List initialization (also called brace initialization).
List initialization is widely preferred in modern C++ because it provides useful protection against certain narrowing conversions.
Rejected because converting 3.14 to int would narrow the value.
Copy initialization allows the conversion, although it may lose information.
int age = 25;int age(25);int age{25};int value{3.14}; // error: narrowing conversionint value = 3.14; // allowed, but loses information (value becomes 3)5. Default Initialization
If a local fundamental-type variable is declared without an initializer, the object is default-initialized:
value is default-initialized. For a local variable of fundamental type, this means its value is indeterminate.
Using an indeterminate value without first giving it a valid value can lead to undefined behavior in relevant cases.
Therefore, prefer explicit initialization when zero initialization is appropriate:
Both forms give the object a defined starting value of 0.
int value;int value = 0;
int value2{};6. Value Initialization
Empty braces can be used to value-initialize an object.
For an int, this results in count being 0.
This is a common modern C++ style. Examples:
Each object is value-initialized to the zero-equivalent of its type.
int count{};int count{}; // count -> 0
double price{}; // price -> 0.0
bool active{}; // active -> false7. Variable Naming Rules
C++ identifiers follow specific rules. A name can contain letters, digits, and underscores, but it cannot begin with a digit.
All of these are valid identifiers.
Invalid because an identifier cannot begin with a digit.
A name also cannot be a C++ keyword.
Invalid because class is a C++ keyword.
int age;
int studentCount;
int value2;
int _value;int 2value; // invalidint class; // invalid8. Naming Conventions
Good names make programs easier to understand.
Preferred over int x; double p; bool b; when the meaning of the value is known.
Common naming styles include camelCase (studentCount, totalPrice, maxValue) or snake_case (student_count, total_price, max_value). The important point is to use a consistent naming convention within a project.
int studentCount;
double totalPrice;
bool isConnected;9. Case Sensitivity
C++ is case-sensitive.
These are three different identifiers, not the same variable written three ways. Similarly, studentCount, StudentCount, and studentcount are different names.
int value;
int Value;
int VALUE;10. Assigning Values to Variables
After initialization, a variable can be assigned another value.
age starts at 25 and is then reassigned to 30.
Assignment uses a single =. Do not confuse assignment with equality comparison: age = 30; is assignment, while age == 30 is a comparison.
int age = 25;
age = 30;11. Multiple Variables
Multiple variables can be declared separately:
They can also be declared together in one statement:
Although valid, separate declarations are often easier to read when the variables have different purposes.
int x = 10;
int y = 20;
int z = 30;int x = 10, y = 20, z = 30;12. Variables of Different Types
C++ supports many data types.
The type determines what kind of value the object represents and affects which operations can be performed on it.
Assigning another int is fine.
A string literal cannot be assigned to an int.
int age = 25;
double salary = 50000.50;
char grade = 'A';
bool active = true;int count = 10;
count = 20; // validint count = "Hello"; // invalid13. const Variables
The const keyword can be used to make an object non-modifiable through that declaration.
Attempting to modify a const object through its name is a compile error.
A const object must generally be initialized when it is defined.
const int maxUsers = 100;maxUsers = 200; // invalidconst int maxUsers = 100;
const int maxUsers2{100};14. Why Use const?
const communicates that a value should not be modified.
This prevents accidental modification of pi.
It also makes the programmer's intention clearer. Instead of double pi = 3.141592653589793;, writing const double pi = 3.141592653589793; communicates: this object should not be changed.
const double pi = 3.141592653589793;pi = 3.14; // Error15. const Does Not Mean "Compile-Time Constant"
This distinction is important.
value cannot be modified after initialization, but its value does not necessarily have to be known at compile time — it can come from a runtime function call.
const means "cannot modify the object through this const declaration"; constexpr requires a constant expression where applicable.
This is a compile-time constant expression.
constexpr is a separate C++ concept and should not be confused with ordinary const.
int getValue();
const int value = getValue();constexpr int maxUsers = 100;16. constexpr Variables
A constexpr variable is intended to hold a value that can be evaluated at compile time.
The initializer must satisfy the requirements for a constant expression. constexpr variables are also const.
Conceptually: const prevents modification through the object; constexpr adds compile-time constant-expression requirements on top of const.
constexpr int maxUsers = 100;
constexpr int secondsPerMinute = 60;17. const vs constexpr
The two keywords can be compared directly:
The const version is fine because value is initialized at runtime. The constexpr version fails because input is not a constant expression.
Property const constexpr
----------------------------------------------------------------------
Prevents modification Yes Yes
Value must be compile-time const Not necessarily Yes, where required
Can be initialized at runtime Yes No, not for the value itself
Common use Read-only objects Compile-time valuesint input = 10;
const int value = input; // valid: initialized at runtime
constexpr int value2 = input; // invalid: input is not a constant expression18. Constants Using enum
C++ also provides enumerations for named sets of related values.
Enumeration constants are useful when a value should represent one of a defined set of named choices. Detailed enumerations are covered in their own topic.
enum class Color
{
Red,
Green,
Blue
};Color color = Color::Red;19. const Objects and Classes
const can also be applied to objects of class types.
The object cannot be modified through name.
Class member functions also have a separate const concept:
This means the member function promises not to modify the object's non-mutable state through that member function.
That topic is covered under const member functions.
const std::string name = "Rina";name += " Sahu"; // Errorclass Student
{
public:
int getAge() const;
};20. Local and Global Variables
Variables can exist in different scopes.
value is a local variable, declared inside the function.
globalValue is declared outside any function, so it has namespace/file scope.
The behavior, lifetime, and visibility of a variable depend on where and how it is declared. Scope and storage duration are separate concepts and should not be confused.
int main()
{
int value = 10;
}int globalValue = 100;
int main()
{
}21. static Variables
The keyword static can affect the storage duration or linkage of an entity depending on where it is used. For example, a local static variable retains its value between function calls:
count is initialized once, the first time counter() runs, and keeps its value across later calls.
counter() is called the first time: count is initialized to 0, then incremented to 1, and 1 is printed.
counter() is called a second time: initialization is skipped since it already happened; count is incremented to 2, and 2 is printed.
counter() is called a third time: count is incremented to 3, and 3 is printed.
Calling counter(); counter(); counter(); produces 1, 2, 3. The detailed rules for static, scope, storage duration, and linkage belong to their own dedicated topic.
void counter()
{
static int count = 0;
++count;
std::cout << count << '\n';
}22. extern Variables
extern can declare an object whose definition is provided elsewhere.
This tells the compiler that an object named globalValue exists elsewhere.
A definition that could satisfy the extern declaration above.
This becomes especially useful in multi-file programs.
extern int globalValue;int globalValue = 100;23. auto Variables
Modern C++ allows the compiler to deduce the type of a variable using auto.
The deduced type is int.
The deduced type is double.
The deduced type is bool.
auto does not mean that C++ becomes dynamically typed. The type is still determined and checked by the compiler.
auto age = 25;auto price = 99.99;auto active = true;24. auto Does Not Mean "Any Type"
auto value = 10; does not mean value can later hold a different type.
This does not mean value can later contain any type.
The compiler deduces int value = 10;. Conceptually, after deduction, auto value = 10; behaves exactly like an int object. This is still statically typed C++.
auto value = 10;25. const auto
auto can be combined with const.
The compiler deduces const int value = 100;.
The compiler deduces const double price = 10.5;.
const auto value = 100;const auto price = 10.5;26. Variable Lifetime
A variable has a lifetime during which its object exists.
The local object value is created when its declaration is reached during execution, and its lifetime ends when execution leaves its scope in the normal case.
Different kinds of objects can have different storage durations. C++ commonly discusses automatic storage duration, static storage duration, thread storage duration, and dynamic storage duration. These are important for understanding object lifetime and memory management.
void function()
{
int value = 10;
}27. Variable Scope vs Lifetime
Scope and lifetime are not the same thing. Scope describes where a name can be used; lifetime describes when the object exists.
count has block scope and static storage duration.
Its name is accessible only within the block, but the object continues to exist between function calls. Therefore: scope is about visibility of a name; lifetime is about existence of an object.
void function()
{
static int count = 0;
}28. Constants and Literals
A literal is a value written directly in source code.
Examples: 10, 3.14, 'A', "Hello", true.
Here age is the variable/object, and 25 is the integer literal.
pi is a const object, and 3.14159 is a floating-point literal.
A literal itself is not the same thing as a named constant variable.
int age = 25;const double pi = 3.14159;29. Literal Types and Suffixes
C++ provides suffixes that can affect the type of a literal.
Common meanings:
The exact type selected follows C++'s literal rules and the types available on the implementation.
10U
10L
10LL
10.0f
10.0
10.0LLiteral Type
------- -----------
10 int
10U unsigned int
10L long
10LL long long
10.0f float
10.0 double
10.0L long double30. Character Constants
A character literal can be written using single quotes:
'A' is a character literal.
A string literal is different:
"A" is a string literal, not a character literal.
These are different kinds of literals and should not be confused.
char grade = 'A';const char* text = "A";31. Boolean Constants
C++ has built-in Boolean values: true and false.
true and false are Boolean literals.
bool isActive = true;
bool isFinished = false;32. Constant Expressions
A constant expression is an expression that satisfies C++'s rules for compile-time evaluation.
The compiler can evaluate width * height as a constant expression.
This is useful when a value needs to be known during compilation.
constexpr int width = 10;
constexpr int height = 20;
constexpr int area = width * height;33. Choosing Between Variable and Constant
Use a normal variable when the value needs to change:
Use const when the object should not be modified:
Use constexpr when the value should be a compile-time constant:
A simple decision model: does the value change? If yes, use a variable. If no, does it need to be a compile-time constant? If yes, use constexpr; if no, use const.
int counter = 0;
++counter;const int maxRetries = 3;constexpr int bufferSize = 256;34. Best Practices
Initialize variables. Prefer int count{}; over leaving a local fundamental-type variable uninitialized.
Use const by default when a value should not change:
Use constexpr for compile-time constants:
Prefer meaningful names — double totalPrice; is clearer than double x;.
Prefer braces for initialization, since this can help prevent unintended narrowing conversions:
Keep scope as narrow as practical. Declare variables close to where they are needed:
result is declared right where it is used, rather than as an unnecessary global variable.
const int maxRetries = 3;constexpr int secondsPerMinute = 60;int count{10};
double price{99.99};void process()
{
int result = calculate();
std::cout << result;
}35. Quick Reference
int x; Declaration / default initialization
int x = 10; Copy initialization
int x(10); Direct initialization
int x{10}; List initialization
int x{}; Value initialization
x = 20; Assignment
const int x = 10; Read-only object
constexpr int x = 10; Compile-time constant
auto x = 10; Type deduction
static int x; Static storage duration (in applicable contexts)
extern int x; Declaration of an object defined elsewhere36. Variable vs Constant
What is the difference between declaration, initialization, and assignment? Give an example of each.
Declaration introduces an object's name and type without necessarily giving it a value, e.g. int count;. Initialization declares the object and gives it its first value in the same statement, e.g. int count = 10;. Assignment changes the value of an object that already exists, e.g. count = 20;.
Why does int value{3.14}; fail to compile while int value = 3.14; compiles (but loses precision)?
List initialization (the braces form) performs a narrowing-conversion check and rejects conversions that could lose information, such as double to int. Copy initialization (the = form) does not perform that check, so it silently allows the conversion and value ends up truncated to 3.
Explain the difference between const and constexpr using an example where const is initialized at runtime.
const only guarantees the object cannot be modified after initialization — its value can still come from a runtime source, e.g. const int value = getValue(); where getValue() runs at runtime. constexpr additionally requires the initializer to be a constant expression that the compiler can evaluate at compile time, so constexpr int value = getValue(); would only compile if getValue() itself could be evaluated as a constant expression.
What is the difference between the scope and the lifetime of a local static variable?
Scope is about where the name can be used in the source code — a local static variable's name is only visible inside the block where it is declared. Lifetime is about how long the underlying object exists — a static local variable's object is created once and persists for the entire program, surviving between separate calls to the function, even though its name is not visible outside the block.
Why is auto still considered part of C++'s static type system even though the programmer doesn't write the type explicitly?
auto only affects how the type is written, not when it is determined. The compiler deduces the concrete type (e.g. int for auto value = 10;) at compile time, and from that point on the object behaves exactly like a normal int — its type is fixed and checked just as strictly as if it had been spelled out explicitly.
What does this program print, and why?
It prints 1, 2, and 3 on separate lines. count is a static local variable, so it is initialized to 0 only once; each call to counter() increments the same persistent object rather than creating a fresh one.
Write a small program that declares a constexpr variable for the number of seconds in a minute and the number of minutes in an hour, and uses both to compute the number of seconds in an hour, also as a constexpr.
secondsPerHour is computed entirely at compile time because both operands are constexpr, so the program prints 3600.
What does this print, and why might it surprise someone at first?
It prints "a is not less". The usual arithmetic conversions convert the signed a to unsigned before the comparison, so -1 becomes a very large unsigned value, making a < b false.
Write a program that declares an int using copy initialization, direct initialization, list initialization, and value initialization, and prints all four values.
It prints 10 20 30 0 — a, b, and c hold their explicitly given values, while d is value-initialized to 0.
Variable const Object constexpr Variable
Can be modified? Usually yes No No
Runtime init possible? Yes Yes No (must be constant expr)
Type checked statically Yes Yes Yes
Common purpose Changing state Read-only value Compile-time value
Example int count = 0; const int max = 100; constexpr int size = 256;void counter()
{
static int count = 0;
++count;
std::cout << count << '\n';
}
int main()
{
counter();
counter();
counter();
}int a = -1;
unsigned int b = 1;
if (a < b)
{
std::cout << "a is less\n";
}
else
{
std::cout << "a is not less\n";
}