Skip to main content

Building Blocks in C++

Variables in C++(PART-I)

In the previous article, we explored and discussed the basic structure of a C++ program, covering topics such as tokens, keywords, identifiers, and more. In this article, we will delve into the concept of variables, and by combining this with the next article, you will gain an in-depth understanding of variables in C++.

What do we understand by variables ?

Everyone enjoys playing video games, right? I’m sure you’ve played at least one type of video game. Now, imagine you're playing a multiplayer game. In such games, it's essential to keep track of all the players, their information, their scores, the points they've earned, the levels they've reached, and much more. This information needs to be constantly updated and managed throughout the game.

I hope this doesn’t feel overwhelming so far, and the example makes sense. Now, if you’re wondering how a computer keeps track of all this data while your program is running — this is where variables come into play!

Think of variables like labeled storage containers in your computer’s memory. These containers temporarily store information that your program needs to use or update as it runs.

For example:

Imagine you have two containers: one for storing books and another for storing fragile items like crockery. Not only would you label the containers to indicate what they hold—‘books’ for the first one and ‘crockery’ for the second—but you would also include an additional label like ‘fragile’ on the crockery box to clarify its special nature.

Similarly, when you create a variable, you give it a name that describes the type of data it holds, like book_count or crockery_list. Additionally, you define the type of data it stores—whether it’s an integer, string, or something else—to ensure it only holds the appropriate kind of information, just like the fragile label ensures the crockery box is treated carefully.

Pictorial Representation of Variables in Real World

As a programmer, most of the time, you don’t interact directly with memory addresses. Instead, you use labels (variable names) to identify and work with the data stored in variables. However, there are situations, especially when using pointers, where you work directly with memory addresses. Pointers are special variables that store memory addresses instead of actual data. By using pointers, you can directly access or modify the data at those memory addresses. We will discuss pointers in more detail later


Why do we need or use Variables ?

Single Point of Change with Variables

What happens before using Variables( Manual Changes Everywhere )

Imagine you want to change your email which is associated with your gaming account. Without using variables, you would have to manually go to each part of your code where the email address is used and change it. This can be time-consuming and error-prone.

Example before using variables:

#include <iostream>
using namespace std;

int main() {
    // Using email directly in multiple places
    // -------------------------------------------------------
    cout << "Sending notification to user at william_jane@gmail.com" << endl;
    cout << "Updating profile for user with email: william_jane@gmail.com" << endl;
    cout << "Sending password reset link to william_jane@gmail.com" << endl;

    return 0;
}

Output:

Sending notification to user at william_jane@gmail.com
Updating profile for user with email: william_jane@gmail.com
Sending password reset link to william_jane@gmail.com

What happens after using variables( Single Point of Change )

Now, by using variables, you can store the email address in one place, and any part of the program that uses that variable will automatically reflect the updated value if you change it. This makes your code more maintainable and reduces the chances of errors.

Example after using variables:

#include <iostream>
#include <string>
using namespace std;
int main(){
    
    // Storing the email in a variable
	// -------------------------------------------------------
    string user_email = "william_jane.com";
    
    // Using the variable wherever the email is needed.
	// -------------------------------------------------------
    cout<<"Sending the notification to the user:"<<user_email<<endl;
    cout<<"Updating the profile for the user with email:"<<user_email<<endl;
    
    // Change the email, we only update this one line 
	// -------------------------------------------------------
    user_email = "william_jane@outlook.com";
    
    // All the references to user_email will automatically use the updated email
	// -------------------------------------------------------
    cout<<"Sending the notification to the user:"<<user_email<<endl;
    cout<<"Updating the profile for the user with email:"<<user_email<<endl;
    
    return 0;
    
}

Output:

Sending the notification to the user:william_jane@gmail.com
Updating the profile for the user with email:william_jane@gmail.com
Sending the notification to the user:william_jane@outlook.com
Updating the profile for the user with email:william_jane@outlook.com

Improved Code Readability and Maintenance

What happens before using variables( Hardcoded Data )

Imagine you're about to play a game, and you need to set a user_name and full_ name before starting. Without using variables, you'd have to hardcode the username and full name in multiple places throughout the program. This would require you to manually track which part of the code refers to the username and which part refers to the full name, making the code harder to maintain and understand.

Example before using variables:

#include <iostream>
using namespace std;

int main(){

    // Hardcoding user's information 
    // -------------------------------------------------------
    cout<<"Welcome Back, William Jane"<<endl;
    cout<<"Logging in the user: william_jane_2003"<<endl;
    
    // Simulate the login process
    // -------------------------------------------------------
    cout<<"User william_jane_2003 is now logged in !"<<endl;
    
    return 0;
}

Output:

Welcome Back, William Jane
Logging in the user: william_jane_2003
User william_jane_2003 is now logged in !

What happens with variables( Descriptive Naming )

By using variables, you can store user_name and full_name in dedicated variables with meaningful names. This makes the code more readable, as you can instantly understand what the values represent. Additionally, when you need to make changes, you only need to update the variable once, making the program easier to maintain.

Example after using variables:

#include <iostream>
#include <string>
using namespace std;

int main(){

    string full_name = "William Jane";
    string user_name = "william_jane_2003";
    
    // Using descriptive variables names:
    // -------------------------------------------------------
    cout<<"Welcome Back,"<<full_name<<endl;
    cout<<"Logging in user: "<<user_name<<endl;
    
    // Simulate the login process
    // -------------------------------------------------------
    cout<<"User "<<user_name<<"is now logged in !"<<endl;
    
    return 0;
}

Output:

Welcome Back,William Jane
Logging in user: william_jane_2003
User william_jane_2003is now logged in !

Understanding variable declaration and definition

What do we mean by variable declaration ?

A declaration is like telling the compiler about the variable's name and type. It ensures the compiler knows the variable exists but does not necessarily allocate memory for it.

Syntax for declaration

data_type variable_name;
  • data_type here specifies the kind of data( eg: int, float, char )[ we will study them in detail in upcoming articles ]
  • variable_name here is an identifier used to reference the variable in the program.

NOTE: Declaration only introduces the variable to the compiler.

The declaration of variable is generally of two types depending on whether memory allocated or not during declaration.

  • Standalone declaration( without extern ): Allocates memory
    • This declaration introduces the variable's type and name to the compiler without necessarily assigning the value. It is implicitly treated as definition.
  • Declaration with extern: Does not allocate memory( definition required elsewhere ).

The extern keyword in C++ is used to declare a variable or function that is defined elsewhere, typically in another file. It essentially tells the compiler,

"Don't allocate memory for this variable here; it's already defined in another part of the program."

Let’s simplify the explanation of the extern keyword using the example of a multiplayer game:

Imagine you’re playing a multiplayer game with your friends. The game has five levels, and two teams race against each other, with 3-4 players per team. Each level has a unique task that the teams must complete within a set time limit. As the game progresses:

  • Obstacles appear after Level 2 to make the game challenging.
  • Player scores are displayed at the top of the screen during gameplay.
  • At the end of the game, the total score for each team is calculated and displayed.

Now, let’s look at this from the game creator’s perspective. To build this game, the creator needs to manage variables like:

  1. obstacles – defining hurdles that appear beyond Level 2.
  2. score – tracking each player’s score.
  3. total_score – summing up the scores for each team.

Now, the creator wants to organise the code into multiple files for better structure.

  1. gameengine.cpp: The main file controlling the game logic.
  2. variables.h: A header file to declare shared variables.
  3. Separate files for each level like: level1.cpp, level2.cpp and so on.

The game creator doesn't want to allocate memory for same variables in every file nor allocating the memory to those variables which are not needed till yet in the game. Here extern keyword comes into play.

The creator declares the variables in header files ( variables.h ) without allocating memory:

// variables.h
extern int obstacles;  
extern int score;  
extern int total_score;  

The variables are defined and memory is allocated only once, in the main file( gameengine.cpp ):

// gameengine.cpp
#include "variables.h"  
int obstacles;  
int score = 0;  
int total_score = 0;  

Other files like level4.cpp or level5.cpp, can access these variables without re-allocating memory:

// level3.cpp
#include "variables.h"  
void startLevel3() {  
    obstacles = 5;  
    score += 10;  
    total_score += score;  
}  

Using extern keyword to declare variables for programs like this ensures that memory for variables is allocted only once, no matter how many files need access to them this optimises memory usage and avoids redundant declarations making the program efficient and well-structured.

What do we mean by variable definition ?

During definition, memory is allocated for the variable. This means the program sets aside a portion of memory based on the variable's type.

In simpler terms, when you define a variable, you are reserving space in the computer's memory for the variable, so the program can use it during execution.

In most cases, a variable is also initialised at the time of the definition. This means you assign an initial value to the variable. If the variable is defined but not initialised, it will contain garbage value, meaning the variable will hold random data in memory until a value is explicitly assigned.

Here is the syntax for variable definition

data_type variable_name; // Defines the variable without initialising 
data_type variable_name = value; // Defines the variable and also initialises it

Now, here are two different detailed example

Definition with Initialisation

#include <iostream>
#include <string>
using namespace std;

int main() {

    // Defining a variable 'email' and initializing it with a value 'william_jane@gmail.com'
	// -------------------------------------------------------
    string email = "william_jane@gmail.com";  

    cout << "Email: " << email << endl;  

    return 0;
}

Output:

Email: william_jane@gmail.com

Definition without Intialization

#include <iostream>
#include <string>
using namespace std;

int main() {
    // Defining a variable 'email' without initializing it 
	// -------------------------------------------------------

    string email;
    cout << "Email: " << email << endl; 
    return 0;
}

Output:

Email: 

Why is it always a good practise to initialise the variables while defining?

When a variable ise defined without initialisation, it holds garbage data because it is assigned whatever value was previously stored in that memory location. This happens because the memory space allocated for the variable is not specifically cleared or set to a known value by the program.

Now, the question comes,

How a variable holding a garbage value could pose a problem ?

  • If you try to use a variable that contains garbage data, your program may behave unpredictably. For example, if a variable is supposed to store a user's age but it holds garbage data, calculations involving that variable could produce incorrect results or even crash the program.
  • Uninitialised variables make debugging difficult because the behavior of the program becomes non-deterministic ( i.e., it changes unpredictably depending on what random data is in the memory ). By always initialising variables, you ensure that they start with known values, making the program’s behaviour more predictable and easier to debug.

Initialising variables as soon as you define them is considered a best practice. It ensures that your program functions as expected from the very beginning and avoids the potential risks associated with using uninitialised variables.


Rules for declaring variable names

Now that we’ve completed discussing variable declaration and definition, let’s talk about the rules you need to follow when declaring variables in C++.

Think of these rules as guidelines to ensure your program runs smoothly and your code remains clear and error-free.

RULE-1: A variable must NOT start with the digit

A variable cannot begin with number because the compiler interprets number as values , not names this might contain confusion and results in false results which definitely you don't want.

Example of an INVALID declaration of a variable name:

#include <iostream>
using namespace std;

int main() {
    // This will cause a compile-time error: ❌ Invalid: Variable name cannot begin with a number
    // -------------------------------------------------------
    
    int 123user_name = 10;  
    
    cout << "User Name: " << 123user_name << endl;
    return 0;
}

Output:

Example of VALID declaration of a variable name:

#include <iostream>
using namespace std;

int main() {
    // Correct way to declare the variable: ✅ Valid: Variable name starts with a letter
	// -------------------------------------------------------

    string user_name = "william_jane_2003";  

    cout << "User Name: " << user_name << endl;
    return 0;
}

Output:

User Name: william_jane_2003

RULE-2: A variable should start with alphabets and underscore

You can start a variable name with a letter ( a-z or A-Z ) or an underscore (_).

Examples of INVALID variable names:

#include <iostream>
using namespace std;

int main(){

    // These will cause compile-time errors because they don't start with a letter or an underscore
    // -------------------------------------------------------

	// ❌ Invalid: Variable names start with '@'
	// -------------------------------------------------------
    int @score = 10; 

	// ❌ Invalid: Variable names start with '#'
	// -------------------------------------------------------
    int #total = 20;
    
    return 0;
    
}

Output:

Examples of VALID variable names:

#include <iostream>
using namespace std;

int main() {
    // Valid variable names
	// -------------------------------------------------------
	// ✅ Starts with a letter
	// -------------------------------------------------------
    int result = 10;

	// ✅ Starts with an underscore
	// -------------------------------------------------------
    int _value = 20;

	// ✅ Starts with a letter and contains digits later
	// -------------------------------------------------------
    int count_2023 = 30;

    cout << "Result: " << result << endl;  
    cout << "Value: " << _value << endl;  
    cout << "Count: " << count_2023 << endl; 

    return 0;
}

Output:

Result: 10
Value: 20
Count: 30

RULE-3: Variable names are case sensitive

Variable names in C++ are case-sensitive, meaning that it treats uppercase and lowercase letters as distinct. So user_name and USER_NAME are considered two different variable names.

While it's technically allowed to declare both, it's not a good practise because if someone else is reading your code( or even you are reading your code in future ), it could be confusing to tell whether user_name and USER_NAME refer to same thing or different.

Another reason for it not to be a good practise is because accidental case mismatches can easily happen, leading to bugs. For example, if you meant to use user_name but accidentally typed USER_NAME, you could unintentionally reference the wrong variable.

Let's look at this coding example:

#include <iostream>
#include <string>
using namespace std;

int main(){
    
    string user_name = "william_jane_2003";
    string USER_NAME = "austin_jane_2004";
    
    cout<<"Value of user_name: "<<user_name<<endl;
    cout<<"Value of USER_NAME: "<<USER_NAME<<endl;
    
    return 0;
    
}

Both yeilds different output:

Ouptut:

Value of user_name: william_jane_2003
Value of USER_NAME: austin_jane_2004

However, to avoid confusion and improve readability it's recommended to use consistent casing for variable names.

Check out this example:

#include <iostream>
#include <string>
using namespace std;

int main(){
    
    string user_name = "william_jane_2003";
    string user_name_copy = "austin_jane_2004";
    
    cout<<"Value of user_name: "<<user_name<<endl;
    cout<<"Value of user_name_copy: "<<user_name_copy<<endl;
    
    return 0;
    
}

RULE-4: There should be no spaces in the variable names

Variable names must not contain spaces. If you need to represent multiple words in a variable name, you should use underscore(_) to separate them.

Example of INVALID variable names with spaces:


#include <iostream>
using namespace std;

int main() {
    // This will cause a compile-time error because spaces are not allowed in variable names
	// -------------------------------------------------------

	// ❌ Invalid: Spaces are not allowed in variable names
	// -------------------------------------------------------
    string user name = "william_jane_2003";

	// ❌ Invalid: Spaces are not allowed in variable names
	// -------------------------------------------------------  
    int total views = 50;    
    
    cout << "User Name: " << user name << endl;
    cout << "Total Views: " << total views << endl;
    
    return 0;
}

Output:

Example of VALID variable names without spaces:

#include <iostream>
using namespace std;

int main() {
    // This will cause a compile-time error because spaces are not allowed in variable names
	// -------------------------------------------------------

	// These are ✅ Valid variable_names
	// -------------------------------------------------------
    string user_name = "william_jane_2003";  
    int total_views = 50;     
    
    cout << "User Name: " << user_name << endl;
    cout << "Total Views: " << total_views << endl;
    
    return 0;
}

Output:

User Name: william_jane_2003
Total Views: 50

RULE-5: Variable names cannot be reserved keywords

As mentioned in the previous article, keywords are reserved words with predefined meanings in the programming language. These words are essential to the language’s syntax and are used by the compiler to perform specific operations. Since keywords have a special function, they cannot be used as variable names. Using them as variables would create ambiguity in the code, making it difficult to understand and maintain.

Examples of INVALID variable names( using reserved Keywords ):


#include <iostream>
using namespace std;

int main() {
    // These will cause compile-time errors because they are reserved keywords in C++
	// -------------------------------------------------------
	
	// ❌ Invalid: 'int' is a reserved keyword
	// -------------------------------------------------------
    int int = 5;

	// ❌ Invalid: 'for' is a reserved keyword
	// -------------------------------------------------------
    double for = 10.5; 
    
    cout << "int: " << int << endl;    
    cout << "for: " << for << endl;    
    
    return 0;
}

Output:

Examples of VALID variable names( avoiding reserved keywords ):

#include <iostream>
using namespace std;

int main() {
    // Correct: Using valid names instead of reserved keywords
	// -------------------------------------------------------

	// ✅ Valid: 'int_value' is a valid variable name
	// -------------------------------------------------------
    int int_value = 5;

	// ✅ Valid: 'total_value' is a valid variable name
	// -------------------------------------------------------      
    double total_value = 10.5; 
    
    cout << "int_value: " << int_value << endl;   
    cout << "total_value: " << total_value << endl; 
    
    return 0;
}

Output:

int_value: 5
total_value: 10.5

By following these rules you'll will avoid common mistakes and make your programs easier to read and maintain.


Conclusion

We have thoroughly discussed what variables are, how they are stored in memory, variable declaration, definition, and the essential rules you need to follow when working with variables.

However, our journey into understanding variables isn’t over yet.In the next article, we will dive into the scope and lifetime of variables.

These concepts will help you understand where variables can be accessed and how long they exist in memory during the execution of a program. Stay tuned for more insights!