CSE101 Unit 2 Notes

Control Structures and Input/Output Functions

This unit delves into the essential control structures in C programming that dictate the flow of a program, as well as input/output functions that facilitate interaction with the user. Mastery of these concepts is crucial for writing efficient and interactive C programs.

Control Structures

Control structures determine the order in which statements are executed in a program. They enable decision-making, looping, and altering the normal sequential flow of control.

Decision-Making Statements

If Statement

  • Definition: Executes a block of code if a specified condition evaluates to true.

  • Syntax:

    if (condition) {
        // Statements to execute if condition is true
    }
  • Explanation:

    • Condition: An expression that evaluates to a non-zero (true) or zero (false) value.
    • The code block inside the braces {} runs only if the condition is true.
  • Example:

    int age = 20;
    
    if (age >= 18) {
        printf("You are eligible to vote.\n");
    }
  • Notes:

    • Braces {} can be omitted if there is only one statement.
      if (age >= 18)
          printf("You are eligible to vote.\n");

If-Else Statement

  • Definition: Provides an alternative execution path when the if condition evaluates to false.

  • Syntax:

    if (condition) {
        // Statements if condition is true
    } else {
        // Statements if condition is false
    }
  • Example:

    int num = 5;
    
    if (num % 2 == 0) {
        printf("%d is even.\n", num);
    } else {
        printf("%d is odd.\n", num);
    }
  • Explanation:

    • If condition is true, the first block executes; otherwise, the code within the else block runs.

Nested If-Else Statements

  • Definition: An if or if-else statement inside another if or else block.

  • Usage: To handle multiple conditions and decisions.

  • Syntax:

    if (condition1) {
        // Statements if condition1 is true
        if (condition2) {
            // Statements if condition2 is true
        } else {
            // Statements if condition2 is false
        }
    } else {
        // Statements if condition1 is false
    }
  • Example:

    int marks = 85;
    
    if (marks >= 90) {
        printf("Grade: A\n");
    } else if (marks >= 80) {
        printf("Grade: B\n");
    } else if (marks >= 70) {
        printf("Grade: C\n");
    } else {
        printf("Grade: D\n");
    }
  • Notes:

    • The else if ladder is a series of if statements following an else to handle multiple mutually exclusive conditions.

Switch-Case Statement

  • Definition: Selects one of many code blocks to execute based on the value of an expression.

  • Syntax:

    switch (expression) {
        case constant1:
            // Statements
            break;
        case constant2:
            // Statements
            break;
        // Additional cases...
        default:
            // Default statements
    }
  • Components:

    • Expression: An integral or enumerated type.
    • Case Labels: Must be unique constants (integer or character constants).
    • Break Statement: Terminates a case block to prevent fall-through.
    • Default Case: Executes if no matching case is found (optional).
  • Example:

    char grade = 'B';
    
    switch (grade) {
        case 'A':
            printf("Excellent!\n");
            break;
        case 'B':
            printf("Well done.\n");
            break;
        case 'C':
            printf("Good.\n");
            break;
        case 'D':
            printf("You passed.\n");
            break;
        case 'F':
            printf("Better try again.\n");
            break;
        default:
            printf("Invalid grade.\n");
    }
  • Notes:

    • Omitting the break; statement causes execution to continue to the next case (fall-through).
    • Suitable for scenarios with multiple discrete values.

Looping Statements

Looping structures allow repeated execution of a block of code as long as a specified condition is met.

While Loop

  • Definition: Repeats a block of code while a condition remains true.

  • Syntax:

    while (condition) {
        // Statements
    }
  • Explanation:

    • Entry-Controlled Loop: The condition is evaluated before the loop body executes.
    • If the condition is false initially, the loop body may not execute at all.
  • Example:

    int i = 1;
    
    while (i <= 5) {
        printf("Count: %d\n", i);
        i++;
    }
  • Notes:

    • Ensure the condition eventually becomes false to avoid infinite loops.
    • Use for situations where the number of iterations isn't known in advance.

For Loop

  • Definition: Simplifies the creation of loops with an initialization, condition, and increment/decrement in one line.

  • Syntax:

    for (initialization; condition; increment/decrement) {
        // Statements
    }
  • Explanation:

    • Initialization: Executes once before the loop starts.
    • Condition: Evaluated before each iteration.
    • Increment/Decrement: Executes after each iteration.
  • Example:

    for (int i = 0; i < 5; i++) {
        printf("Iteration: %d\n", i);
    }
  • Notes:

    • Ideal for loops with a known number of iterations.
    • All three components (initialization, condition, increment) are optional but semicolons ; are mandatory.

Do-While Loop

  • Definition: Executes the loop body at least once before checking the condition.

  • Syntax:

    do {
        // Statements
    } while (condition);
  • Explanation:

    • Exit-Controlled Loop: The condition is evaluated after the loop body executes.
  • Example:

    int i = 1;
    
    do {
        printf("Value of i: %d\n", i);
        i++;
    } while (i <= 3);
  • Notes:

    • Use when the loop body must execute at least once regardless of the condition.
    • Be cautious of infinite loops if the condition never becomes false.

Jump Statements

Jump statements alter the flow of control unconditionally.

Break Statement

  • Definition: Terminates the nearest enclosing loop or switch statement.

  • Syntax:

    break;
  • Usage in Loops:

    for (int i = 0; i < 10; i++) {
        if (i == 5) {
            break;
        }
        printf("%d ", i);
    }
    // Output: 0 1 2 3 4
  • Usage in Switch Cases:

    • Prevents execution from proceeding to subsequent cases.
  • Notes:

    • Enhances control over loop execution.
    • Exiting loops prematurely if a certain condition is met.

Continue Statement

  • Definition: Skips the remaining code in the current loop iteration and proceeds to the next iteration.

  • Syntax:

    continue;
  • Example:

    for (int i = 0; i < 10; i++) {
        if (i % 2 == 0) {
            continue; // Skip even numbers
        }
        printf("%d ", i);
    }
    // Output: 1 3 5 7 9
  • Explanation:

    • When continue; is encountered, control jumps to the loop's increment/decrement expression (or condition check in while loops).
  • Notes:

    • Useful for skipping specific iterations based on a condition.

Goto Statement

  • Definition: Transfers control unconditionally to a labeled statement.

  • Syntax:

    ```c goto label;

// ... label: // Statements


- **Example**:

```c
int i = 1;

start:
printf("%d ", i);
i++;
if (i <= 5) {
    goto start;
}
// Output: 1 2 3 4 5
  • Notes:
    • Usage Consideration:
      • Can make code less readable and maintainable.
      • Generally discouraged in structured programming.
    • When to Use:
      • Rarely, for breaking out of deeply nested loops or error handling in legacy code.

Return Statement

  • Definition: Exits a function and optionally returns a value to the calling function.

  • Syntax:

    return;          // For void functions
    return expression; // For functions returning a value
  • Example:

    int add(int a, int b) {
        return a + b;
    }
    
    int main() {
        int sum = add(5, 3);
        printf("Sum: %d\n", sum);
        return 0;
    }
  • Notes:

    • In the main() function, return 0; typically indicates successful execution.
    • Multiple return statements can be used in a function to exit at different points.

Type Conversion and Type Modifiers

Understanding how data types interact and how to modify them is crucial for precise and error-free programming.

Type Conversion

Implicit Type Conversion (Automatic)

  • Definition: The compiler automatically converts one data type to another when necessary.

  • Rules:

    • Lower-ranked types are converted to higher-ranked types to prevent data loss.
    • Order of Types (lowest to highest):
      • char < short < int < long < float < double < long double
  • Examples:

    int i = 10;
    double d = i; // 'i' is implicitly converted to double
    • The integer i is promoted to double before assigning.
  • Notes:

    • No need for explicit casting.
    • Avoids potential data loss.

Explicit Type Conversion (Casting)

  • Definition: Manually converting a value from one data type to another.

  • Syntax:

    (type) expression
  • Examples:

    double num = 9.7;
    int int_num = (int)num; // Explicitly cast 'num' to int
    • Result: int_num becomes 9 (fractional part truncated).
  • Possible Data Loss:

    • Converting from a higher to a lower data type may result in loss of precision or data.
    • Always ensure that such casting is intentional.
  • Notes:

    • Be careful when casting pointers; incorrect casting can lead to undefined behavior.

Type Modifiers

Type modifiers allow the basic data types to be adjusted according to the needs of a program.

Signed and Unsigned

  • Signed Types:

    • Able to represent both positive and negative values.
    • Default Behavior: All integer types are signed unless specified otherwise.
  • Unsigned Types:

    • Represents only non-negative values (zero and positive numbers).

    • Syntax:

      unsigned int variable_name;
  • Examples:

    unsigned int count = 100;
    signed int temperature = -20;
  • Range Differences:

    • For a 16-bit int:
      • Signed int: -32,768 to 32,767
      • Unsigned int: 0 to 65,535
  • Notes:

    • Use unsigned types when negative values are not expected.
    • Mixing signed and unsigned types can lead to unexpected results.

Short and Long

  • Purpose: Adjust the storage size (and range) of integer types.

  • Short Integers:

    • Syntax:

      short int si;
    • Typically: 2 bytes (16 bits).

    • Range:

      • Signed: -32,768 to 32,767
      • Unsigned: 0 to 65,535
  • Long Integers:

    • Syntax:

      long int li;
      long long int lli; // For even larger numbers
    • Typically: At least 4 bytes (32 bits) for long, 8 bytes (64 bits) for long long.

    • Range:

      • long int:
        • Signed: -2,147,483,648 to 2,147,483,647
        • Unsigned: 0 to 4,294,967,295
      • long long int:
        • Signed: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
  • Examples:

    short int smallNum = 32767;
    long int largeNum = 2147483647;
    long long int veryLargeNum = 9223372036854775807LL;
  • Notes:

    • Use long long for variables that require storage of very large numbers.
    • The size of these types may vary between systems; use sizeof() to verify.

Designing Structured Programs in C

Structured programming involves writing clear, understandable, and maintainable code by controlling the flow of the program using functions, loops, and conditionals.

Structured Programming Principles

Modularity

  • Definition: Dividing a program into separate modules or functions, each handling a specific task.

  • Advantages:

    • Simplifies complex programs.
    • Enhances code reusability.
    • Makes testing and debugging easier.
  • Example:

    // Function prototypes
    void input_data();
    void process_data();
    void output_results();
    
    int main() {
        input_data();
        process_data();
        output_results();
        return 0;
    }

Top-Down Design

  • Definition: Starting from the highest level of the system and breaking it down into smaller, manageable sub-systems.

  • Approach:

    • Define the main function.
    • Decompose into sub-functions or modules.
    • Implement detailed logic at the lowest level.
  • Benefits:

    • Provides a clear structure.
    • Facilitates understanding of program flow.

Sequential Flow

  • Definition: Ensuring that statements are executed one after another in a logical order.

  • Practice:

    • Arrange code logically.
    • Avoid unnecessary jumps or convoluted control flows.

Control Structures

  • Usage:

    • Loops: For repeated execution of code blocks.
    • Conditionals: For decision-making.
  • Goal: Use loops and conditionals effectively to control the flow without resorting to unstructured jumps (like goto).

Avoiding Goto Statements

  • Reason:

    • Goto statements can create spaghetti code.
    • Makes the program hard to read and maintain.
  • Alternatives:

    • Use loops (for, while, do-while).
    • Use functions to encapsulate repetitive code.
    • Use structured exception handling (if language supports it).

Best Practices

Consistent Indentation

  • Purpose: Enhances readability.

  • Guidelines:

    • Use spaces or tabs consistently.
    • Common practice is 4-space indentation.

Meaningful Names

  • Purpose: Makes code self-documenting.

  • Guidelines:

    • Variables: Use names that describe their purpose (totalScore, userName).
    • Functions: Verb-based names (computeAverage, displayResults).

Comments

  • Purpose: Explain complex logic or clarify code purpose.

  • Types:

    • Single-line comments: // This is a comment

    • Multi-line comments:

      /* This is
         a multi-line
         comment */
  • Guidelines:

    • Avoid over-commenting obvious code.
    • Keep comments up-to-date with code changes.

Code Reusability

  • Methods:

    • Write generic functions.
    • Use function parameters effectively.
  • Advantages:

    • Saves time.
    • Reduces code duplication.

Debugging and Testing

  • Steps:

    • Test individual functions (unit testing).
    • Use print statements or debuggers to trace code execution.
    • Test with different input scenarios.
  • Importance:

    • Ensures program correctness.
    • Identifies and eliminates bugs early.

Input/Output Functions

Interaction with the user or other systems is a critical aspect of programming. C provides several functions for handling input and output operations.

Formatted Input/Output Functions

Formatted I/O functions allow for controlled presentation and parsing of data.

printf() Function

  • Purpose: Sends formatted output to the standard output (typically the console).

  • Syntax:

    printf("format string", argument_list);
  • Format Specifiers:

    • Integer Types:

      • %d or %i: Signed decimal integer.
      • %u: Unsigned decimal integer.
      • %x or %X: Unsigned hexadecimal integer.
      • %o: Unsigned octal integer.
    • Floating-Point Types:

      • %f: Decimal floating-point (lowercase).
      • %F: Decimal floating-point (uppercase).
      • %e or %E: Scientific notation.
      • %g or %G: Use %f or %e based on value.
    • Character and String Types:

      • %c: Character.
      • %s: String of characters.
    • Others:

      • %p: Pointer address.
      • %%: Literal % character.
  • Modifiers:

    • Field Width: Minimum number of characters to be printed.

    • Precision: Number of digits after the decimal point for floating-point numbers.

    • Syntax:

      printf("%[flags][width][.precision][length]specifier", argument);
  • Flags:

    • -: Left-align within the given field width.
    • +: Forces a sign (+ or -) to be used on a number.
    • 0: Pad with zeros instead of spaces.
  • Example:

    int a = 10;
    float b = 3.1415;
    
    printf("Integer: %d\n", a);
    printf("Float: %.2f\n", b); // Outputs float with 2 decimal places
    printf("Right-aligned number: %5d\n", a); // Field width of 5
  • Escape Sequences:

    • \n: Newline.
    • \t: Horizontal tab.
    • \\: Backslash.
    • \": Double quote.

scanf() Function

  • Purpose: Reads formatted input from the standard input (keyboard).

  • Syntax:

    scanf("format string", argument_list);
  • Usage:

    • Requires the address-of operator (&) before variable names (except for strings).
    • Stops reading input when a whitespace is encountered for most format specifiers.
  • Common Format Specifiers: Same as in printf(), but with slightly different behaviors.

  • Example:

    int age;
    float salary;
    char name[50];
    
    printf("Enter your age: ");
    scanf("%d", &age);
    
    printf("Enter your salary: ");
    scanf("%f", &salary);
    
    printf("Enter your name: ");
    scanf("%s", name); // Note: no '&' with arrays
  • Notes:

    • Buffer Issues:

      • scanf() reads until it encounters whitespace.
      • For reading strings with spaces, use gets() or fgets().
    • Input Validation:

      • Check the return value of scanf() to ensure the correct number of inputs were read.
        int result = scanf("%d", &age);
        if (result != 1) {
            // Handle invalid input
        }

Unformatted Input/Output Functions

Unformatted I/O functions handle data as raw bytes or characters without any specific format.

puts() Function

  • Purpose: Writes a string to the standard output, followed by a newline character.

  • Syntax:

    puts(string);
  • Example:

    puts("Hello, World!");
  • Notes:

    • Automatically appends a newline character after the string.
    • Simpler alternative to printf() when no formatting is needed.

gets() Function

  • Purpose: Reads a line from the standard input into a string until a newline character is encountered.

  • Syntax:

    gets(string);
  • Example:

    char name[50];
    
    printf("Enter your name: ");
    gets(name);
    
    printf("Hello, %s!\n", name);
  • Important Note:

    • Security Risk: gets() does not check the buffer size, leading to buffer overflows.
    • Recommendation: Do not use gets(). Use fgets() instead.

putchar() Function

  • Purpose: Writes a single character to the standard output.

  • Syntax:

    putchar(character);
  • Example:

    char ch = 'A';
    putchar(ch);
  • Notes:

    • Returns the character written as an int or EOF on error.

getchar() Function

  • Purpose: Reads the next character from the standard input.

  • Syntax:

    int getchar(void);
  • Example:

    int ch;
    
    printf("Press a key: ");
    ch = getchar();
    
    printf("You pressed: ");
    putchar(ch);
    printf("\n");
  • Notes:

    • Returns an int, so it can indicate EOF (End of File).
    • Useful for reading single characters, including whitespace.

fgets() Function

  • Purpose: Reads a string from the standard input, up to a specified number of characters.

  • Syntax:

    fgets(string, size, stdin);
  • Example:

    char buffer[50];
    
    printf("Enter a string: ");
    fgets(buffer, sizeof(buffer), stdin);
    
    printf("You entered: %s\n", buffer);
  • Notes:

    • Safe Alternative to gets():
      • Limits input to the size specified.
      • Retains the newline character if it fits within the size.
  • Handling Newline Character:

    • To remove the newline character at the end of the string:

      buffer[strcspn(buffer, "\n")] = '\0'; // Requires <string.h>

fputs() Function

  • Purpose: Writes a string to the specified output stream (typically stdout).

  • Syntax:

    fputs(string, stdout);
  • Example:

    char message[] = "Hello, World!";
    fputs(message, stdout);
  • Notes:

    • Does not append a newline character automatically.

Comparison of Formatted and Unformatted I/O

  • Formatted I/O (printf() and scanf()):

    • Allows specifying data types and formats.
    • Suitable for complex data and precise control over input/output presentation.
    • Pros:
      • Greater control and flexibility.
      • Can handle multiple data types simultaneously.
    • Cons:
      • More complex syntax.
      • Requires careful use of format specifiers to avoid errors.
  • Unformatted I/O (gets(), puts(), getchar(), putchar(), fgets(), fputs()):

    • Simpler functions for straightforward character or string input/output.
    • Reads or writes data as is, without format specifiers.
    • Pros:
      • Simpler to use for basic input/output.
      • Less overhead when formatting is unnecessary.
    • Cons:
      • Less control over the data format.
      • Functions like gets() are unsafe (use fgets() instead).

Post a Comment