Logical Operators

Introduction

Logical operators are used to combine or modify boolean expressions in C programming. They work with conditions and return either true (non-zero) or false (zero) values. These operators are fundamental for creating complex conditional statements, loops, and decision-making structures in programs.

C provides three logical operators: AND (&&), OR (||), and NOT (!). Understanding these operators is crucial for controlling program flow and implementing complex logical conditions.

Key Concepts

Boolean Logic: Working with true/false values Short-Circuit Evaluation: Optimization where second operand may not be evaluated Truth Values: In C, 0 is false, any non-zero value is true Logical vs Bitwise: Logical operators work on entire expressions, not individual bits

Logical AND (&&)

Basic AND Operation

#include <stdio.h>
int main() {
    int a = 5, b = 10, c = 0;
    
    // Both conditions must be true
    if (a > 0 && b > 0) {
        printf("Both a and b are positive\n");
    }
    
    if (a > 0 && c > 0) {
        printf("This won't print\n");
    } else {
        printf("At least one condition is false\n");
    }
    
    return 0;
}

Truth Table for AND

#include <stdio.h>
int main() {
    printf("Logical AND Truth Table:\n");
    printf("0 && 0 = %d\n", 0 && 0);  // 0
    printf("0 && 1 = %d\n", 0 && 1);  // 0
    printf("1 && 0 = %d\n", 1 && 0);  // 0
    printf("1 && 1 = %d\n", 1 && 1);  // 1
    
    return 0;
}

Short-Circuit Evaluation with AND

#include <stdio.h>
int checkValue(int x) {
    printf("checkValue(%d) called\n", x);
    return x > 5;
}

int main() {
    int a = 3;
    
    // Second function won't be called because first condition is false
    if (a > 5 && checkValue(10)) {
        printf("Both conditions true\n");
    }
    
    printf("\nNow with a = 8:\n");
    a = 8;
    
    // Now both functions will be called
    if (a > 5 && checkValue(10)) {
        printf("Both conditions true\n");
    }
    
    return 0;
}

Logical OR (||)

Basic OR Operation

#include <stdio.h>
int main() {
    int score = 85;
    char grade = 'A';
    
    // Either condition can be true
    if (score >= 90 || grade == 'A') {
        printf("Excellent performance!\n");
    }
    
    int age = 16;
    int hasLicense = 0;  // false
    
    if (age >= 18 || hasLicense) {
        printf("Can drive\n");
    } else {
        printf("Cannot drive\n");
    }
    
    return 0;
}

Truth Table for OR

#include <stdio.h>
int main() {
    printf("Logical OR Truth Table:\n");
    printf("0 || 0 = %d\n", 0 || 0);  // 0
    printf("0 || 1 = %d\n", 0 || 1);  // 1
    printf("1 || 0 = %d\n", 1 || 0);  // 1
    printf("1 || 1 = %d\n", 1 || 1);  // 1
    
    return 0;
}

Short-Circuit Evaluation with OR

#include <stdio.h>
int expensiveCheck() {
    printf("Expensive operation called\n");
    return 1;
}

int main() {
    int quickCheck = 1;  // true
    
    // Second function won't be called because first condition is true
    if (quickCheck || expensiveCheck()) {
        printf("At least one condition is true\n");
    }
    
    printf("\nNow with quickCheck = 0:\n");
    quickCheck = 0;
    
    // Now both checks will be performed
    if (quickCheck || expensiveCheck()) {
        printf("At least one condition is true\n");
    }
    
    return 0;
}

Logical NOT (!)

Basic NOT Operation

#include <stdio.h>
int main() {
    int isLoggedIn = 0;  // false
    int hasPermission = 1;  // true
    
    if (!isLoggedIn) {
        printf("Please log in\n");
    }
    
    if (!hasPermission) {
        printf("Access denied\n");
    } else {
        printf("Access granted\n");
    }
    
    return 0;
}

Truth Table for NOT

#include <stdio.h>
int main() {
    printf("Logical NOT Truth Table:\n");
    printf("!0 = %d\n", !0);  // 1
    printf("!1 = %d\n", !1);  // 0
    printf("!5 = %d\n", !5);  // 0 (any non-zero becomes 0)
    printf("!(-3) = %d\n", !(-3));  // 0
    
    return 0;
}

Combining Logical Operators

Complex Conditions

#include <stdio.h>
int main() {
    int age = 25;
    int income = 30000;
    int creditScore = 720;
    int hasJob = 1;
    
    // Loan approval logic
    if ((age >= 21 && age <= 65) && 
        (income >= 25000 || hasJob) && 
        creditScore >= 650) {
        printf("Loan approved!\n");
    } else {
        printf("Loan denied\n");
    }
    
    return 0;
}

Using Parentheses for Clarity

#include <stdio.h>
int main() {
    int a = 5, b = 10, c = 15;
    
    // Without parentheses (relies on operator precedence)
    if (a > 0 && b > 0 || c < 0) {
        printf("Condition met (without parentheses)\n");
    }
    
    // With parentheses for clarity
    if ((a > 0 && b > 0) || c < 0) {
        printf("Condition met (with parentheses)\n");
    }
    
    return 0;
}

Practical Examples

User Authentication System

#include <stdio.h>
#include <string.h>

int main() {
    char username[20], password[20];
    int attempts = 0;
    int maxAttempts = 3;
    int isAuthenticated = 0;
    
    while (attempts < maxAttempts && !isAuthenticated) {
        printf("Enter username: ");
        scanf("%s", username);
        printf("Enter password: ");
        scanf("%s", password);
        
        if (strcmp(username, "admin") == 0 && strcmp(password, "secret") == 0) {
            printf("Login successful!\n");
            isAuthenticated = 1;
        } else {
            attempts++;
            printf("Invalid credentials. Attempts remaining: %d\n", 
                   maxAttempts - attempts);
        }
    }
    
    if (!isAuthenticated) {
        printf("Account locked due to too many failed attempts\n");
    }
    
    return 0;
}

Grade Classification System

#include <stdio.h>
int main() {
    int marks = 87;
    int attendance = 92;
    int assignments = 8;  // out of 10
    
    // Complex grading criteria
    if (marks >= 90 && attendance >= 85 && assignments >= 8) {
        printf("Grade: A+\n");
    } else if (marks >= 80 && (attendance >= 80 || assignments >= 7)) {
        printf("Grade: A\n");
    } else if (marks >= 70 && attendance >= 75) {
        printf("Grade: B\n");
    } else if (marks >= 60 || (attendance >= 90 && assignments >= 6)) {
        printf("Grade: C\n");
    } else {
        printf("Grade: F\n");
    }
    
    return 0;
}

Range Checking

#include <stdio.h>
int main() {
    int number = 45;
    
    // Check if number is in range [10, 50]
    if (number >= 10 && number <= 50) {
        printf("%d is in range [10, 50]\n", number);
    }
    
    // Check if number is outside range [20, 30]
    if (number < 20 || number > 30) {
        printf("%d is outside range [20, 30]\n", number);
    }
    
    // Check for valid percentage
    int percentage = 95;
    if (percentage >= 0 && percentage <= 100) {
        printf("%d is a valid percentage\n", percentage);
    } else {
        printf("%d is not a valid percentage\n", percentage);
    }
    
    return 0;
}

Logical vs Bitwise Operators

Comparison

#include <stdio.h>
int main() {
    int a = 3;  // Binary: 011
    int b = 5;  // Binary: 101
    
    printf("a = %d, b = %d\n", a, b);
    
    // Logical operators (work on truth values)
    printf("Logical AND: a && b = %d\n", a && b);  // 1 (both non-zero)
    printf("Logical OR:  a || b = %d\n", a || b);  // 1 (both non-zero)
    
    // Bitwise operators (work on individual bits)
    printf("Bitwise AND: a & b = %d\n", a & b);    // 1 (011 & 101 = 001)
    printf("Bitwise OR:  a | b = %d\n", a | b);    // 7 (011 | 101 = 111)
    
    return 0;
}

Operator Precedence

Precedence Example

#include <stdio.h>
int main() {
    int a = 1, b = 0, c = 1;
    
    // ! has higher precedence than &&
    int result1 = !a && b;  // (!a) && b = 0 && 0 = 0
    printf("!a && b = %d\n", result1);
    
    // && has higher precedence than ||
    int result2 = a || b && c;  // a || (b && c) = 1 || 0 = 1
    printf("a || b && c = %d\n", result2);
    
    // Using parentheses to change precedence
    int result3 = (a || b) && c;  // (1 || 0) && 1 = 1 && 1 = 1
    printf("(a || b) && c = %d\n", result3);
    
    return 0;
}

Common Mistakes and Solutions

Assignment vs Equality in Conditions

// Wrong - assignment instead of comparison
int x = 5;
if (x = 10) {  // Assignment, always true!
    printf("This will always execute\n");
}

// Correct - use equality operator
if (x == 10) {  // Comparison
    printf("This executes only if x equals 10\n");
}

Incorrect Range Checking

int age = 25;

// Wrong - this doesn't work as expected
if (18 <= age <= 65) {  // This is evaluated as (18 <= age) <= 65
    printf("Working age\n");  // Will always be true!
}

// Correct - use logical AND
if (age >= 18 && age <= 65) {
    printf("Working age\n");
}

Mixing Logical and Bitwise Operators

int flags = 7;  // Binary: 111

// Wrong - using bitwise when logical is intended
if (flags & 1 && flags & 2) {  // Might work but unclear intent
    printf("Flags 1 and 2 are set\n");
}

// Better - be explicit about intent
if ((flags & 1) != 0 && (flags & 2) != 0) {
    printf("Flags 1 and 2 are set\n");
}

Important Points

  • Short-Circuit Evaluation: && stops at first false, || stops at first true
  • Truth Values: 0 is false, any non-zero value is true
  • Precedence: ! > && > ||, but use parentheses for clarity
  • Side Effects: Be careful with functions that have side effects in logical expressions
  • Performance: Short-circuiting can improve performance by avoiding unnecessary evaluations
  • Readability: Use parentheses to make complex expressions clear

Summary

Logical operators are essential for creating conditional statements and controlling program flow in C. The AND (&&), OR (||), and NOT (!) operators work with boolean expressions and use short-circuit evaluation for efficiency. Understanding operator precedence and the difference between logical and bitwise operators is crucial for writing correct programs. These operators are commonly used in if statements, loops, and complex decision-making logic. Proper use of parentheses improves code readability and prevents precedence-related bugs. Mastering logical operators enables you to build sophisticated conditional logic for authentication systems, validation routines, and complex business rules.


Part of BCA Programming with C Course (UGCOA22J201)