variables
In C++, a type must be declared before a variable can be used. This page covers how to declare, initialize, and assign basic types such as int, double, string, and bool; the const and constexpr keywords for defining values that cannot be changed; and auto, which lets the compiler automatically infer the type.
Syntax
// ========================================
// Basic syntax for variable declaration and initialization
// ========================================
// type name; — declaration only (value is undefined)
// type name = value; — copy initialization
// type name(value); — constructor call initialization
// type name{value}; — uniform initialization with braces (available since C++11)
int age = 25; // declares an int and copy-initializes it
double height{175.5}; // initializes a double with braces (prevents implicit narrowing)
std::string name("Son Goku"); // initializes a string with a constructor call
bool isAlive = true; // declares and initializes a bool
// ========================================
// const — runtime constant
// ========================================
// const type name = value;
const int MAX_POWER = 9000; // cannot be changed after assignment
// ========================================
// constexpr — compile-time constant (C++11 and later)
// ========================================
// constexpr type name = constant_expression;
constexpr double PI = 3.14159265358979; // value is determined at compile time
// ========================================
// auto — type inference (C++11 and later)
// ========================================
// auto name = value; — compiler infers the type from the right-hand side
auto level = 50; // inferred as int
auto power = 9001.0; // inferred as double
Syntax Reference
| Syntax / Keyword | Description |
|---|---|
| int name | Declares a variable that holds an integer. Typically 32 bits (-2147483648 to 2147483647). |
| double name | Declares a variable that holds a double-precision floating-point number. Used for decimal calculations. |
| std::string name | Declares a variable that holds a string. Requires the <string> header. |
| bool name | Declares a logical-type variable that holds true or false. |
| const type name = value | Defines a constant whose value is determined at runtime. Reassignment after declaration causes a compile error. |
| constexpr type name = expr | Defines a constant whose value is determined at compile time. Can be used where compile-time evaluation is required, such as array sizes. |
| auto name = value | The compiler automatically infers the type from the right-hand expression. Useful for omitting complex type names. |
| type name = value | Copy initialization using the assignment operator =. The most fundamental initialization style. |
| type name{value} | Uniform initialization (list initialization) with braces. Prevents implicit narrowing conversions. |
| type name(value) | Constructor call form of initialization using parentheses. |
Sample Code
variables.cpp
// ========================================
// variables.cpp — variable and constant sample
// Manages Dragon Ball character data
// using variables and constants
// ========================================
#include <iostream> // standard I/O library
#include <string> // for std::string
int main() {
// ----------------------------------------
// constexpr — compile-time constant
// ----------------------------------------
// Define a power threshold as a compile-time constant
// Value is fixed at compile time, so it can also be used for array sizes
constexpr int SUPER_SAIYAN_THRESHOLD = 9000;
// ----------------------------------------
// const — runtime constant
// ----------------------------------------
// Team name is defined as a constant that should not change
const std::string TEAM_NAME = "Z Warriors";
// ----------------------------------------
// Basic variable declarations and initialization
// ----------------------------------------
// Son Goku's data stored in variables (copy initialization)
std::string gokuName = "Son Goku";
int gokuAge = 37; // age (integer type)
double gokuHeight = 175.0; // height in cm (floating-point type)
bool gokuIsSaiyan = true; // whether Saiyan (boolean type)
int gokuPower = 9001; // power level
// Vegeta's data stored with brace (uniform) initialization
// Brace initialization prevents implicit narrowing conversions
std::string vegetaName{ "Vegeta"};
int vegetaAge{ 41};
double vegetaHeight{164.0};
bool vegetaIsSaiyan{true};
int vegetaPower{8000};
// Piccolo's data with auto type inference
// The compiler determines the type from the right-hand side
auto piccoloName = std::string("Piccolo");
auto piccoloAge = 25; // inferred as int
auto piccoloHeight = 226.0; // inferred as double
auto piccoloIsSaiyan = false; // inferred as bool
auto piccoloPower = 3500; // inferred as int
// ----------------------------------------
// Output variable values
// ----------------------------------------
std::cout << "=== " << TEAM_NAME << " Member Info ===" << std::endl;
std::cout << std::endl;
// Output Son Goku's info
std::cout << "[" << gokuName << "]" << std::endl;
std::cout << " Age : " << gokuAge << std::endl;
std::cout << " Height : " << gokuHeight << " cm" << std::endl;
std::cout << " Saiyan : " << (gokuIsSaiyan ? "yes" : "no") << std::endl;
std::cout << " Power : " << gokuPower << std::endl;
// Check whether power exceeds the threshold
if (gokuPower > SUPER_SAIYAN_THRESHOLD) {
std::cout << " * Power exceeds threshold (" << SUPER_SAIYAN_THRESHOLD
<< ")!" << std::endl;
}
std::cout << std::endl;
// Output Vegeta's info
std::cout << "[" << vegetaName << "]" << std::endl;
std::cout << " Age : " << vegetaAge << std::endl;
std::cout << " Height : " << vegetaHeight << " cm" << std::endl;
std::cout << " Saiyan : " << (vegetaIsSaiyan ? "yes" : "no") << std::endl;
std::cout << " Power : " << vegetaPower << std::endl;
std::cout << std::endl;
// Output Piccolo's info
std::cout << "[" << piccoloName << "]" << std::endl;
std::cout << " Age : " << piccoloAge << std::endl;
std::cout << " Height : " << piccoloHeight << " cm" << std::endl;
std::cout << " Saiyan : " << (piccoloIsSaiyan ? "yes" : "no") << std::endl;
std::cout << " Power : " << piccoloPower << std::endl;
std::cout << std::endl;
// ----------------------------------------
// Reassigning a variable
// ----------------------------------------
// Son Goku's power rises after training
gokuPower = 150000000;
std::cout << gokuName << "'s power after training: " << gokuPower << std::endl;
// const constants cannot be changed (the line below would be a compile error)
// TEAM_NAME = "Evil Army"; // error: assignment to const variable
return 0;
}
# Compile with C++17 g++ -std=c++17 variables.cpp -o variables # Run after successful compilation (macOS / Linux) ./variables === Z Warriors Member Info === [Son Goku] Age : 37 Height : 175 cm Saiyan : yes Power : 9001 * Power exceeds threshold (9000)! [Vegeta] Age : 41 Height : 164 cm Saiyan : yes Power : 8000 [Piccolo] Age : 25 Height : 226 cm Saiyan : no Power : 3500 Son Goku's power after training: 150000000
Common Mistakes
Using an uninitialized variable is undefined behavior. In C++, declaring a variable does not give it a defined value. Built-in types (int, double, etc.) contain garbage values, and reading them results in undefined behavior. Initializing variables at the point of declaration prevents this.
uninitialized_ng.cpp — NG: undefined behavior
#include <iostream>
int main() {
// Reading an uninitialized variable is undefined behavior
int power;
std::cout << power << std::endl; // outputs a garbage value (undefined behavior)
return 0;
}
uninitialized_ok.cpp — OK: initialize at declaration
#include <iostream>
#include <string>
int main() {
// Initialize at the point of declaration
int power = 0;
std::string name = "Vegeta";
std::cout << name << "'s power: " << power << std::endl;
return 0;
}
# Compile g++ -std=c++17 uninitialized.cpp -o uninitialized && ./uninitialized Vegeta's power: 0
Beware of the most vexing parse with brace initialization. Writing type name() with empty parentheses is parsed as a function prototype declaration rather than a variable declaration (known as the most vexing parse). Using brace syntax type name{} avoids this issue.
most_vexing_parse_ng.cpp — NG: interpreted as a function prototype
#include <iostream>
#include <string>
int main() {
// Most vexing parse — interpreted as a function prototype, not a variable
std::string name(); // declares a function "name" returning string, not a variable
std::cout << name << std::endl; // compile error
return 0;
}
most_vexing_parse_ok.cpp — OK: use brace initialization
#include <iostream>
#include <string>
int main() {
// Brace initialization unambiguously declares a variable
std::string name{}; // default-constructed empty string variable
name = "Son Goku";
std::cout << "Name: " << name << std::endl;
// Parentheses with an argument also work fine
std::string name2("Vegeta");
std::cout << "Name: " << name2 << std::endl;
return 0;
}
# Compile g++ -std=c++17 most_vexing_parse_ok.cpp -o most_vexing_parse_ok && ./most_vexing_parse_ok Name: Son Goku Name: Vegeta
Overview
C++ variables fundamentally require an explicit type declaration, but since C++11 the auto keyword lets the compiler automatically infer the type from the right-hand side. There are three initialization styles: copy form (= value), parenthesis form ((value)), and brace form ({value}). Brace initialization prevents implicit narrowing conversions. There are two ways to define constants: const and constexpr. const is used for constants whose values are determined at runtime, while constexpr guarantees the value is determined at compile time. constexpr is stricter and can also be used in contexts that require compile-time evaluation, such as array size specifications and template arguments. Reassigning a const or constexpr variable after definition causes a compile error, preventing unintentional modifications.
If you find any errors or copyright issues, please contact us.