Data types specify the kind of values that a variable can hold and the operations that can be performed on it. C++ offers a variety of built-in (primitive) data types.
int
(Integer)Used to store whole numbers (both positive and negative) without any decimal point. The size of an int
can vary depending on the system architecture but is typically 4 bytes.
#include <iostream>
int main() {
int age = 30;
int count = -10;
std::cout << "Age: " << age << std::endl;
std::cout << "Count: " << count << std::endl;
return 0;
}
Age: 30
Count: -10
float
(Floating-Point)Used to store single-precision floating-point numbers (numbers with a decimal point). Typically occupies 4 bytes.
#include <iostream>
#include <iomanip> // For std::fixed and std::setprecision
int main() {
float price = 19.99f; // 'f' suffix indicates a float literal
float temperature = -5.5f;
std::cout << "Price: " << std::fixed << std::setprecision(2) << price << std::endl;
std::cout << "Temperature: " << temperature << std::endl;
return 0;
}
Price: 19.99
Temperature: -5.5
double
(Double-Precision Floating-Point)Used to store double-precision floating-point numbers, offering more precision than float
. Typically occupies 8 bytes. It's often the default choice for floating-point numbers unless memory is a significant constraint.
#include <iostream>
#include <iomanip>
int main() {
double pi = 3.14159265358979323846;
double gravity = 9.81;
std::cout << "Pi: " << std::fixed << std::setprecision(15) << pi << std::endl;
std::cout << "Gravity: " << gravity << std::endl;
return 0;
}
Pi: 3.141592653589793
Gravity: 9.810000000000000
char
(Character)Used to store single characters (letters, digits, symbols). Typically occupies 1 byte. Character literals are enclosed in single quotes.
#include <iostream>
int main() {
char initial = 'A';
char digit = '7';
char symbol = '$';
std::cout << "Initial: " << initial << std::endl;
std::cout << "Digit: " << digit << std::endl;
std::cout << "Symbol: " << symbol << std::endl;
return 0;
}
Initial: A
Digit: 7
Symbol: $
bool
(Boolean)Used to store truth values, which can be either true
or false
.
#include <iostream>
int main() {
bool is_valid = true;
bool is_finished = false;
std::cout << "Is valid: " << std::boolalpha << is_valid << std::endl; // std::boolalpha prints true/false instead of 1/0
std::cout << "Is finished: " << std::boolalpha << is_finished << std::endl;
return 0;
}
Is valid: true
Is finished: false
auto
Keyword (C++11 and later):The auto
keyword allows the compiler to deduce the data type of a variable based on its initializer. This can make code more concise, especially when dealing with complex types.
#include <iostream>
#include <vector>
int main() {
auto number = 10; // number will be of type int
auto pi = 3.14159; // pi will be of type double
auto message = "Hello"; // message will be of type const char*
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (auto it = numbers.begin(); it != numbers.end(); ++it) { // Type of 'it' is deduced
std::cout << *it << " ";
}
std::cout << std::endl;
for (auto val : numbers) { // Range-based for loop, type of 'val' is deduced
std::cout << val * 2 << " ";
}
std::cout << std::endl;
return 0;
}
1 2 3 4 5
2 4 6 8 10
Important Note about auto
: While convenient, overuse of auto
can sometimes reduce code readability if the type of the variable is not immediately obvious from its initialization.
Variables are named storage locations in memory that can hold values of a specific data type. The value stored in a variable can be changed during the program's execution.
#include <iostream>
int main() {
int counter = 0; // Declaration and initialization of an integer variable
std::cout << "Initial counter: " << counter << std::endl;
counter = 5; // Assigning a new value to the variable
std::cout << "Updated counter: " << counter << std::endl;
counter = counter + 2; // Modifying the variable's value
std::cout << "Incremented counter: " << counter << std::endl;
return 0;
}
Initial counter: 0
Updated counter: 5
Incremented counter: 7
Constants are variables whose values cannot be changed after they are initialized. C++ provides several ways to define constants:
const
Keyword:Used to declare variables whose values are read-only after initialization. const
variables can be initialized at runtime.
#include <iostream>
int main() {
const double PI = 3.14159;
// PI = 3.0; // Error: assignment of read-only variable 'PI'
std::cout << "Value of PI: " << PI << std::endl;
return 0;
}
Value of PI: 3.14159
constexpr
Keyword (C++11 and later):Used to declare constants whose values must be known at compile time. This allows the compiler to perform optimizations. constexpr
can also be used with functions that can be evaluated at compile time given constant arguments.
#include <iostream>
constexpr int MAX_SIZE = 100;
constexpr double EULER = 2.71828;
constexpr int square(int n) {
return n * n;
}
int main() {
std::cout << "Max size: " << MAX_SIZE << std::endl;
std::cout << "Euler's number: " << EULER << std::endl;
constexpr int squared_five = square(5); // Value is computed at compile time
std::cout << "Square of 5 (constexpr): " << squared_five << std::endl;
return 0;
}
Max size: 100
Euler's number: 2.71828
Square of 5 (constexpr): 25
volatile
Keyword:The volatile
keyword is a type qualifier used to indicate that a variable's value might be changed by factors outside the normal execution flow of the program (e.g., by hardware, an interrupt handler, or another thread). This prevents the compiler from making optimizations that assume the variable's value remains unchanged unless modified by the program itself.
#include <iostream>
#include <thread>
#include <chrono>
volatile bool data_ready = false;
void worker_thread() {
std::this_thread::sleep_for(std::chrono::seconds(2));
data_ready = true; // Value changed by another thread
std::cout << "Worker thread: Data is now ready." << std::endl;
}
int main() {
std::thread t(worker_thread);
while (!data_ready) {
std::cout << "Main thread: Waiting for data..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::cout << "Main thread: Data processing started." << std::endl;
t.join();
return 0;
}
Main thread: Waiting for data...
Main thread: Waiting for data...
Main thread: Waiting for data...
Main thread: Waiting for data...
Worker thread: Data is now ready.
Main thread: Data processing started.
Explanation: Without volatile
, the compiler might optimize the while (!data_ready)
loop in main()
by assuming data_ready
never changes within the loop's context, leading to an infinite loop. volatile
forces the compiler to re-read the value of data_ready
from memory each time the condition is checked.
Operators are symbols that perform operations on operands (variables or values).
+
(Addition)-
(Subtraction)*
(Multiplication)/
(Division)%
(Modulo - remainder of integer division)++
(Increment - prefix or postfix)--
(Decrement - prefix or postfix)
#include <iostream>
int main() {
int a = 10, b = 3;
std::cout << "a + b = " << a + b << std::endl;
std::cout << "a - b = " << a - b << std::endl;
std::cout << "a * b = " << a * b << std::endl;
std::cout << "a / b = " << a / b << std::endl; // Integer division
std::cout << "a % b = " << a % b << std::endl;
std::cout << "a++ = " << a++ << " (a is now " << a << ")" << std::endl;
std::cout << "++b = " << ++b << " (b is now " << b << ")" << std::endl;
return 0;
}
a + b = 13
a - b = 7
a * b = 30
a / b = 3
a % b = 1
a++ = 10 (a is now 11)
++b = 4 (b is now 4)
&&
(Logical AND) - Returns true
if both operands are true
.||
(Logical OR) - Returns true
if at least one operand is true
.!
(Logical NOT) - Returns the opposite of the operand's boolean value.
#include <iostream>
int main() {
bool p = true, q = false;
std::cout << "p && q = " << std::boolalpha << (p && q) << std::endl;
std::cout << "p || q = " << std::boolalpha << (p || q) << std::endl;
std::cout << "!p = " << std::boolalpha << (!p) << std::endl;
std::cout << "!q = " << std::boolalpha << (!q) << std::endl;
return 0;
}
p && q = false
p || q = true
!p = false
!q = true
These operators perform operations at the bit level.
&
(Bitwise AND)|
(Bitwise OR)^
(Bitwise XOR - Exclusive OR)~
(Bitwise NOT - One's complement)<<
(Left Shift)>>
(Right Shift)
#include <iostream>
#include <bitset> // For std::bitset
int main() {
unsigned int a = 5; // Binary: 0101
unsigned int b = 3; // Binary: 0011
std::cout << "a & b = " << (a & b) << " (Binary: " << std::bitset<4>(a & b) << ")" << std::endl;
std::cout << "a | b = " << (a | b) << " (Binary: " << std::bitset<4>(a | b) << ")" << std::endl;
std::cout << "a ^ b = " << (a ^ b) << " (Binary: " << std::bitset<4>(a ^ b) << ")" << std::endl;
std::cout << "~a = " << (~a) << " (Binary: " << std::bitset<8>(~a) << ")" << std::endl; // Assuming 8-bit int for demonstration
std::cout << "a << 1 = " << (a << 1) << " (Binary: " << std::bitset<4>(a << 1) << ")" << std::endl;
std::cout << "a >> 1 = " << (a >> 1) << " (Binary: " << std::bitset<4>(a >> 1) << ")" << std::endl;
return 0;
}
a & b = 1 (Binary: 0001)
a | b = 7 (Binary: 0111)
a ^ b = 6 (Binary: 0110)
~a = 4294967290 (Binary: 11111111111111111111111111111010)
a << 1 = 10 (Binary: 1010)
a >> 1 = 2 (Binary: 0010)
Note: The output of ~a
depends on the size of the unsigned int
type on your system. The std::bitset
is used here to visualize the binary representation.
The ternary operator (?:
) is a concise way to express a simple if-else
condition.
#include <iostream>
#include <string>
int main() {
int age = 18;
std::string status = (age >= 18) ? "Adult" : "Minor";
std::cout << "Age: " << age << ", Status: " << status << std::endl;
int x = 10, y = 5;
int max = (x > y) ? x : y;
std::cout << "The maximum of " << x << " and " << y << " is: " << max << std::endl;
return 0;
}
Age: 18, Status: Adult
The maximum of 10 and 5 is: 10
sizeof
Operator:The sizeof
operator returns the size (in bytes) of a data type or an expression.
#include <iostream>
int main() {
std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
std::cout << "Size of float: " << sizeof(float) << " bytes" << std::endl;
int numbers[5];
std::cout << "Size of numbers array (5 ints): " << sizeof(numbers) << " bytes" << std::endl;
int x = 10;
std::cout << "Size of variable x (int): " << sizeof(x) << " bytes" << std::endl;
return 0;
}
Size of int: 4 bytes
Size of float: 4 bytes
Size of numbers array (5 ints): 20 bytes
Size of variable x (int): 4 bytes
Note: The exact sizes of primitive data types can sometimes vary slightly depending on the compiler and the target architecture.
Control structures dictate the flow of execution in a program, allowing you to make decisions and repeat blocks of code.
if-else
Statement:The if
statement executes a block of code if a specified condition is true. The optional else
block executes if the condition is false. You can also have multiple conditions using else if
.
#include <iostream>
int main() {
int age = 20;
if (age >= 18) {
std::cout << "You are an adult." << std::endl;
} else {
std::cout << "You are a minor." << std::endl;
}
int grade = 75;
if (grade >= 90) {
std::cout << "Excellent!" << std::endl;
} else if (grade >= 80) {
std::cout << "Very good." << std::endl;
} else if (grade >= 70) {
std::cout << "Good." << std::endl;
} else {
std::cout << "Needs improvement." << std::endl;
}
return 0;
}
You are an adult.
Good.
switch
Statement:The switch
statement allows you to execute different blocks of code based on the value of a single variable (the switch expression).
#include <iostream>
int main() {
int day = 3;
switch (day) {
case 1:
std::cout << "Monday" << std::endl;
break;
case 2:
std::cout << "Tuesday" << std::endl;
break;
case 3:
std::cout << "Wednesday" << std::endl;
break;
case 4:
std::cout << "Thursday" << std::endl;
break;
case 5:
std::cout << "Friday" << std::endl;
break;
case 6:
case 7:
std::cout << "Weekend" << std::endl;
break;
default:
std::cout << "Invalid day" << std::endl;
}
return 0;
}
Wednesday
Important Notes about switch
:
break
statement is crucial to exit the switch
block after a case is matched. Without break
, execution will "fall through" to the next case.default
case is optional and is executed if none of the other cases match the switch expression.for
Loop:The for
loop is used to execute a block of code a specific number of times. It typically has three parts: initialization, condition, and increment/decrement.
#include <iostream>
int main() {
for (int i = 0; i < 5; ++i) {
std::cout << "Iteration: " << i << std::endl;
}
return 0;
}
Iteration: 0
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
for
Loop (C++11 and later):This provides a more concise way to iterate over elements in a range (e.g., arrays, vectors, strings).
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {10, 20, 30, 40, 50};
for (int num : numbers) { // Iterates through each element in 'numbers'
std::cout << "Number: " << num << std::endl;
}
std::string message = "Hello";
for (char ch : message) { // Iterates through each character in 'message'
std::cout << "Character: " << ch << std::endl;
}
return 0;
}
Number: 10
Number: 20
Number: 30
Number: 40
Number: 50
Character: H
Character: e
Character: l
Character: l
Character: o
while
Loop:The while
loop executes a block of code as long as a specified condition is true. The condition is checked before each iteration.
#include <iostream>
int main() {
int count = 0;
while (count < 3) {
std::cout << "Count is: " << count << std::endl;
count++;
}
return 0;
}
Count is: 0
Count is: 1
Count is: 2
do-while
Loop:The do-while
loop is similar to the while
loop, but the condition is checked after each iteration. This guarantees that the loop body will execute at least once.
#include <iostream>
int main() {
int num = 0;
do {
std::cout << "Num is: " << num << std::endl;
num++;
} while (num < 2);
return 0;
}
Num is: 0
Num is: 1
Understanding these fundamental C++ syntax elements is crucial for building more complex programs. Mastering data types, variables, constants, operators, and control structures will allow you to write logic that can make decisions, perform calculations, and repeat actions as needed. Remember to practice writing small programs using these concepts to solidify your understanding.