C++ Fundamentals - II
This part of C++ fundamentals focuses mainly on expressions, operators, type conversion, bitwise operations, and swapping values. These topics are small individually, but they appear everywhere in programming. Once they become familiar, writing logic becomes much smoother because most decisions, calculations, comparisons, and updates in a program are built using them.
Expressions in C++
An expression is a combination of values, variable names, and operators that C++ evaluates to produce a value or cause a side effect, such as changing the value stored in a variable.
Examples of expressions include:
a + b=> An arithmetic expression that adds the values stored inaandband produces their sum.marks >= 40=> A relational expression that checks whether the value stored inmarksis greater than or equal to40. It evaluates to eithertrueorfalse.count = count + 1=> An assignment expression that adds1to the current value ofcountand stores the result back incount, thereby changing its value. This change is called a side effect.
Side Effect
Not every expression changes stored data. For example, a + b simply calculates a result; it does not modify a or b.
int a = 10;int b = 20;int sum = a + b;Here, a + b produces 30, and that value is stored in sum. The values of a and b remain unchanged.
But in the following expression: count = count + 1;
The value of count is updated. If count was 5, it becomes 6. This update is the side effect.
Operands and Operators
In an expression such as: a + b
+ is the operator, while a and b are operands. The operator tells C++ what operation to perform, and the operands are the values or variables on which the operation is performed.
Arithmetic Operators
Arithmetic operators are used for mathematical calculations.
+performs addition.-performs subtraction.*performs multiplication./performs division.%gives the remainder after division.
Remainder Operator
The remainder operator, also called modulo, gives the remainder after integer division.
When 13 is divided by 2, the quotient is 6 and the remainder is 1. So: 13 % 2 = 1
The modulo operator is useful in many problems, such as checking whether a number is even or odd.
int number = 13;if (number % 2 == 0) { cout << "Even";} else { cout << "Odd";}If a number gives remainder 0 when divided by 2, it is even. Otherwise, it is odd.
Integer Division
Integer division is a common source of mistakes. If both operands are integers, the result is also an integer, even if the mathematical answer has a decimal part.
int total = 56;int num = 6;double average = total / num;cout << average;// Output: 9.0Mathematically, 56 / 6 is approximately 9.3333. But in this code, both total and num are integers, so C++ performs integer division first. The result becomes 9, and then 9 is stored in the double variable average.
Storing the result in a double is not enough. At least one operand must be a floating-point value before the division happens.
int total = 56;int num = 6;double average = static_cast<double>(total) / num;cout << average;// Output: 9.3333Now total is converted to double before division, so the result is a decimal value.
Type Conversion in C++
Type conversion means converting a value from one data type to another. For example, converting an int value into a double value is a type conversion.
int x = 10;double y = x;Here, x stores the integer value 10. When it is assigned to y, C++ automatically converts it to 10.0. This is allowed because a double can comfortably store an integer value.
Implicit Type Conversion
Implicit conversion happens automatically. The programmer does not explicitly request it; C++ performs it when needed.
int x = 10;double y = x;In this example, C++ automatically converts x from int to double.
Another example:
int total = 56;double num = 6;double average = total / num;cout << average;Here, total is an integer and num is a double. Since one operand is a double, C++ converts the integer operand to double and performs floating-point division. The result is approximately 9.33333.
Explicit Type Conversion
Explicit conversion happens when the programmer forces a conversion. In modern C++, static_cast is the preferred form.
int total = 56;int num = 6;double average = static_cast<double>(total) / num;cout << average;static_cast<double>(total) tells C++ to convert total into a double. Once one operand becomes double, the division produces a decimal result.
There is also an older C-style cast syntax:
int total = 56;int num = 6;double average = (double)total / num;cout << average;This also converts total to double, but static_cast is clearer and safer in modern C++ style.
Conversion Can Lose Information
Converting an int to a double preserves the value of ordinary small integers, representing them with a decimal part when appropriate. However, converting a double to an int removes the fractional part rather than rounding the number, which can result in a loss of information.
int x = 10;double y = x; // y becomes 10.0double price = 10.56;int value = price; // Fractional part is discarded; value becomes 10cout << value; // Prints: 10Character and Integer Conversion
Characters are internally associated with integer values. In the commonly used ASCII representation, uppercase and lowercase English letters have fixed numeric codes.
'A'has ASCII value65.'B'has ASCII value66.'Z'has ASCII value90.'a'has ASCII value97.'b'has ASCII value98.'z'has ASCII value122.
Character to Integer
C++ can convert a character to its corresponding integer character code. When a character is assigned to an int variable, its corresponding integer value is stored.
char ch1 = 'A';int value1 = ch1;cout << value1; // Prints: 65char ch2 = 'a';int value2 = ch2;cout << value2; // Prints: 97Integer to Character
The reverse is also possible. If an integer corresponds to a valid character code, it can be converted to char.
int value1 = 65;char ch1 = value1;cout << ch1; // Prints: Aint value2 = 97;char ch2 = value2;cout << ch2; // Prints: aIf a number is outside the meaningful range for the character set being used, the output may look strange or unreadable. For basic ASCII, values are often discussed in the range 0 to 255, but exact behavior can depend on the system and character representation.
Assignment Operators
The assignment operator stores a value into a variable.
// This stores 90 in score.int score = 90;The left side of assignment must be a modifiable object, usually a variable.
score = 90; // valid90 = score; // invalidA constant value cannot appear on the left side because it cannot be modified.
Updating a Value
score = score + 5;This means:
Read the current value of
score.Add
5to it.Store the new value back into
score.
If score was 90, it becomes 95.
Compound Assignment
Compound assignment combines an operation with assignment. For example:
score += 5; // Adds 5 to score// Equivalent to:score = score + 5;Other compound assignment operators work similarly:
score -= 5; // score = score - 5score *= 2; // score = score * 2score /= 3; // score = score / 3score %= 4; // score = score % 4Compound assignment is shorter and often clearer when the same variable is being updated.
Increment and Decrement Operators
The increment operator ++ increases a value by 1. The decrement operator -- decreases a value by 1.
Without Updating the Original Variable
int x = 5;int y = x + 1;cout << "y = " << y << "\n";cout << "x = " << x << "\n";/*Output: y = 6x = 5*/y gets x + 1, but x itself remains unchanged.
Updating the Original Variable
int x = 5;x = x + 1;int y = x;cout << "y = " << y << "\n";cout << "x = " << x << "\n";/*Output:y = 6x = 6*/This can be shortened using compound assignment: x += 1;
It can be shortened further using increment: ++x;
Prefix Increment
In prefix increment, the operator appears before the variable.
int x = 5;int y = ++x;cout << "y = " << y << "\n";cout << "x = " << x << "\n";/*Output:y = 6x = 6*/Here, x is increased first. Then the updated value is assigned to y.
Prefix Decrement
int x = 5;int y = --x;cout << "y = " << y << "\n";cout << "x = " << x << "\n";/*Output:y = 4x = 4*/x is decreased first, and then the updated value is assigned to y.
Postfix Increment
In postfix increment, the operator appears after the variable.
int x = 5;int y = x++;cout << "y = " << y << "\n";cout << "x = " << x << "\n";/*Output:y = 5x = 6*/The old value of x is assigned to y first. After that, x is incremented.
Postfix Decrement
int x = 5;int y = x++;cout << "y = " << y << "\n";cout << "x = " << x << "\n";/*Output:y = 5x = 6*/The old value is used first, then the decrement happens.
Avoid Dense Increment Expressions
Expressions that modify the same variable multiple times in one line are hard to read and should be avoided.
// Avoid writing expressions like thisx++ + ++x + x++;Even if such expressions appear clever, they make code difficult to reason about. Readability matters more than cleverness. If a value needs to be updated multiple times, write the steps clearly.
Relational Operators
Relational operators compare values and produce either true or false.
==checks equality.!=checks inequality.<checks less than.>checks greater than.<=checks less than or equal to.>=checks greater than or equal to.
Equality Check
int x = 5;int y = 5;bool result = (x == y);cout << result; // Prints: 1In C++, true is commonly printed as 1 and false as 0.
If y is changed to 6:
int x = 5;int y = 6;bool result = (x == y);cout << result; // Prints: 0Assignment vs Equality
= and == are different.
// Assigns 5 to x.x = 5;// Checks whether x is equal to 5.x == 5;Logical Operators
Logical operators combine or modify boolean conditions.
&&means logical AND.||means logical OR.!means logical NOT.
Logical AND
&& returns true only when both conditions are true.
marks >= 0 && marks <= 100This checks whether marks lies between 0 and 100, inclusive. Both conditions must be true.
Logical OR
|| returns true if at least one condition is true.
day == 6 || day == 7This can be used to check whether day is either 6 or 7. If either condition is true, the whole expression is true.
Logical NOT
! reverses a boolean value.
bool result = true;cout << !result; // Prints: 0Since result is true, !result becomes false.
Short-Circuiting
Logical operators do not always evaluate both sides. This behavior is called short-circuiting.
Short-Circuiting with AND
For the expression, A && B, to be true, both A and B must be true. If C++ evaluates A and finds it false, the result is already guaranteed to be false. There is no need to evaluate B.
bool result = false && someOtherCondition;The second condition is skipped because false && anything is always false.
Short-Circuiting with OR
For the expression, A || B, to be true, at least one condition must be true. If C++ evaluates A and finds it true, the result is already guaranteed to be true. There is no need to evaluate B.
bool result = true || someOtherCondition;The second condition is skipped because true || anything is always true.
Short-circuiting can save unnecessary computation. More importantly, it is often used to write safe checks.
if (denominator != 0 && numerator / denominator > 5) { cout << "Valid calculation";}If denominator != 0 is false, the division is never performed, so division by zero is avoided.
Operator Precedence and Parentheses
Operator precedence decides which operation happens first when an expression has multiple operators. This is similar to mathematics.
int result = 2 + 3 * 4;cout << result; // Prints: 14// Calculation:// 3 * 4 = 12// 2 + 12 = 14Multiplication has higher precedence than addition, so 3 * 4 happens first. So result becomes 14.
int result = (2 + 3) * 4;cout << result; // Prints: 14// Calculation:// 2 + 3 = 5// 5 * 4 = 20Parentheses can change the order. Now 2 + 3 happens first. So result becomes 20.
Even when precedence rules are known, large expressions should be avoided if they hurt readability. It is better to write a few clear lines than one dense line that is hard to understand.
Conditional Operator
The conditional operator is also called the ternary operator. It is used to choose between two values based on a condition.
condition ? value_if_true : value_if_falseIt is useful for simple decisions.
Problem: Print the Larger of Two Numbers
Given two unique numbers, print the larger one. Since the two numbers are guaranteed to be different, there is no equal case to handle.
Using If-Else
#include <iostream>using namespace std;int main() { int a, b; cin >> a >> b; if (a > b) { cout << a; } else { cout << b; } return 0;}/*Input: 10 4Output: 10Input: 10 40Output: 40*/Using the Conditional Operator
#include <iostream>using namespace std;int main() { int a, b; cin >> a >> b; int result = (a > b) ? a : b; cout << result; return 0;}If a > b is true, a is chosen. Otherwise, b is chosen.
For a = 10 and b = 40, the condition 10 > 40 is false, so b is selected and 40 is stored in result.
Printing Directly
The value chosen by the conditional operator can be printed directly.
cout << ((a > b) ? a : b);This is fine for simple cases. Avoid putting complex logic inside a ternary expression because it quickly becomes unreadable.
Bitwise Operators
Bitwise operators work directly on the binary representation of numbers. This section only introduces the operators; deeper bit manipulation is studied later as a separate topic.
The operators discussed are:
&bitwise AND|bitwise OR^bitwise XOR
Do not confuse & with &&. A single & is bitwise AND. Double && is logical AND used in conditions.
Binary Representation
The machine stores numbers using 0 and 1. For example, the decimal number 6 is written as 110 in binary.
To convert 6 to binary, repeatedly divide by 2 and note the remainders:
6 / 2 = 3 remainder 03 / 2 = 1 remainder 11 / 2 = 0 remainder 1Read the remainders from bottom to top. So, 6 = 110 in binary.
Although we write 6 as 110 for simplicity, an int commonly uses 32 bits. So internally, it is stored with leading zeros i.e. 00000000000000000000000000000110
For a long long, which commonly uses 64 bits, the same value has even more leading zeros.
Bitwise AND
Bitwise AND produces 1 at a bit position only when both bits are 1.
6 = 1103 = 011Now compare bit by bit: 110& 011----- 010At the rightmost bit, 0 & 1 = 0. At the middle bit, 1 & 1 = 1. At the left bit, 1 & 0 = 0.
The result is: 010
Convert it back to decimal:
0 * 2^0 = 01 * 2^1 = 20 * 2^2 = 0Total = 0 + 2 + 0 = 2Therefore, 6 & 3 = 2
Bitwise OR
Bitwise OR produces 1 at a bit position if at least one of the bits is 1.
6 = 1103 = 011Compare bit by bit 110| 011----- 111Convert 111 to decimal:
1 * 2^0 = 11 * 2^1 = 21 * 2^2 = 4Total = 1 + 2 + 4 = 7Therefore, 6 | 3 = 7
Bitwise XOR
Bitwise XOR produces 1 when the number of 1s at that bit position is odd. For two bits, this means it gives 1 when the bits are different and 0 when they are the same.
6 = 1103 = 011Compare bit by bit 110^ 011----- 101At the rightmost bit, there is one 1, so the result bit is 1. At the middle bit, there are two 1s, so the result bit is 0. At the left bit, there is one 1, so the result bit is 1.
Convert 101 to decimal:
1 * 2^0 = 10 * 2^1 = 01 * 2^2 = 4Total = 1 + 0 + 4 = 5Therefore, 6 ^ 3 = 5
Swapping Two Numbers
Swapping means exchanging the values of two variables. If a = 5 and b = 7, then after swapping, a = 7 and b = 5.
Incorrect Swap Attempt
A common first attempt is:
a = b;b = a;This does not work. Suppose a = 5 and b = 7.
After the first line: a = b;
a becomes 7. The original value 5 is lost.
Then the second line: b = a;
assigns the current value of a, which is already 7, into b. Both variables become 7. No swap happens.
Swapping Using a Temporary Variable
To swap safely, preserve one value before overwriting it.
#include <iostream>using namespace std;int main() { int a = 5; int b = 7; int temp = a; a = b; b = temp; cout << "a = " << a << "\n"; cout << "b = " << b << "\n"; return 0;}Output:
a = 7
b = 5The steps are:
temp = apreserves the original value ofa.a = bassigns the value ofbtoa.b = tempassigns the original value ofatob.
Swapping Without a Temporary Variable
Swapping can also be done using arithmetic operations.
#include <iostream>using namespace std;int main() { int a = 5; int b = 7; a = a + b; b = a - b; a = a - b; cout << "a = " << a << "\n"; cout << "b = " << b << "\n"; return 0;}Step-by-step:
Initial:
a = 5,b = 7Step 1:
a = a + b=>a = 5 + 7 = 12,b = 7Step 2:
b = a - b=>b = 12 - 7 = 5Step 3:
a = a - b=>a = 12 - 5 = 7Final result:
a = 7,b = 5
Overflow Risk in Arithmetic Swap
The arithmetic method has a risk. If a and b are large, a + b may exceed the maximum value that the integer type can store. This causes overflow and can make the program incorrect.
int a = 2147483647;int b = 1;a = a + b; // overflow riskSince 2147483647 is commonly the maximum value for a signed 32-bit int, adding 1 cannot fit in the same type.
Because of this, the temporary variable method is clearer and safer for beginners.
Key Takeaways
An expression combines values, variable names, and operators to produce a value or cause a side effect.
Integer division returns an integer when both operands are integers.
Type conversion can be implicit or explicit.
Converting from
doubletointcan lose the decimal part.Characters can be converted to their integer codes and vice versa.
Assignment updates values; compound assignment shortens common updates.
Prefix and postfix increment/decrement differ in when the updated value is used.
Relational operators produce boolean results.
Logical operators combine boolean conditions and support short-circuiting.
Parentheses should be used to make expressions clear.
The ternary operator is useful for simple choices, but complex logic should remain readable.
Bitwise operators work on binary representations of numbers.
Swapping with a temporary variable is simple, readable, and safe for beginners.
Be the first to add a comment.