Unary Operators
The bitwise NOT operator (~) performs a one's complement operation, flipping all bits in the binary representation. Since C stores signed integers using two's complement, applying ~ to zero yields -1:
#include <stdio.h>
int main() {
int val = 0;
int result = ~val;
printf("%d\n", result); // Outputs: -1
return 0;
}
This occurs because 0 represents all 32 bits as 0 in two's complement. The inversion sets all bits to 1, which corresponds to -1 in signed integer representation.
Bitwise Complement Algorithm
Consider the problem of finding the binary complement of a decimal integer (similar to finding the bitwise complement). The complement inverts each bit, effectively calculating mask XOR n where mask contains all 1s matching the bit-length of n:
int findComplement(int num) {
if (num == 0) return 1;
unsigned int mask = ~0;
while (num & mask) {
mask <<= 1;
}
return ~mask ^ num;
}
Alternatively, using arithmetic progression:
int bitwiseComplement(int n) {
if (n == 0) return 1;
int power = 1;
while (power <= n) {
power <<= 1;
}
return power - 1 - n;
}
Increment and Decrement
C provides two forms for increment/decrement operators with distinct evaluation timing:
Prefix Form (++var, --var): The variable modifies before its value participates in the expression.
#include <stdio.h>
int main() {
int idx = 5;
int res = --idx; // idx decrements to 4, then assigns to res
printf("idx=%d, res=%d\n", idx, res); // Both output 4
return 0;
}
Postfix Form (var++, var--): The original value participates in the expression, then the variable modifies.
#include <stdio.h>
int main() {
int idx = 5;
int res = idx++; // res receives 5, then idx increments to 6
printf("idx=%d, res=%d\n", idx, res); // Outputs: idx=6, res=5
return 0;
}
Relational Operators
These operators establish comparisons between operands, yielding boolean results (represented as 1 for true, 0 for false):
| Operator | Meaning |
|---|---|
> |
Greater than |
>= |
Greater than or equal |
< |
Less than |
<= |
Less than or equal |
== |
Equality comparison |
!= |
Inequality |
Note the distinction between assignment (=) and equality comparison (==), a common source of logical errors.
Logical Operators
Logical operators combine boolean expressions:
&&(Logical AND): Evaluates true only if both operands are non-zero.||(Logical OR): Evaluates true if either operand is non-zero.
Leap Year Calculation Example:
A year qualifies as leap if divisible by 4 but not by 100, unless divisible by 400:
int isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
Short-Circuit Evaluation
C guarantees left-to-right evaluation for logical operators. If the left operand determines the final result, the right operand never executes:
int x = 0;
int y = 5;
// If x < 3 is false, y++ never executes
if (x >= 3 && y++ > 4) {
printf("Condition met\n");
}
// y remains 5 due to short-circuit
Similarly for OR:
int a = 10;
int b = 0;
// Since a != 0 evaluates true, b++ is skipped
if (a != 0 || b++) {
printf("Short-circuit prevents b increment\n");
}
// b remains 0
Conditional (Ternary) Operator
The ternary operator ?: provides concise conditional assignment:
condition ? expression_if_true : expression_if_false
Maximum Value Selection:
#include <stdio.h>
int main() {
int first = 42;
int second = 17;
int maximum = (first > second) ? first : second;
printf("Maximum: %d\n", maximum);
return 0;
}
For array manipulation:
#include <stdio.h>
int main() {
int values[3];
scanf("%d %d", &values[0], &values[1]);
values[2] = (values[0] > values[1]) ? values[0] : values[1];
printf("Larger value: %d\n", values[2]);
return 0;
}
Equivalent to:
int threshold = 5;
int signal = (threshold > 5) ? 3 : -3;
Comma Operator
The comma operator , evaluates expressions left-too-right, returning the rightmost value:
int p = 0;
int q = 0;
int final = (p += 3, q += 5, p + q); // final equals 8
Loop Optimization:
Consolidating multiple operations within loop controls:
// Verbose approach
int fetchStatus();
void processData(int data);
int data = fetchStatus();
while (data > 0) {
processData(data);
data = fetchStatus();
}
// Condensed using comma operator
while (data = fetchStatus(), processData(data), data > 0) {
// Processing logic
}
Subscript and Function Call Operators
Array Subscript [ ]:
Accesses array elements through pointer arithmetic: arr[idx] equals *(arr + idx).
Function Call ( ):
Invokes functions with specified arguments: function_name(argument_list).
Type Casting (type):
Explicitly converts values between data types:
double pi = 3.14159;
int whole = (int)pi; // Truncates to 3
float ratio = (float)7 / 4; // Ensures floating-point division, yields 1.75
Type casting proves essential when mixing arithmetic operations between integer and floating-point types to prevent unintended integer truncation.