Logical operators are the foundation of decision-making in C programming. They allow programs to evaluate conditions, combine multiple tests, and control the flow of execution based on complex criteria. For C developers, mastering logical operators is essential for writing efficient, readable, and correct conditional logic in everything from simple input validation to complex algorithm implementations.
What are Logical Operators?
Logical operators in C are symbols that perform logical operations on Boolean expressions (expressions that evaluate to true or false). They combine or modify conditions to produce a single true or false result. C uses three primary logical operators: AND (&&), OR (||), and NOT (!).
Why Logical Operators are Essential in C
- Decision Making: Enable programs to choose different paths based on multiple conditions.
- Complex Condition Testing: Combine simple conditions into sophisticated logic.
- Code Efficiency: Short-circuit evaluation can optimize performance.
- Readability: Make complex conditions more understandable than nested if statements.
- Flow Control: Essential for loops, conditionals, and state machines.
The Three Logical Operators
#include <stdio.h>
#include <stdbool.h>
int main() {
printf("=== Logical Operators in C ===\n\n");
// Define some test values
int a = 5, b = 10, c = 0;
// AND operator (&&) - both must be true
printf("AND Operator (&&):\n");
printf(" (a > 0 && b > 0) = %d (both true)\n", (a > 0 && b > 0));
printf(" (a > 0 && c > 0) = %d (one false)\n", (a > 0 && c > 0));
printf(" (a < 0 && b < 0) = %d (both false)\n\n", (a < 0 && b < 0));
// OR operator (||) - at least one must be true
printf("OR Operator (||):\n");
printf(" (a > 0 || b > 0) = %d (both true)\n", (a > 0 || b > 0));
printf(" (a > 0 || c > 0) = %d (one true)\n", (a > 0 || c > 0));
printf(" (a < 0 || b < 0) = %d (both false)\n\n", (a < 0 || b < 0));
// NOT operator (!) - inverts the truth value
printf("NOT Operator (!):\n");
printf(" !(a > 0) = %d (true becomes false)\n", !(a > 0));
printf(" !(a < 0) = %d (false becomes true)\n", !(a < 0));
printf(" !!a = %d (double NOT returns original truth value)\n\n", !!a);
// Boolean type (C99)
bool flag1 = true;
bool flag2 = false;
printf("Using bool type (stdbool.h):\n");
printf(" flag1 && flag2 = %d\n", flag1 && flag2);
printf(" flag1 || flag2 = %d\n", flag1 || flag2);
printf(" !flag1 = %d\n", !flag1);
return 0;
}
Truth Tables
#include <stdio.h>
void printTruthTables() {
printf("=== Truth Tables ===\n\n");
// Define all possible combinations
int values[] = {0, 1}; // 0 = false, 1 = true
printf("AND (&&) Truth Table:\n");
printf(" A B A&&B\n");
printf(" -----------\n");
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
printf(" %d %d %d\n", values[i], values[j], values[i] && values[j]);
}
}
printf("\nOR (||) Truth Table:\n");
printf(" A B A||B\n");
printf(" -----------\n");
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
printf(" %d %d %d\n", values[i], values[j], values[i] || values[j]);
}
}
printf("\nNOT (!) Truth Table:\n");
printf(" A !A\n");
printf(" ------\n");
for (int i = 0; i < 2; i++) {
printf(" %d %d\n", values[i], !values[i]);
}
}
int main() {
printTruthTables();
return 0;
}
Short-Circuit Evaluation
One of the most important features of C's logical operators is short-circuit evaluation: the right-hand operand is evaluated only if necessary.
#include <stdio.h>
int riskyFunction(int x) {
printf(" riskyFunction(%d) called\n", x);
return x > 0;
}
int main() {
printf("=== Short-Circuit Evaluation ===\n\n");
int x = -5;
int y = 10;
// AND short-circuit: if left is false, right is NOT evaluated
printf("AND Short-Circuit:\n");
printf("x = %d\n", x);
printf("Expression: (x > 0 && riskyFunction(y))\n");
printf("Result: %d\n", (x > 0 && riskyFunction(y)));
printf("Note: riskyFunction was NOT called because x > 0 is false\n\n");
// Reset and try with x positive
x = 5;
printf("x = %d\n", x);
printf("Expression: (x > 0 && riskyFunction(y))\n");
printf("Result: %d\n", (x > 0 && riskyFunction(y)));
printf("Note: riskyFunction WAS called because x > 0 is true\n\n");
// OR short-circuit: if left is true, right is NOT evaluated
printf("OR Short-Circuit:\n");
x = 5;
printf("x = %d\n", x);
printf("Expression: (x > 0 || riskyFunction(y))\n");
printf("Result: %d\n", (x > 0 || riskyFunction(y)));
printf("Note: riskyFunction was NOT called because x > 0 is true\n\n");
// OR with false left side
x = -5;
printf("x = %d\n", x);
printf("Expression: (x > 0 || riskyFunction(y))\n");
printf("Result: %d\n", (x > 0 || riskyFunction(y)));
printf("Note: riskyFunction WAS called because x > 0 is false\n");
return 0;
}
Practical Examples
1. Input Validation
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int isValidUsername(const char *username) {
int len = strlen(username);
// Check multiple conditions:
// - Length between 3 and 20 characters
// - First character must be letter
// - All characters must be alphanumeric
return (len >= 3 && len <= 20) &&
isalpha(username[0]) &&
(strspn(username, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") == len);
}
int isValidPassword(const char *password) {
int len = strlen(password);
int hasUpper = 0, hasLower = 0, hasDigit = 0, hasSpecial = 0;
// Check each character
for (int i = 0; password[i]; i++) {
if (isupper(password[i])) hasUpper = 1;
else if (islower(password[i])) hasLower = 1;
else if (isdigit(password[i])) hasDigit = 1;
else hasSpecial = 1; // Assume any non-alphanumeric is special
}
// Password must:
// - Be at least 8 characters long
// - Have at least one uppercase letter
// - Have at least one lowercase letter
// - Have at least one digit
// - Have at least one special character
return (len >= 8) &&
hasUpper && hasLower && hasDigit && hasSpecial;
}
int main() {
printf("=== Input Validation ===\n\n");
char username[50], password[50];
printf("Enter username: ");
scanf("%49s", username);
printf("Enter password: ");
scanf("%49s", password);
printf("\nValidation Results:\n");
printf("Username '%s' is %s\n",
username, isValidUsername(username) ? "VALID" : "INVALID");
printf("Password '%s' is %s\n",
password, isValidPassword(password) ? "VALID" : "INVALID");
// Combined validation
if (isValidUsername(username) && isValidPassword(password)) {
printf("\nAll credentials are valid!\n");
} else if (!isValidUsername(username) && !isValidPassword(password)) {
printf("\nBoth username and password are invalid.\n");
} else if (!isValidUsername(username)) {
printf("\nUsername is invalid.\n");
} else {
printf("\nPassword is invalid.\n");
}
return 0;
}
2. Range Checking
#include <stdio.h>
typedef struct {
int min;
int max;
} Range;
int isInRange(int value, Range r) {
return value >= r.min && value <= r.max;
}
int isOutsideRange(int value, Range r) {
return value < r.min || value > r.max;
}
int isBetween(int value, int low, int high) {
return value > low && value < high;
}
int main() {
printf("=== Range Checking ===\n\n");
Range tempRange = {0, 100}; // 0 to 100 degrees
Range ageRange = {0, 120}; // 0 to 120 years
Range scoreRange = {0, 100}; // 0 to 100 percent
int temperature = 75;
int age = 25;
int score = 85;
printf("Temperature %d is %svalid (range 0-100)\n",
temperature, isInRange(temperature, tempRange) ? "" : "in");
printf("Age %d is %svalid (range 0-120)\n",
age, isInRange(age, ageRange) ? "" : "in");
printf("Score %d is %svalid (range 0-100)\n",
score, isInRange(score, scoreRange) ? "" : "in");
// Multiple range checks
printf("\nGrade Classification:\n");
if (score >= 90 && score <= 100) {
printf(" A (Excellent)\n");
} else if (score >= 80 && score < 90) {
printf(" B (Good)\n");
} else if (score >= 70 && score < 80) {
printf(" C (Average)\n");
} else if (score >= 60 && score < 70) {
printf(" D (Below Average)\n");
} else if (score >= 0 && score < 60) {
printf(" F (Failing)\n");
} else {
printf(" Invalid score\n");
}
return 0;
}
3. Menu System with Logical Conditions
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
typedef struct {
bool loggedIn;
bool hasAdminPrivileges;
bool hasWriteAccess;
bool hasReadAccess;
} UserPermissions;
void displayMenu(UserPermissions *user) {
printf("\n=== Main Menu ===\n");
// Always show if logged in
if (user->loggedIn) {
printf("1. View Profile\n");
}
// Show if logged in AND has read access
if (user->loggedIn && user->hasReadAccess) {
printf("2. View Documents\n");
}
// Show if logged in AND (has write access OR is admin)
if (user->loggedIn && (user->hasWriteAccess || user->hasAdminPrivileges)) {
printf("3. Edit Documents\n");
}
// Show if logged in AND has admin privileges
if (user->loggedIn && user->hasAdminPrivileges) {
printf("4. User Management\n");
printf("5. System Settings\n");
}
// Show logout if logged in
if (user->loggedIn) {
printf("6. Logout\n");
} else {
printf("1. Login\n");
printf("2. Exit\n");
}
printf("Choice: ");
}
int main() {
UserPermissions user = {
.loggedIn = false,
.hasAdminPrivileges = false,
.hasWriteAccess = false,
.hasReadAccess = false
};
int choice;
char username[50];
char password[50];
while (1) {
displayMenu(&user);
scanf("%d", &choice);
if (!user.loggedIn) {
// Not logged in menu
if (choice == 1) {
printf("Username: ");
scanf("%49s", username);
printf("Password: ");
scanf("%49s", password);
// Simple authentication logic
bool validUser = (strcmp(username, "alice") == 0 ||
strcmp(username, "bob") == 0 ||
strcmp(username, "admin") == 0);
bool validPass = (strcmp(password, "pass123") == 0);
if (validUser && validPass) {
user.loggedIn = true;
// Set permissions based on username
user.hasAdminPrivileges = (strcmp(username, "admin") == 0);
user.hasReadAccess = true;
user.hasWriteAccess = (strcmp(username, "alice") == 0 ||
strcmp(username, "admin") == 0);
printf("Login successful!\n");
} else {
printf("Invalid credentials.\n");
}
} else if (choice == 2) {
printf("Goodbye!\n");
break;
}
} else {
// Logged in menu
if (choice == 1) {
printf("Viewing profile...\n");
} else if (choice == 2 && (user.loggedIn && user.hasReadAccess)) {
printf("Viewing documents...\n");
} else if (choice == 3 && (user.loggedIn && (user.hasWriteAccess || user.hasAdminPrivileges))) {
printf("Editing documents...\n");
} else if (choice == 4 && (user.loggedIn && user.hasAdminPrivileges)) {
printf("Managing users...\n");
} else if (choice == 5 && (user.loggedIn && user.hasAdminPrivileges)) {
printf("System settings...\n");
} else if (choice == 6) {
user.loggedIn = false;
printf("Logged out.\n");
} else {
printf("Invalid choice or insufficient permissions.\n");
}
}
}
return 0;
}
4. Leap Year Calculation
#include <stdio.h>
#include <stdbool.h>
bool isLeapYear(int year) {
// A year is a leap year if:
// - It is divisible by 4
// - AND (it is NOT divisible by 100 OR it is divisible by 400)
return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
}
void printLeapYearInfo(int year) {
printf("\nYear %d:\n", year);
printf(" Divisible by 4: %s\n", (year % 4 == 0) ? "yes" : "no");
printf(" Divisible by 100: %s\n", (year % 100 == 0) ? "yes" : "no");
printf(" Divisible by 400: %s\n", (year % 400 == 0) ? "yes" : "no");
printf(" Leap year: %s\n", isLeapYear(year) ? "YES" : "NO");
// Show the logical breakdown
printf(" Logic: (%d %% 4 == 0) && (%d %% 100 != 0 || %d %% 400 == 0)\n",
year, year, year);
printf(" = (%s) && (%s)\n",
(year % 4 == 0) ? "true" : "false",
(year % 100 != 0 || year % 400 == 0) ? "true" : "false");
}
int main() {
printf("=== Leap Year Calculation ===\n");
int years[] = {1900, 2000, 2004, 2020, 2021, 2024, 2100};
int count = sizeof(years) / sizeof(years[0]);
for (int i = 0; i < count; i++) {
printLeapYearInfo(years[i]);
}
// Interactive version
printf("\nCheck a specific year: ");
int year;
scanf("%d", &year);
printLeapYearInfo(year);
return 0;
}
5. Complex Business Logic
#include <stdio.h>
#include <stdbool.h>
typedef struct {
int age;
bool hasLicense;
bool hasInsurance;
bool isSober;
bool hasRegistration;
bool isOwnersPermission;
} DriverStatus;
bool canDrive(DriverStatus driver) {
// A person can drive if:
// 1. They are at least 16 years old
// 2. They have a valid license
// 3. They have insurance
// 4. They are sober
// 5. The vehicle has valid registration OR they have owner's permission
return (driver.age >= 16) &&
driver.hasLicense &&
driver.hasInsurance &&
driver.isSober &&
(driver.hasRegistration || driver.isOwnersPermission);
}
typedef struct {
bool hasPayment;
bool isMember;
bool hasCoupon;
bool isFirstTime;
bool isHoliday;
} PurchaseStatus;
float calculateDiscount(PurchaseStatus purchase, float total) {
float discount = 0.0;
// Members always get 10% off
if (purchase.isMember) {
discount += 0.10;
}
// First-time customers get 15% off, but not combined with member discount
if (purchase.isFirstTime && !purchase.isMember) {
discount = 0.15; // Better discount
}
// Coupon gives extra 5% if (member OR first-time) AND (not holiday)
if (purchase.hasCoupon &&
(purchase.isMember || purchase.isFirstTime) &&
!purchase.isHoliday) {
discount += 0.05;
}
// Holiday shoppers without membership get 5% (if not first-time)
if (purchase.isHoliday && !purchase.isMember && !purchase.isFirstTime) {
discount = 0.05;
}
// Cap discount at 25%
if (discount > 0.25) {
discount = 0.25;
}
return discount;
}
int main() {
printf("=== Complex Business Logic ===\n\n");
printf("Driver Eligibility:\n");
DriverStatus drivers[] = {
{25, true, true, true, true, false}, // Legal owner
{17, true, true, true, false, true}, // With permission
{15, true, true, true, true, false}, // Underage
{30, false, true, true, true, false}, // No license
{22, true, false, true, true, false}, // No insurance
{35, true, true, false, true, false}, // Not sober
{19, true, true, true, false, false} // No reg, no permission
};
char *status[] = {"cannot drive", "CAN drive"};
for (int i = 0; i < 7; i++) {
printf("Driver %d: age=%d, license=%d, insurance=%d, sober=%d, reg=%d, permission=%d -> %s\n",
i+1,
drivers[i].age,
drivers[i].hasLicense,
drivers[i].hasInsurance,
drivers[i].isSober,
drivers[i].hasRegistration,
drivers[i].isOwnersPermission,
status[canDrive(drivers[i])]);
}
printf("\nDiscount Calculation:\n");
PurchaseStatus purchases[] = {
{true, true, false, false, false}, // Member
{true, false, false, true, false}, // First-time
{true, true, true, false, false}, // Member with coupon
{true, false, true, false, true}, // Holiday shopper with coupon
{true, false, false, false, true}, // Holiday shopper
{true, true, true, false, true} // Member on holiday with coupon
};
float baseTotal = 100.00;
for (int i = 0; i < 6; i++) {
float discount = calculateDiscount(purchases[i], baseTotal);
float finalTotal = baseTotal * (1 - discount);
printf("Purchase %d: member=%d, first=%d, coupon=%d, holiday=%d -> "
"discount=%.0f%%, total=$%.2f\n",
i+1,
purchases[i].isMember,
purchases[i].isFirstTime,
purchases[i].hasCoupon,
purchases[i].isHoliday,
discount * 100,
finalTotal);
}
return 0;
}
De Morgan's Laws
De Morgan's laws show how to transform logical expressions:
#include <stdio.h>
#include <stdbool.h>
void demonstrateDeMorgansLaws() {
printf("=== De Morgan's Laws ===\n\n");
// De Morgan's First Law: !(A && B) == (!A || !B)
printf("First Law: !(A && B) == (!A || !B)\n");
printf(" A B !(A&&B) !A||!B\n");
printf(" -------------------------\n");
for (int a = 0; a <= 1; a++) {
for (int b = 0; b <= 1; b++) {
int left = !(a && b);
int right = (!a || !b);
printf(" %d %d %d %d %s\n",
a, b, left, right,
(left == right) ? "✓" : "✗");
}
}
// De Morgan's Second Law: !(A || B) == (!A && !B)
printf("\nSecond Law: !(A || B) == (!A && !B)\n");
printf(" A B !(A||B) !A&&!B\n");
printf(" -------------------------\n");
for (int a = 0; a <= 1; a++) {
for (int b = 0; b <= 1; b++) {
int left = !(a || b);
int right = (!a && !b);
printf(" %d %d %d %d %s\n",
a, b, left, right,
(left == right) ? "✓" : "✗");
}
}
}
int main() {
demonstrateDeMorgansLaws();
return 0;
}
Precedence and Associativity
#include <stdio.h>
void demonstratePrecedence() {
printf("=== Operator Precedence ===\n\n");
int a = 5, b = 10, c = 15;
printf("a = %d, b = %d, c = %d\n\n", a, b, c);
// Without parentheses, ! has highest precedence,
// then &&, then ||
printf("Without parentheses (relying on precedence):\n");
printf("a > 0 && b > 0 || c > 0 = %d\n", a > 0 && b > 0 || c > 0);
printf("This is evaluated as: (a > 0 && b > 0) || c > 0\n\n");
printf("With parentheses to clarify:\n");
printf("(a > 0 && b > 0) || c > 0 = %d\n", (a > 0 && b > 0) || c > 0);
printf("a > 0 && (b > 0 || c > 0) = %d\n\n", a > 0 && (b > 0 || c > 0));
// Combining multiple operators
printf("Complex expression:\n");
printf("!a > b && c != 0 || a == b\n");
printf("Step by step:\n");
printf(" 1. !a = %d\n", !a);
printf(" 2. !a > b = %d\n", !a > b);
printf(" 3. c != 0 = %d\n", c != 0);
printf(" 4. a == b = %d\n", a == b);
printf(" 5. (!a > b) && (c != 0) = %d\n", (!a > b) && (c != 0));
printf(" 6. ((!a > b) && (c != 0)) || (a == b) = %d\n",
((!a > b) && (c != 0)) || (a == b));
}
int main() {
demonstratePrecedence();
return 0;
}
Common Pitfalls
#include <stdio.h>
void demonstratePitfalls() {
printf("=== Common Pitfalls ===\n\n");
// Pitfall 1: Using = instead of ==
int x = 5;
printf("Pitfall 1: Using assignment instead of comparison\n");
printf(" x = 5 (initial)\n");
if (x = 10) { // Assignment, not comparison!
printf(" This always executes because x = 10 assigns 10, which is true\n");
}
printf(" x is now: %d (was changed!)\n\n", x);
// Pitfall 2: Operator precedence confusion
int a = 1, b = 2, c = 3;
printf("Pitfall 2: Precedence confusion\n");
printf(" a = %d, b = %d, c = %d\n", a, b, c);
printf(" a && b || c && a = %d\n", a && b || c && a);
printf(" What you might think: (a && b) || (c && a) = %d\n",
(a && b) || (c && a));
printf(" What actually happens: ((a && b) || c) && a = %d\n\n",
((a && b) || c) && a);
// Pitfall 3: Side effects in logical expressions
int i = 0;
printf("Pitfall 3: Side effects with short-circuit\n");
printf(" i = %d\n", i);
if (i > 0 && ++i > 0) {
// This won't execute
}
printf(" After (i > 0 && ++i > 0), i = %d (++i NOT executed)\n", i);
if (i == 0 || ++i > 0) {
printf(" Inside OR condition\n");
}
printf(" After (i == 0 || ++i > 0), i = %d (++i WAS executed)\n\n", i);
// Pitfall 4: Confusing bitwise operators with logical operators
int p = 2, q = 3;
printf("Pitfall 4: Bitwise vs Logical\n");
printf(" p = %d (binary 010), q = %d (binary 011)\n", p, q);
printf(" p && q = %d (logical AND)\n", p && q);
printf(" p & q = %d (bitwise AND) = 010 & 011 = 010 = 2\n", p & q);
printf(" p || q = %d (logical OR)\n", p || q);
printf(" p | q = %d (bitwise OR) = 010 | 011 = 011 = 3\n\n", p | q);
// Pitfall 5: Floating point comparisons
double d1 = 0.1 + 0.2;
double d2 = 0.3;
printf("Pitfall 5: Floating point comparisons\n");
printf(" 0.1 + 0.2 = %.20f\n", d1);
printf(" 0.3 = %.20f\n", d2);
printf(" d1 == d2 = %d (often false due to precision)\n", d1 == d2);
printf(" Better: abs(d1 - d2) < epsilon\n");
}
int main() {
demonstratePitfalls();
return 0;
}
Best Practices
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
// Best Practice 1: Use parentheses for clarity
void practiceParentheses() {
int a = 5, b = 10, c = 15;
// Hard to read
if (a > 0 && b > 0 || c > 0 && a < b) {
// ...
}
// Clear and maintainable
if ((a > 0 && b > 0) || (c > 0 && a < b)) {
// ...
}
}
// Best Practice 2: Extract complex conditions
bool isValidInput(int value, int min, int max, bool allowZero) {
bool inRange = (value >= min && value <= max);
bool zeroAllowed = (allowZero && value == 0);
return inRange || zeroAllowed;
}
// Best Practice 3: Use meaningful variable names
void practiceMeaningfulNames() {
int age = 25;
bool hasLicense = true;
bool isSober = true;
// Good - reads like English
if (age >= 16 && hasLicense && isSober) {
printf("Can drive\n");
}
// Bad - cryptic
int a = 25, l = 1, s = 1;
if (a >= 16 && l && s) {
printf("Can drive\n");
}
}
// Best Practice 4: Use early returns to avoid deep nesting
bool processOrder(int quantity, float price, bool inStock, bool customerValid) {
if (!inStock) {
printf("Out of stock\n");
return false;
}
if (!customerValid) {
printf("Invalid customer\n");
return false;
}
if (quantity <= 0) {
printf("Invalid quantity\n");
return false;
}
if (price <= 0.0) {
printf("Invalid price\n");
return false;
}
// Process order...
printf("Order processed successfully\n");
return true;
}
// Best Practice 5: Use boolean functions for complex conditions
bool isEligibleForDiscount(int age, bool isMember, float purchaseAmount, bool isHoliday) {
bool ageEligible = (age >= 18 && age <= 65);
bool memberBonus = isMember && purchaseAmount > 100.0;
bool holidaySpecial = isHoliday && purchaseAmount > 50.0 && !isMember;
return ageEligible && (memberBonus || holidaySpecial);
}
// Best Practice 6: Avoid side effects in conditions
int getNextValue(int *counter) {
return (*counter)++;
}
void practiceNoSideEffects() {
int counter = 0;
// Bad - side effect in condition
if (getNextValue(&counter) > 0 && getNextValue(&counter) < 10) {
// counter may be incremented 1 or 2 times depending on short-circuit
}
// Good - side effect separate
int val1 = getNextValue(&counter);
int val2 = getNextValue(&counter);
if (val1 > 0 && val2 < 10) {
// Predictable behavior
}
}
// Best Practice 7: Use epsilon for float comparisons
bool approxEqual(double a, double b, double epsilon) {
return fabs(a - b) < epsilon;
}
int main() {
printf("=== Best Practices ===\n");
// Test epsilon comparison
double d1 = 0.1 + 0.2;
double d2 = 0.3;
printf("0.1 + 0.2 == 0.3: %d\n", d1 == d2);
printf("approxEqual(0.1+0.2, 0.3, 1e-10): %d\n",
approxEqual(d1, d2, 1e-10));
return 0;
}
Performance Considerations
#include <stdio.h>
#include <time.h>
void performanceComparison() {
printf("=== Performance Considerations ===\n\n");
const int ITERATIONS = 10000000;
int count = 0;
clock_t start, end;
// Test 1: Simple condition
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
if (i % 2 == 0) {
count++;
}
}
end = clock();
printf("Simple condition: %.3f seconds\n",
(double)(end - start) / CLOCKS_PER_SEC);
// Test 2: Complex condition with AND
count = 0;
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
if (i % 2 == 0 && i % 3 == 0 && i % 5 == 0) {
count++;
}
}
end = clock();
printf("Complex AND chain: %.3f seconds\n",
(double)(end - start) / CLOCKS_PER_SEC);
// Test 3: Complex condition with OR
count = 0;
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
if (i % 2 == 0 || i % 3 == 0 || i % 5 == 0) {
count++;
}
}
end = clock();
printf("Complex OR chain: %.3f seconds\n",
(double)(end - start) / CLOCKS_PER_SEC);
printf("\nNote: AND chains often faster because they short-circuit early.\n");
printf("Place conditions that are most likely to be false first in AND chains.\n");
printf("Place conditions that are most likely to be true first in OR chains.\n");
}
int main() {
performanceComparison();
return 0;
}
Summary Table
| Operator | Name | Example | Result |
|---|---|---|---|
&& | Logical AND | (x > 0 && x < 10) | True if both conditions true |
|| | Logical OR | (x < 0 || x > 10) | True if either condition true |
! | Logical NOT | !(x > 0) | True if condition false |
Conclusion
Logical operators are fundamental to controlling program flow in C. They enable complex decision-making, input validation, and state management through the combination of simple Boolean expressions. Understanding short-circuit evaluation, operator precedence, and common pitfalls is essential for writing correct and efficient code.
By mastering logical operators, C programmers can create clear, maintainable conditions that accurately reflect business logic and user requirements. Combined with relational operators and proper parentheses for clarity, logical operators form the backbone of conditional programming in C.